diff options
Diffstat (limited to 'src/gallium/state_trackers')
226 files changed, 48661 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/Makefile b/src/gallium/state_trackers/Makefile new file mode 100644 index 0000000000..265ca468c2 --- /dev/null +++ b/src/gallium/state_trackers/Makefile @@ -0,0 +1,25 @@ +TOP = ../../.. +include $(TOP)/configs/current + + +SUBDIRS = $(GALLIUM_STATE_TRACKERS_DIRS) + + +default: subdirs + + +subdirs: + @for dir in $(SUBDIRS) ; do \ + if [ -d $$dir ] ; then \ + (cd $$dir && $(MAKE)) || exit 1 ; \ + fi \ + done + + +clean: + rm -f `find . -name \*.[oa]` + rm -f `find . -name depend` + + +# Dummy install target +install: diff --git a/src/gallium/state_trackers/README b/src/gallium/state_trackers/README new file mode 100644 index 0000000000..28dd27bbd5 --- /dev/null +++ b/src/gallium/state_trackers/README @@ -0,0 +1,2 @@ +This directory is a placeholder for incubating state-trackers. Mesa's +state-tracker is in src/mesa. diff --git a/src/gallium/state_trackers/dri/Makefile b/src/gallium/state_trackers/dri/Makefile new file mode 100644 index 0000000000..ef8f19709a --- /dev/null +++ b/src/gallium/state_trackers/dri/Makefile @@ -0,0 +1,28 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBNAME = dridrm + +LIBRARY_INCLUDES = \ + -I$(TOP)/include \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/mesa/drivers/dri/common \ + -I$(TOP)/src/mesa/main \ + $(shell pkg-config --cflags-only-I libdrm) + + +C_SOURCES = \ + dri_context.c \ + dri_screen.c \ + dri_drawable.c \ + dri_extensions.c + +# $(TOP)/src/mesa/drivers/dri/common/utils.c \ + $(TOP)/src/mesa/drivers/dri/common/vblank.c \ + $(TOP)/src/mesa/drivers/dri/common/dri_util.c \ + $(TOP)/src/mesa/drivers/dri/common/xmlconfig.c \ + $(TOP)/src/mesa/drivers/common/driverfuncs.c \ + $(TOP)/src/mesa/drivers/dri/common/texmem.c \ + $(TOP)/src/mesa/drivers/dri/common/drirenderbuffer.c + +include ../../Makefile.template diff --git a/src/gallium/state_trackers/dri/SConscript b/src/gallium/state_trackers/dri/SConscript new file mode 100644 index 0000000000..ce2c273597 --- /dev/null +++ b/src/gallium/state_trackers/dri/SConscript @@ -0,0 +1,23 @@ +####################################################################### +# SConscript for dri state_tracker + +Import('*') + +if env['dri']: + + env = env.Clone() + + env.Append(CPPPATH = [ + '#/src/mesa', + '#/src/mesa/drivers/dri/common', + ]) + + st_dri = env.ConvenienceLibrary( + target = 'st_dri', + source = [ 'dri_context.c', + 'dri_drawable.c', + 'dri_extensions.c', + 'dri_screen.c', + ] + ) + Export('st_dri') diff --git a/src/gallium/state_trackers/dri/dri_context.c b/src/gallium/state_trackers/dri/dri_context.c new file mode 100644 index 0000000000..8819936fca --- /dev/null +++ b/src/gallium/state_trackers/dri/dri_context.c @@ -0,0 +1,215 @@ +/************************************************************************** + * + * Copyright 2009, VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Author: Keith Whitwell <keithw@vmware.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + */ + +#include "dri_screen.h" + +#include "dri_drawable.h" +#include "state_tracker/drm_api.h" +#include "state_tracker/dri1_api.h" +#include "state_tracker/st_public.h" +#include "state_tracker/st_context.h" +#include "pipe/p_context.h" + +#include "dri_context.h" + +#include "util/u_memory.h" + +GLboolean +dri_create_context(const __GLcontextModes * visual, + __DRIcontextPrivate * cPriv, void *sharedContextPrivate) +{ + __DRIscreenPrivate *sPriv = cPriv->driScreenPriv; + struct dri_screen *screen = dri_screen(sPriv); + struct dri_context *ctx = NULL; + struct st_context *st_share = NULL; + + if (sharedContextPrivate) { + st_share = ((struct dri_context *)sharedContextPrivate)->st; + } + + ctx = CALLOC_STRUCT(dri_context); + if (ctx == NULL) + goto fail; + + cPriv->driverPrivate = ctx; + ctx->cPriv = cPriv; + ctx->sPriv = sPriv; + ctx->lock = screen->drmLock; + ctx->d_stamp = -1; + ctx->r_stamp = -1; + + driParseConfigFiles(&ctx->optionCache, + &screen->optionCache, sPriv->myNum, "dri"); + + ctx->pipe = screen->api->create_context(screen->api, screen->pipe_screen); + + if (ctx->pipe == NULL) + goto fail; + + /* used in dri_flush_frontbuffer */ + ctx->pipe->priv = ctx; + + ctx->st = st_create_context(ctx->pipe, visual, st_share); + if (ctx->st == NULL) + goto fail; + + dri_init_extensions(ctx); + + return GL_TRUE; + + fail: + if (ctx && ctx->st) + st_destroy_context(ctx->st); + + if (ctx && ctx->pipe) + ctx->pipe->destroy(ctx->pipe); + + FREE(ctx); + return FALSE; +} + +void +dri_destroy_context(__DRIcontextPrivate * cPriv) +{ + struct dri_context *ctx = dri_context(cPriv); + + /* No particular reason to wait for command completion before + * destroying a context, but it is probably worthwhile flushing it + * to avoid having to add code elsewhere to cope with flushing a + * partially destroyed context. + */ + st_flush(ctx->st, 0, NULL); + + /* Also frees ctx->pipe? + */ + st_destroy_context(ctx->st); + + FREE(ctx); +} + +GLboolean +dri_unbind_context(__DRIcontextPrivate * cPriv) +{ + if (cPriv) { + struct dri_context *ctx = dri_context(cPriv); + + if (--ctx->bind_count == 0) { + if (ctx->st && ctx->st == st_get_current()) { + st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); + st_make_current(NULL, NULL, NULL); + } + } + } + + return GL_TRUE; +} + +GLboolean +dri_make_current(__DRIcontextPrivate * cPriv, + __DRIdrawablePrivate * driDrawPriv, + __DRIdrawablePrivate * driReadPriv) +{ + if (cPriv) { + struct dri_context *ctx = dri_context(cPriv); + struct dri_drawable *draw = dri_drawable(driDrawPriv); + struct dri_drawable *read = dri_drawable(driReadPriv); + struct st_context *old_st = st_get_current(); + + if (old_st && old_st != ctx->st) + st_flush(old_st, PIPE_FLUSH_RENDER_CACHE, NULL); + + ++ctx->bind_count; + + if (ctx->dPriv != driDrawPriv) { + ctx->dPriv = driDrawPriv; + ctx->d_stamp = driDrawPriv->lastStamp - 1; + } + if (ctx->rPriv != driReadPriv) { + ctx->rPriv = driReadPriv; + ctx->r_stamp = driReadPriv->lastStamp - 1; + } + + st_make_current(ctx->st, draw->stfb, read->stfb); + + if (__dri1_api_hooks) { + dri1_update_drawables(ctx, draw, read); + } else { + if (driDrawPriv) + dri_get_buffers(driDrawPriv); + if (driDrawPriv != driReadPriv && driReadPriv) + dri_get_buffers(driReadPriv); + } + } else { + st_make_current(NULL, NULL, NULL); + } + + return GL_TRUE; +} + +static void +st_dri_lock(struct pipe_context *pipe) +{ + dri_lock((struct dri_context *)pipe->priv); +} + +static void +st_dri_unlock(struct pipe_context *pipe) +{ + dri_unlock((struct dri_context *)pipe->priv); +} + +static boolean +st_dri_is_locked(struct pipe_context *pipe) +{ + return ((struct dri_context *)pipe->priv)->isLocked; +} + +static boolean +st_dri_lost_lock(struct pipe_context *pipe) +{ + return ((struct dri_context *)pipe->priv)->wsLostLock; +} + +static void +st_dri_clear_lost_lock(struct pipe_context *pipe) +{ + ((struct dri_context *)pipe->priv)->wsLostLock = FALSE; +} + +struct dri1_api_lock_funcs dri1_lf = { + .lock = st_dri_lock, + .unlock = st_dri_unlock, + .is_locked = st_dri_is_locked, + .is_lock_lost = st_dri_lost_lock, + .clear_lost_lock = st_dri_clear_lost_lock +}; + +/* vim: set sw=3 ts=8 sts=3 expandtab: */ diff --git a/src/gallium/state_trackers/dri/dri_context.h b/src/gallium/state_trackers/dri/dri_context.h new file mode 100644 index 0000000000..4650178734 --- /dev/null +++ b/src/gallium/state_trackers/dri/dri_context.h @@ -0,0 +1,123 @@ +/************************************************************************** + * + * Copyright (C) 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Author: Keith Whitwell <keithw@vmware.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + */ + +#ifndef DRI_CONTEXT_H +#define DRI_CONTEXT_H + +#include "pipe/p_compiler.h" +#include "drm.h" +#include "dri_util.h" + +struct pipe_context; +struct pipe_fence; +struct st_context; +struct dri_drawable; + +struct dri_context +{ + /* dri */ + __DRIscreenPrivate *sPriv; + __DRIcontextPrivate *cPriv; + __DRIdrawablePrivate *dPriv; + __DRIdrawablePrivate *rPriv; + + driOptionCache optionCache; + + unsigned int d_stamp; + unsigned int r_stamp; + + drmLock *lock; + boolean isLocked; + boolean stLostLock; + boolean wsLostLock; + + unsigned int bind_count; + + /* gallium */ + struct st_context *st; + struct pipe_context *pipe; +}; + +static INLINE struct dri_context * +dri_context(__DRIcontextPrivate * driContextPriv) +{ + return (struct dri_context *)driContextPriv->driverPrivate; +} + +static INLINE void +dri_lock(struct dri_context *ctx) +{ + drm_context_t hw_context = ctx->cPriv->hHWContext; + char ret = 0; + + DRM_CAS(ctx->lock, hw_context, DRM_LOCK_HELD | hw_context, ret); + if (ret) { + drmGetLock(ctx->sPriv->fd, hw_context, 0); + ctx->stLostLock = TRUE; + ctx->wsLostLock = TRUE; + } + ctx->isLocked = TRUE; +} + +static INLINE void +dri_unlock(struct dri_context *ctx) +{ + ctx->isLocked = FALSE; + DRM_UNLOCK(ctx->sPriv->fd, ctx->lock, ctx->cPriv->hHWContext); +} + +/*********************************************************************** + * dri_context.c + */ +extern struct dri1_api_lock_funcs dri1_lf; + +void dri_destroy_context(__DRIcontextPrivate * driContextPriv); + +boolean dri_unbind_context(__DRIcontextPrivate * driContextPriv); + +boolean +dri_make_current(__DRIcontextPrivate * driContextPriv, + __DRIdrawablePrivate * driDrawPriv, + __DRIdrawablePrivate * driReadPriv); + +boolean +dri_create_context(const __GLcontextModes * visual, + __DRIcontextPrivate * driContextPriv, + void *sharedContextPrivate); + +/*********************************************************************** + * dri_extensions.c + */ +void dri_init_extensions(struct dri_context *ctx); + +#endif + +/* vim: set sw=3 ts=8 sts=3 expandtab: */ diff --git a/src/gallium/state_trackers/dri/dri_drawable.c b/src/gallium/state_trackers/dri/dri_drawable.c new file mode 100644 index 0000000000..5cec9e329d --- /dev/null +++ b/src/gallium/state_trackers/dri/dri_drawable.c @@ -0,0 +1,687 @@ +/************************************************************************** + * + * Copyright 2009, VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Author: Keith Whitwell <keithw@vmware.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + */ + +#include "dri_screen.h" +#include "dri_context.h" +#include "dri_drawable.h" + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_inlines.h" +#include "main/mtypes.h" +#include "main/renderbuffer.h" +#include "state_tracker/drm_api.h" +#include "state_tracker/dri1_api.h" +#include "state_tracker/st_public.h" +#include "state_tracker/st_context.h" +#include "state_tracker/st_cb_fbo.h" + +#include "util/u_memory.h" + +static struct pipe_surface * +dri_surface_from_handle(struct drm_api *api, + struct pipe_screen *screen, + unsigned handle, + enum pipe_format format, + unsigned width, unsigned height, unsigned pitch) +{ + struct pipe_surface *surface = NULL; + struct pipe_texture *texture = NULL; + struct pipe_texture templat; + + memset(&templat, 0, sizeof(templat)); + templat.tex_usage |= PIPE_TEXTURE_USAGE_RENDER_TARGET; + templat.target = PIPE_TEXTURE_2D; + templat.last_level = 0; + templat.depth[0] = 1; + templat.format = format; + templat.width[0] = width; + templat.height[0] = height; + pf_get_block(templat.format, &templat.block); + + texture = api->texture_from_shared_handle(api, screen, &templat, + "dri2 buffer", pitch, handle); + + if (!texture) { + debug_printf("%s: Failed to blanket the buffer with a texture\n", __func__); + return NULL; + } + + surface = screen->get_tex_surface(screen, texture, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE); + + /* we don't need the texture from this point on */ + pipe_texture_reference(&texture, NULL); + return surface; +} + +/** + * Pixmaps have will have the same name of fake front and front. + */ +static boolean +dri2_check_if_pixmap(__DRIbuffer *buffers, int count) +{ + boolean found = FALSE; + boolean is_pixmap = FALSE; + unsigned name; + int i; + + for (i = 0; i < count; i++) { + switch (buffers[i].attachment) { + case __DRI_BUFFER_FRONT_LEFT: + case __DRI_BUFFER_FAKE_FRONT_LEFT: + if (found) { + is_pixmap = buffers[i].name == name; + } else { + name = buffers[i].name; + found = TRUE; + } + default: + continue; + } + } + + return is_pixmap; +} + +/** + * This will be called a drawable is known to have been resized. + */ +void +dri_get_buffers(__DRIdrawablePrivate * dPriv) +{ + + struct dri_drawable *drawable = dri_drawable(dPriv); + struct pipe_surface *surface = NULL; + struct pipe_screen *screen = dri_screen(drawable->sPriv)->pipe_screen; + __DRIbuffer *buffers = NULL; + __DRIscreen *dri_screen = drawable->sPriv; + __DRIdrawable *dri_drawable = drawable->dPriv; + struct drm_api *api = ((struct dri_screen*)(dri_screen->private))->api; + boolean have_depth = FALSE; + int i, count; + + buffers = (*dri_screen->dri2.loader->getBuffers) (dri_drawable, + &dri_drawable->w, + &dri_drawable->h, + drawable->attachments, + drawable-> + num_attachments, &count, + dri_drawable-> + loaderPrivate); + + if (buffers == NULL) { + return; + } + + /* set one cliprect to cover the whole dri_drawable */ + dri_drawable->x = 0; + dri_drawable->y = 0; + dri_drawable->backX = 0; + dri_drawable->backY = 0; + dri_drawable->numClipRects = 1; + dri_drawable->pClipRects[0].x1 = 0; + dri_drawable->pClipRects[0].y1 = 0; + dri_drawable->pClipRects[0].x2 = dri_drawable->w; + dri_drawable->pClipRects[0].y2 = dri_drawable->h; + dri_drawable->numBackClipRects = 1; + dri_drawable->pBackClipRects[0].x1 = 0; + dri_drawable->pBackClipRects[0].y1 = 0; + dri_drawable->pBackClipRects[0].x2 = dri_drawable->w; + dri_drawable->pBackClipRects[0].y2 = dri_drawable->h; + + if (drawable->old_num == count && + drawable->old_w == dri_drawable->w && + drawable->old_h == dri_drawable->h && + memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0) { + return; + } else { + drawable->old_num = count; + drawable->old_w = dri_drawable->w; + drawable->old_h = dri_drawable->h; + memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count); + } + + drawable->is_pixmap = dri2_check_if_pixmap(buffers, count); + + for (i = 0; i < count; i++) { + enum pipe_format format = 0; + int index = 0; + + switch (buffers[i].attachment) { + case __DRI_BUFFER_FRONT_LEFT: + continue; + case __DRI_BUFFER_FAKE_FRONT_LEFT: + index = ST_SURFACE_FRONT_LEFT; + format = drawable->color_format; + break; + case __DRI_BUFFER_BACK_LEFT: + index = ST_SURFACE_BACK_LEFT; + format = drawable->color_format; + break; + case __DRI_BUFFER_DEPTH: + case __DRI_BUFFER_DEPTH_STENCIL: + case __DRI_BUFFER_STENCIL: + index = ST_SURFACE_DEPTH; + format = drawable->depth_stencil_format; + break; + case __DRI_BUFFER_ACCUM: + default: + assert(0); + } + + if (index == ST_SURFACE_DEPTH) { + if (have_depth) + continue; + else + have_depth = TRUE; + } + + surface = dri_surface_from_handle(api, + screen, + buffers[i].name, + format, + dri_drawable->w, + dri_drawable->h, buffers[i].pitch); + + switch (buffers[i].attachment) { + case __DRI_BUFFER_FAKE_FRONT_LEFT: + case __DRI_BUFFER_BACK_LEFT: + drawable->color_format = surface->format; + break; + case __DRI_BUFFER_DEPTH: + case __DRI_BUFFER_DEPTH_STENCIL: + case __DRI_BUFFER_STENCIL: + drawable->depth_stencil_format = surface->format; + break; + } + + st_set_framebuffer_surface(drawable->stfb, index, surface); + pipe_surface_reference(&surface, NULL); + } + /* this needed, or else the state tracker fails to pick the new buffers */ + st_resize_framebuffer(drawable->stfb, dri_drawable->w, dri_drawable->h); +} + +/** + * These are used for GLX_EXT_texture_from_pixmap + */ +void dri2_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target, + GLint format, __DRIdrawable *dPriv) +{ + struct dri_drawable *drawable = dri_drawable(dPriv); + struct pipe_surface *ps; + + if (!drawable->stfb->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer) { + struct gl_renderbuffer *rb = + st_new_renderbuffer_fb(drawable->color_format, 0 /*XXX*/, FALSE); + _mesa_add_renderbuffer(&drawable->stfb->Base, BUFFER_FRONT_LEFT, rb); + } + + dri_get_buffers(drawable->dPriv); + st_get_framebuffer_surface(drawable->stfb, ST_SURFACE_FRONT_LEFT, &ps); + + st_bind_texture_surface(ps, target == GL_TEXTURE_2D ? ST_TEXTURE_2D : + ST_TEXTURE_RECT, 0, drawable->color_format); +} + +void dri2_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, + __DRIdrawable *dPriv) +{ + dri2_set_tex_buffer2(pDRICtx, target, GLX_TEXTURE_FORMAT_RGBA_EXT, dPriv); +} + +void +dri_flush_frontbuffer(struct pipe_screen *screen, + struct pipe_surface *surf, void *context_private) +{ + struct dri_context *ctx = (struct dri_context *)context_private; + struct dri_drawable *drawable = dri_drawable(ctx->dPriv); + __DRIdrawable *dri_drawable = ctx->dPriv; + __DRIscreen *dri_screen = ctx->sPriv; + + /* XXX Does this function get called with DRI1? */ + + if (ctx->dPriv == NULL) { + debug_printf("%s: no drawable bound to context\n", __func__); + return; + } + +#if 0 + /* TODO if rendering to pixmaps is slow enable this code. */ + if (drawable->is_pixmap) + return; +#else + (void)drawable; +#endif + + (*dri_screen->dri2.loader->flushFrontBuffer)(dri_drawable, + dri_drawable->loaderPrivate); +} + +/** + * This is called when we need to set up GL rendering to a new X window. + */ +boolean +dri_create_buffer(__DRIscreenPrivate * sPriv, + __DRIdrawablePrivate * dPriv, + const __GLcontextModes * visual, boolean isPixmap) +{ + struct dri_screen *screen = sPriv->private; + struct dri_drawable *drawable = NULL; + int i; + + if (isPixmap) + goto fail; /* not implemented */ + + drawable = CALLOC_STRUCT(dri_drawable); + if (drawable == NULL) + goto fail; + + if (visual->redBits == 8) { + if (visual->alphaBits == 8) + drawable->color_format = PIPE_FORMAT_A8R8G8B8_UNORM; + else + drawable->color_format = PIPE_FORMAT_X8R8G8B8_UNORM; + } else { + drawable->color_format = PIPE_FORMAT_R5G6B5_UNORM; + } + + switch(visual->depthBits) { + default: + case 0: + drawable->depth_stencil_format = PIPE_FORMAT_NONE; + break; + case 16: + drawable->depth_stencil_format = PIPE_FORMAT_Z16_UNORM; + break; + case 24: + if (visual->stencilBits == 0) { + drawable->depth_stencil_format = (screen->d_depth_bits_last) ? + PIPE_FORMAT_X8Z24_UNORM: + PIPE_FORMAT_Z24X8_UNORM; + } else { + drawable->depth_stencil_format = (screen->sd_depth_bits_last) ? + PIPE_FORMAT_S8Z24_UNORM: + PIPE_FORMAT_Z24S8_UNORM; + } + break; + case 32: + drawable->depth_stencil_format = PIPE_FORMAT_Z32_UNORM; + break; + } + + drawable->stfb = st_create_framebuffer(visual, + drawable->color_format, + drawable->depth_stencil_format, + drawable->depth_stencil_format, + dPriv->w, + dPriv->h, (void *)drawable); + if (drawable->stfb == NULL) + goto fail; + + drawable->sPriv = sPriv; + drawable->dPriv = dPriv; + dPriv->driverPrivate = (void *)drawable; + + /* setup dri2 buffers information */ + /* TODO incase of double buffer visual, delay fake creation */ + i = 0; + drawable->attachments[i++] = __DRI_BUFFER_FRONT_LEFT; + + if (visual->doubleBufferMode) + drawable->attachments[i++] = __DRI_BUFFER_BACK_LEFT; + else + drawable->attachments[i++] = __DRI_BUFFER_FAKE_FRONT_LEFT; + if (visual->depthBits && visual->stencilBits) + drawable->attachments[i++] = __DRI_BUFFER_DEPTH_STENCIL; + else if (visual->depthBits) + drawable->attachments[i++] = __DRI_BUFFER_DEPTH; + else if (visual->stencilBits) + drawable->attachments[i++] = __DRI_BUFFER_STENCIL; + drawable->num_attachments = i; + + drawable->desired_fences = 2; + + return GL_TRUE; + fail: + FREE(drawable); + return GL_FALSE; +} + +static struct pipe_fence_handle * +dri_swap_fences_pop_front(struct dri_drawable *draw) +{ + struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen; + struct pipe_fence_handle *fence = NULL; + + if (draw->cur_fences >= draw->desired_fences) { + screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]); + screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); + --draw->cur_fences; + draw->tail &= DRI_SWAP_FENCES_MASK; + } + return fence; +} + +static void +dri_swap_fences_push_back(struct dri_drawable *draw, + struct pipe_fence_handle *fence) +{ + struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen; + + if (!fence) + return; + + if (draw->cur_fences < DRI_SWAP_FENCES_MAX) { + draw->cur_fences++; + screen->fence_reference(screen, &draw->swap_fences[draw->head++], + fence); + draw->head &= DRI_SWAP_FENCES_MASK; + } +} + +void +dri_destroy_buffer(__DRIdrawablePrivate * dPriv) +{ + struct dri_drawable *drawable = dri_drawable(dPriv); + struct pipe_fence_handle *fence; + struct pipe_screen *screen = dri_screen(drawable->sPriv)->pipe_screen; + + st_unreference_framebuffer(drawable->stfb); + drawable->desired_fences = 0; + while (drawable->cur_fences) { + fence = dri_swap_fences_pop_front(drawable); + screen->fence_reference(screen, &fence, NULL); + } + + FREE(drawable); +} + +static void +dri1_update_drawables_locked(struct dri_context *ctx, + __DRIdrawablePrivate * driDrawPriv, + __DRIdrawablePrivate * driReadPriv) +{ + if (ctx->stLostLock) { + ctx->stLostLock = FALSE; + if (driDrawPriv == driReadPriv) + DRI_VALIDATE_DRAWABLE_INFO(ctx->sPriv, driDrawPriv); + else + DRI_VALIDATE_TWO_DRAWABLES_INFO(ctx->sPriv, driDrawPriv, + driReadPriv); + } +} + +/** + * This ensures all contexts which bind to a drawable pick up the + * drawable change and signal new buffer state. + * Calling st_resize_framebuffer for each context may seem like overkill, + * but no new buffers will actually be allocated if the dimensions don't + * change. + */ + +static void +dri1_propagate_drawable_change(struct dri_context *ctx) +{ + __DRIdrawablePrivate *dPriv = ctx->dPriv; + __DRIdrawablePrivate *rPriv = ctx->rPriv; + boolean flushed = FALSE; + + if (dPriv && ctx->d_stamp != dPriv->lastStamp) { + + st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); + flushed = TRUE; + ctx->d_stamp = dPriv->lastStamp; + st_resize_framebuffer(dri_drawable(dPriv)->stfb, dPriv->w, dPriv->h); + + } + + if (rPriv && dPriv != rPriv && ctx->r_stamp != rPriv->lastStamp) { + + if (!flushed) + st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); + ctx->r_stamp = rPriv->lastStamp; + st_resize_framebuffer(dri_drawable(rPriv)->stfb, rPriv->w, rPriv->h); + + } else if (rPriv && dPriv == rPriv) { + + ctx->r_stamp = ctx->d_stamp; + + } +} + +void +dri1_update_drawables(struct dri_context *ctx, + struct dri_drawable *draw, struct dri_drawable *read) +{ + dri_lock(ctx); + dri1_update_drawables_locked(ctx, draw->dPriv, read->dPriv); + dri_unlock(ctx); + + dri1_propagate_drawable_change(ctx); +} + +static INLINE boolean +dri1_intersect_src_bbox(struct drm_clip_rect *dst, + int dst_x, + int dst_y, + const struct drm_clip_rect *src, + const struct drm_clip_rect *bbox) +{ + int xy1; + int xy2; + + xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 : + (int)bbox->x1 + dst_x; + xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 : + (int)bbox->x2 + dst_x; + if (xy1 >= xy2 || xy1 < 0) + return FALSE; + + dst->x1 = xy1; + dst->x2 = xy2; + + xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 : + (int)bbox->y1 + dst_y; + xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 : + (int)bbox->y2 + dst_y; + if (xy1 >= xy2 || xy1 < 0) + return FALSE; + + dst->y1 = xy1; + dst->y2 = xy2; + return TRUE; +} + +static void +dri1_swap_copy(struct dri_context *ctx, + struct pipe_surface *dst, + struct pipe_surface *src, + __DRIdrawablePrivate * dPriv, const struct drm_clip_rect *bbox) +{ + struct pipe_context *pipe = ctx->pipe; + struct drm_clip_rect clip; + struct drm_clip_rect *cur; + int i; + + cur = dPriv->pClipRects; + + for (i = 0; i < dPriv->numClipRects; ++i) { + if (dri1_intersect_src_bbox(&clip, dPriv->x, dPriv->y, cur++, bbox)) + pipe->surface_copy(pipe, dst, clip.x1, clip.y1, + src, + (int)clip.x1 - dPriv->x, + (int)clip.y1 - dPriv->y, + clip.x2 - clip.x1, clip.y2 - clip.y1); + } +} + +static void +dri1_copy_to_front(struct dri_context *ctx, + struct pipe_surface *surf, + __DRIdrawablePrivate * dPriv, + const struct drm_clip_rect *sub_box, + struct pipe_fence_handle **fence) +{ + struct pipe_context *pipe = ctx->pipe; + boolean save_lost_lock; + uint cur_w; + uint cur_h; + struct drm_clip_rect bbox; + boolean visible = TRUE; + + *fence = NULL; + + dri_lock(ctx); + save_lost_lock = ctx->stLostLock; + dri1_update_drawables_locked(ctx, dPriv, dPriv); + st_get_framebuffer_dimensions(dri_drawable(dPriv)->stfb, &cur_w, &cur_h); + + bbox.x1 = 0; + bbox.x2 = cur_w; + bbox.y1 = 0; + bbox.y2 = cur_h; + + if (sub_box) + visible = dri1_intersect_src_bbox(&bbox, 0, 0, &bbox, sub_box); + + if (visible && __dri1_api_hooks->present_locked) { + + __dri1_api_hooks->present_locked(pipe, + surf, + dPriv->pClipRects, + dPriv->numClipRects, + dPriv->x, dPriv->y, &bbox, fence); + + } else if (visible && __dri1_api_hooks->front_srf_locked) { + + struct pipe_surface *front = __dri1_api_hooks->front_srf_locked(pipe); + + if (front) + dri1_swap_copy(ctx, front, surf, dPriv, &bbox); + + st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence); + } + + ctx->stLostLock = save_lost_lock; + + /** + * FIXME: Revisit this: Update drawables on copy_sub_buffer ? + */ + + if (!sub_box) + dri1_update_drawables_locked(ctx, ctx->dPriv, ctx->rPriv); + + dri_unlock(ctx); + dri1_propagate_drawable_change(ctx); +} + +void +dri1_flush_frontbuffer(struct pipe_screen *screen, + struct pipe_surface *surf, void *context_private) +{ + struct dri_context *ctx = (struct dri_context *)context_private; + struct pipe_fence_handle *dummy_fence; + + dri1_copy_to_front(ctx, surf, ctx->dPriv, NULL, &dummy_fence); + screen->fence_reference(screen, &dummy_fence, NULL); + + /** + * FIXME: Do we need swap throttling here? + */ +} + +void +dri_swap_buffers(__DRIdrawablePrivate * dPriv) +{ + struct dri_context *ctx; + struct pipe_surface *back_surf; + struct dri_drawable *draw = dri_drawable(dPriv); + struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen; + struct pipe_fence_handle *fence; + struct st_context *st = st_get_current(); + + assert(__dri1_api_hooks != NULL); + + if (!st) + return; /* For now */ + + ctx = (struct dri_context *)st->pipe->priv; + + st_get_framebuffer_surface(draw->stfb, ST_SURFACE_BACK_LEFT, &back_surf); + if (back_surf) { + st_notify_swapbuffers(draw->stfb); + st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); + fence = dri_swap_fences_pop_front(draw); + if (fence) { + (void)screen->fence_finish(screen, fence, 0); + screen->fence_reference(screen, &fence, NULL); + } + dri1_copy_to_front(ctx, back_surf, dPriv, NULL, &fence); + dri_swap_fences_push_back(draw, fence); + screen->fence_reference(screen, &fence, NULL); + } +} + +void +dri_copy_sub_buffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h) +{ + struct pipe_screen *screen = dri_screen(dPriv->driScreenPriv)->pipe_screen; + struct drm_clip_rect sub_bbox; + struct dri_context *ctx; + struct pipe_surface *back_surf; + struct dri_drawable *draw = dri_drawable(dPriv); + struct pipe_fence_handle *dummy_fence; + struct st_context *st = st_get_current(); + + assert(__dri1_api_hooks != NULL); + + if (!st) + return; + + ctx = (struct dri_context *)st->pipe->priv; + + sub_bbox.x1 = x; + sub_bbox.x2 = x + w; + sub_bbox.y1 = y; + sub_bbox.y2 = y + h; + + st_get_framebuffer_surface(draw->stfb, ST_SURFACE_BACK_LEFT, &back_surf); + if (back_surf) { + st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); + dri1_copy_to_front(ctx, back_surf, dPriv, &sub_bbox, &dummy_fence); + screen->fence_reference(screen, &dummy_fence, NULL); + } +} + +/* vim: set sw=3 ts=8 sts=3 expandtab: */ diff --git a/src/gallium/state_trackers/dri/dri_drawable.h b/src/gallium/state_trackers/dri/dri_drawable.h new file mode 100644 index 0000000000..b910930db4 --- /dev/null +++ b/src/gallium/state_trackers/dri/dri_drawable.h @@ -0,0 +1,111 @@ +/************************************************************************** + * + * Copyright 2009, VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef DRI_DRAWABLE_H +#define DRI_DRAWABLE_H + +#include "pipe/p_compiler.h" + +struct pipe_surface; +struct pipe_fence_handle; +struct st_framebuffer; +struct dri_context; + +#define DRI_SWAP_FENCES_MAX 8 +#define DRI_SWAP_FENCES_MASK 7 + +struct dri_drawable +{ + /* dri */ + __DRIdrawablePrivate *dPriv; + __DRIscreenPrivate *sPriv; + + unsigned attachments[8]; + unsigned num_attachments; + + boolean is_pixmap; + + __DRIbuffer old[8]; + unsigned old_num; + unsigned old_w; + unsigned old_h; + + /* gallium */ + struct st_framebuffer *stfb; + struct pipe_fence_handle *swap_fences[DRI_SWAP_FENCES_MAX]; + unsigned int head; + unsigned int tail; + unsigned int desired_fences; + unsigned int cur_fences; + + enum pipe_format color_format; + enum pipe_format depth_stencil_format; +}; + +static INLINE struct dri_drawable * +dri_drawable(__DRIdrawablePrivate * driDrawPriv) +{ + return (struct dri_drawable *)driDrawPriv->driverPrivate; +} + +/*********************************************************************** + * dri_drawable.c + */ +boolean +dri_create_buffer(__DRIscreenPrivate * sPriv, + __DRIdrawablePrivate * dPriv, + const __GLcontextModes * visual, boolean isPixmap); + +void +dri_flush_frontbuffer(struct pipe_screen *screen, + struct pipe_surface *surf, void *context_private); + +void dri_swap_buffers(__DRIdrawablePrivate * dPriv); + +void +dri_copy_sub_buffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h); + +void dri_get_buffers(__DRIdrawablePrivate * dPriv); + +void dri_destroy_buffer(__DRIdrawablePrivate * dPriv); + +void dri2_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target, + GLint glx_texture_format, __DRIdrawable *dPriv); + +void dri2_set_tex_buffer(__DRIcontext *pDRICtx, GLint target, + __DRIdrawable *dPriv); + +void +dri1_update_drawables(struct dri_context *ctx, + struct dri_drawable *draw, struct dri_drawable *read); + +void +dri1_flush_frontbuffer(struct pipe_screen *screen, + struct pipe_surface *surf, void *context_private); +#endif + +/* vim: set sw=3 ts=8 sts=3 expandtab: */ diff --git a/src/gallium/state_trackers/dri/dri_extensions.c b/src/gallium/state_trackers/dri/dri_extensions.c new file mode 100644 index 0000000000..4349a4d1d2 --- /dev/null +++ b/src/gallium/state_trackers/dri/dri_extensions.c @@ -0,0 +1,128 @@ +/************************************************************************** + * + * Copyright 2009, VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Author: Keith Whitwell <keithw@vmware.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + */ + +#include "dri_screen.h" +#include "dri_context.h" +#include "state_tracker/st_context.h" + +#define need_GL_ARB_map_buffer_range +#define need_GL_ARB_multisample +#define need_GL_ARB_occlusion_query +#define need_GL_ARB_point_parameters +#define need_GL_ARB_shader_objects +#define need_GL_ARB_texture_compression +#define need_GL_ARB_vertex_buffer_object +#define need_GL_ARB_vertex_program +#define need_GL_ARB_vertex_shader +#define need_GL_ARB_window_pos +#define need_GL_EXT_blend_color +#define need_GL_EXT_blend_equation_separate +#define need_GL_EXT_blend_func_separate +#define need_GL_EXT_blend_minmax +#define need_GL_EXT_cull_vertex +#define need_GL_EXT_fog_coord +#define need_GL_EXT_framebuffer_object +#define need_GL_EXT_multi_draw_arrays +#define need_GL_EXT_secondary_color +#define need_GL_NV_vertex_program +#define need_GL_VERSION_2_0 +#define need_GL_VERSION_2_1 +#include "extension_helper.h" + +/** + * Extension strings exported by the driver. + */ +const struct dri_extension card_extensions[] = { + {"GL_ARB_fragment_shader", NULL}, + {"GL_ARB_map_buffer_range", GL_ARB_map_buffer_range_functions}, + {"GL_ARB_multisample", GL_ARB_multisample_functions}, + {"GL_ARB_multitexture", NULL}, + {"GL_ARB_occlusion_query", GL_ARB_occlusion_query_functions}, + {"GL_ARB_pixel_buffer_object", NULL}, + {"GL_ARB_point_parameters", GL_ARB_point_parameters_functions}, + {"GL_ARB_shading_language_100", GL_VERSION_2_0_functions }, + {"GL_ARB_shading_language_120", GL_VERSION_2_1_functions }, + {"GL_ARB_shader_objects", GL_ARB_shader_objects_functions}, + {"GL_ARB_texture_border_clamp", NULL}, + {"GL_ARB_texture_compression", GL_ARB_texture_compression_functions}, + {"GL_ARB_texture_cube_map", NULL}, + {"GL_ARB_texture_env_add", NULL}, + {"GL_ARB_texture_env_combine", NULL}, + {"GL_ARB_texture_env_dot3", NULL}, + {"GL_ARB_texture_mirrored_repeat", NULL}, + {"GL_ARB_texture_rectangle", NULL}, + {"GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions}, + {"GL_ARB_vertex_shader", GL_ARB_vertex_shader_functions}, + {"GL_ARB_vertex_program", GL_ARB_vertex_program_functions}, + {"GL_ARB_window_pos", GL_ARB_window_pos_functions}, + {"GL_EXT_blend_color", GL_EXT_blend_color_functions}, + {"GL_EXT_blend_equation_separate", GL_EXT_blend_equation_separate_functions}, + {"GL_EXT_blend_func_separate", GL_EXT_blend_func_separate_functions}, + {"GL_EXT_blend_minmax", GL_EXT_blend_minmax_functions}, + {"GL_EXT_blend_subtract", NULL}, + {"GL_EXT_cull_vertex", GL_EXT_cull_vertex_functions}, + {"GL_EXT_fog_coord", GL_EXT_fog_coord_functions}, + {"GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions}, + {"GL_EXT_multi_draw_arrays", GL_EXT_multi_draw_arrays_functions}, + {"GL_EXT_packed_depth_stencil", NULL}, + {"GL_EXT_pixel_buffer_object", NULL}, + {"GL_EXT_secondary_color", GL_EXT_secondary_color_functions}, + {"GL_EXT_stencil_wrap", NULL}, + {"GL_EXT_texture_edge_clamp", NULL}, + {"GL_EXT_texture_env_combine", NULL}, + {"GL_EXT_texture_env_dot3", NULL}, + {"GL_EXT_texture_filter_anisotropic", NULL}, + {"GL_EXT_texture_lod_bias", NULL}, + {"GL_3DFX_texture_compression_FXT1", NULL}, + {"GL_APPLE_client_storage", NULL}, + {"GL_MESA_pack_invert", NULL}, + {"GL_MESA_ycbcr_texture", NULL}, + {"GL_NV_blend_square", NULL}, + {"GL_NV_vertex_program", GL_NV_vertex_program_functions}, + {"GL_NV_vertex_program1_1", NULL}, + {"GL_SGIS_generate_mipmap", NULL}, + {NULL, NULL} +}; + +void +dri_init_extensions(struct dri_context *ctx) +{ + /* The card_extensions list should be pruned according to the + * capabilities of the pipe_screen. This is actually something + * that can/should be done inside st_create_context(). + */ + if (ctx) + driInitExtensions(ctx->st->ctx, card_extensions, GL_TRUE); + else + driInitExtensions(NULL, card_extensions, GL_FALSE); +} + +/* vim: set sw=3 ts=8 sts=3 expandtab: */ diff --git a/src/gallium/state_trackers/dri/dri_screen.c b/src/gallium/state_trackers/dri/dri_screen.c new file mode 100644 index 0000000000..884b6d5011 --- /dev/null +++ b/src/gallium/state_trackers/dri/dri_screen.c @@ -0,0 +1,354 @@ +/************************************************************************** + * + * Copyright 2009, VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Author: Keith Whitwell <keithw@vmware.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + */ + +#include "utils.h" +#include "vblank.h" +#include "xmlpool.h" + +#include "dri_screen.h" +#include "dri_context.h" +#include "dri_drawable.h" + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_inlines.h" +#include "pipe/p_format.h" +#include "state_tracker/drm_api.h" +#include "state_tracker/dri1_api.h" +#include "state_tracker/st_public.h" +#include "state_tracker/st_cb_fbo.h" + +PUBLIC const char __driConfigOptions[] = + DRI_CONF_BEGIN DRI_CONF_SECTION_PERFORMANCE + DRI_CONF_FTHROTTLE_MODE(DRI_CONF_FTHROTTLE_IRQS) + DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_0) + DRI_CONF_SECTION_END DRI_CONF_SECTION_QUALITY + /*DRI_CONF_FORCE_S3TC_ENABLE(false) */ + DRI_CONF_ALLOW_LARGE_TEXTURES(1) + DRI_CONF_SECTION_END DRI_CONF_END; + + const uint __driNConfigOptions = 3; + +static const __DRItexBufferExtension dri2TexBufferExtension = { + { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION }, + dri2_set_tex_buffer, + dri2_set_tex_buffer2, +}; + + static const __DRIextension *dri_screen_extensions[] = { + &driReadDrawableExtension, + &driCopySubBufferExtension.base, + &driSwapControlExtension.base, + &driFrameTrackingExtension.base, + &driMediaStreamCounterExtension.base, + &dri2TexBufferExtension.base, + NULL + }; + +struct dri1_api *__dri1_api_hooks = NULL; + +static const __DRIconfig ** +dri_fill_in_modes(struct dri_screen *screen, + unsigned pixel_bits) +{ + __DRIconfig **configs = NULL; + unsigned num_modes; + uint8_t depth_bits_array[5]; + uint8_t stencil_bits_array[5]; + uint8_t msaa_samples_array[1]; + unsigned depth_buffer_factor; + unsigned back_buffer_factor; + unsigned msaa_samples_factor; + struct pipe_screen *p_screen = screen->pipe_screen; + boolean pf_r5g6b5, pf_a8r8g8b8, pf_x8r8g8b8; + boolean pf_z16, pf_x8z24, pf_z24x8, pf_s8z24, pf_z24s8, pf_z32; + + static const GLenum back_buffer_modes[] = { + GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML + }; + + depth_bits_array[0] = 0; + stencil_bits_array[0] = 0; + depth_buffer_factor = 1; + + pf_z16 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_Z16_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); + pf_z32 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_Z32_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); + pf_x8z24 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_X8Z24_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); + pf_z24x8 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_Z24X8_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); + pf_s8z24 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_S8Z24_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); + pf_z24s8 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_Z24S8_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); + pf_r5g6b5 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_R5G6B5_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_RENDER_TARGET, 0); + pf_a8r8g8b8 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_A8R8G8B8_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_RENDER_TARGET, 0); + pf_x8r8g8b8 = p_screen->is_format_supported(p_screen, PIPE_FORMAT_X8R8G8B8_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_RENDER_TARGET, 0); + + if (pf_z16) { + depth_bits_array[depth_buffer_factor] = 16; + stencil_bits_array[depth_buffer_factor++] = 0; + } + if (pf_x8z24 || pf_z24x8) { + depth_bits_array[depth_buffer_factor] = 24; + stencil_bits_array[depth_buffer_factor++] = 0; + screen->d_depth_bits_last = pf_x8z24; + } + if (pf_s8z24 || pf_z24s8) { + depth_bits_array[depth_buffer_factor] = 24; + stencil_bits_array[depth_buffer_factor++] = 8; + screen->sd_depth_bits_last = pf_s8z24; + } + if (pf_z32) { + depth_bits_array[depth_buffer_factor] = 32; + stencil_bits_array[depth_buffer_factor++] = 0; + } + + msaa_samples_array[0] = 0; + back_buffer_factor = 3; + msaa_samples_factor = 1; + + num_modes = + depth_buffer_factor * back_buffer_factor * msaa_samples_factor * 4; + + if (pixel_bits == 16 && pf_r5g6b5) { + configs = driCreateConfigs(GL_RGB, GL_UNSIGNED_SHORT_5_6_5, + depth_bits_array, stencil_bits_array, + depth_buffer_factor, back_buffer_modes, + back_buffer_factor, + msaa_samples_array, 1); + } else { + __DRIconfig **configs_a8r8g8b8 = NULL; + __DRIconfig **configs_x8r8g8b8 = NULL; + + if (pf_a8r8g8b8) + configs_a8r8g8b8 = driCreateConfigs(GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, + depth_bits_array, + stencil_bits_array, + depth_buffer_factor, + back_buffer_modes, + back_buffer_factor, + msaa_samples_array, 1); + if (pf_x8r8g8b8) + configs_x8r8g8b8 = driCreateConfigs(GL_BGR, GL_UNSIGNED_INT_8_8_8_8_REV, + depth_bits_array, + stencil_bits_array, + depth_buffer_factor, + back_buffer_modes, + back_buffer_factor, + msaa_samples_array, 1); + + if (configs_a8r8g8b8 && configs_x8r8g8b8) + configs = driConcatConfigs(configs_x8r8g8b8, configs_a8r8g8b8); + else if (configs_a8r8g8b8) + configs = configs_a8r8g8b8; + else if (configs_x8r8g8b8) + configs = configs_x8r8g8b8; + else + configs = NULL; + } + + if (configs == NULL) { + debug_printf("%s: driCreateConfigs failed\n", __FUNCTION__); + return NULL; + } + + return (const const __DRIconfig **)configs; +} + +/** + * Get information about previous buffer swaps. + */ +static int +dri_get_swap_info(__DRIdrawablePrivate * dPriv, __DRIswapInfo * sInfo) +{ + if (dPriv == NULL || dPriv->driverPrivate == NULL || sInfo == NULL) + return -1; + else + return 0; +} + +static INLINE void +dri_copy_version(struct dri1_api_version *dst, + const struct __DRIversionRec *src) +{ + dst->major = src->major; + dst->minor = src->minor; + dst->patch_level = src->patch; +} + +static const __DRIconfig ** +dri_init_screen(__DRIscreenPrivate * sPriv) +{ + struct dri_screen *screen; + const __DRIconfig **configs; + struct dri1_create_screen_arg arg; + + dri_init_extensions(NULL); + + screen = CALLOC_STRUCT(dri_screen); + if (!screen) + return NULL; + + screen->api = drm_api_create(); + screen->sPriv = sPriv; + screen->fd = sPriv->fd; + screen->drmLock = (drmLock *) & sPriv->pSAREA->lock; + + sPriv->private = (void *)screen; + sPriv->extensions = dri_screen_extensions; + + arg.base.mode = DRM_CREATE_DRI1; + arg.lf = &dri1_lf; + arg.ddx_info = sPriv->pDevPriv; + arg.ddx_info_size = sPriv->devPrivSize; + arg.sarea = sPriv->pSAREA; + dri_copy_version(&arg.ddx_version, &sPriv->ddx_version); + dri_copy_version(&arg.dri_version, &sPriv->dri_version); + dri_copy_version(&arg.drm_version, &sPriv->drm_version); + arg.api = NULL; + + screen->pipe_screen = screen->api->create_screen(screen->api, screen->fd, &arg.base); + + if (!screen->pipe_screen || !arg.api) { + debug_printf("%s: failed to create dri1 screen\n", __FUNCTION__); + goto out_no_screen; + } + + __dri1_api_hooks = arg.api; + + screen->pipe_screen->flush_frontbuffer = dri1_flush_frontbuffer; + driParseOptionInfo(&screen->optionCache, + __driConfigOptions, __driNConfigOptions); + + /** + * FIXME: If the driver supports format conversion swapbuffer blits, we might + * want to support other color bit depths than the server is currently + * using. + */ + + configs = dri_fill_in_modes(screen, sPriv->fbBPP); + if (!configs) + goto out_no_configs; + + return configs; + out_no_configs: + screen->pipe_screen->destroy(screen->pipe_screen); + out_no_screen: + FREE(screen); + return NULL; +} + +/** + * This is the driver specific part of the createNewScreen entry point. + * + * Returns the __GLcontextModes supported by this driver. + */ +static const __DRIconfig ** +dri_init_screen2(__DRIscreenPrivate * sPriv) +{ + struct dri_screen *screen; + struct drm_create_screen_arg arg; + + /* Set up dispatch table to cope with all known extensions */ + dri_init_extensions(NULL); + + screen = CALLOC_STRUCT(dri_screen); + if (!screen) + goto fail; + + screen->api = drm_api_create(); + screen->sPriv = sPriv; + screen->fd = sPriv->fd; + sPriv->private = (void *)screen; + sPriv->extensions = dri_screen_extensions; + arg.mode = DRM_CREATE_NORMAL; + + screen->pipe_screen = screen->api->create_screen(screen->api, screen->fd, &arg); + if (!screen->pipe_screen) { + debug_printf("%s: failed to create pipe_screen\n", __FUNCTION__); + goto fail; + } + + /* We need to hook in here */ + screen->pipe_screen->flush_frontbuffer = dri_flush_frontbuffer; + + driParseOptionInfo(&screen->optionCache, + __driConfigOptions, __driNConfigOptions); + + return dri_fill_in_modes(screen, 32); + fail: + return NULL; +} + +static void +dri_destroy_screen(__DRIscreenPrivate * sPriv) +{ + struct dri_screen *screen = dri_screen(sPriv); + + screen->pipe_screen->destroy(screen->pipe_screen); + FREE(screen); + sPriv->private = NULL; +} + +PUBLIC const struct __DriverAPIRec driDriverAPI = { + .InitScreen = dri_init_screen, + .DestroyScreen = dri_destroy_screen, + .CreateContext = dri_create_context, + .DestroyContext = dri_destroy_context, + .CreateBuffer = dri_create_buffer, + .DestroyBuffer = dri_destroy_buffer, + .SwapBuffers = dri_swap_buffers, + .MakeCurrent = dri_make_current, + .UnbindContext = dri_unbind_context, + .GetSwapInfo = dri_get_swap_info, + .GetDrawableMSC = driDrawableGetMSC32, + .WaitForMSC = driWaitForMSC32, + .CopySubBuffer = dri_copy_sub_buffer, + .InitScreen = dri_init_screen, + .InitScreen2 = dri_init_screen2, +}; + +/* vim: set sw=3 ts=8 sts=3 expandtab: */ diff --git a/src/gallium/state_trackers/dri/dri_screen.h b/src/gallium/state_trackers/dri/dri_screen.h new file mode 100644 index 0000000000..f6c56d0f0c --- /dev/null +++ b/src/gallium/state_trackers/dri/dri_screen.h @@ -0,0 +1,79 @@ +/************************************************************************** + * + * Copyright 2009, VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +/* + * Author: Keith Whitwell <keithw@vmware.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + */ + +#ifndef DRI_SCREEN_H +#define DRI_SCREEN_H + +#include "dri_util.h" +#include "xmlconfig.h" + +#include "pipe/p_compiler.h" + +#include "state_tracker/dri1_api.h" + +struct dri_screen +{ + /* dri */ + __DRIscreenPrivate *sPriv; + + /** + * Configuration cache with default values for all contexts + */ + driOptionCache optionCache; + + /* drm */ + int fd; + drmLock *drmLock; + + /* gallium */ + struct drm_api *api; + struct pipe_winsys *pipe_winsys; + struct pipe_screen *pipe_screen; + boolean d_depth_bits_last; + boolean sd_depth_bits_last; +}; + +/** cast wrapper */ +static INLINE struct dri_screen * +dri_screen(__DRIscreenPrivate * sPriv) +{ + return (struct dri_screen *)sPriv->private; +} + +/*********************************************************************** + * dri_screen.c + */ + +extern struct dri1_api *__dri1_api_hooks; + +#endif + +/* vim: set sw=3 ts=8 sts=3 expandtab: */ diff --git a/src/gallium/state_trackers/egl/Makefile b/src/gallium/state_trackers/egl/Makefile new file mode 100644 index 0000000000..e825aa718b --- /dev/null +++ b/src/gallium/state_trackers/egl/Makefile @@ -0,0 +1,19 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBNAME = egldrm + +LIBRARY_INCLUDES = \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/mesa/drivers/dri/common \ + -I$(TOP)/src/mesa \ + -I$(TOP)/include \ + -I$(TOP)/src/egl/main \ + $(shell pkg-config --cflags-only-I libdrm) + + +C_SOURCES = $(wildcard ./*.c) + + +include ../../Makefile.template diff --git a/src/gallium/state_trackers/egl/egl_context.c b/src/gallium/state_trackers/egl/egl_context.c new file mode 100644 index 0000000000..c4f7361ca0 --- /dev/null +++ b/src/gallium/state_trackers/egl/egl_context.c @@ -0,0 +1,179 @@ + +#include "utils.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "egl_tracker.h" + +#include "egllog.h" + + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" + +#include "state_tracker/st_public.h" +#include "state_tracker/drm_api.h" + +#include "GL/internal/glcore.h" + +#define need_GL_ARB_multisample +#define need_GL_ARB_point_parameters +#define need_GL_ARB_texture_compression +#define need_GL_ARB_vertex_buffer_object +#define need_GL_ARB_vertex_program +#define need_GL_ARB_window_pos +#define need_GL_EXT_blend_color +#define need_GL_EXT_blend_equation_separate +#define need_GL_EXT_blend_func_separate +#define need_GL_EXT_blend_minmax +#define need_GL_EXT_cull_vertex +#define need_GL_EXT_fog_coord +#define need_GL_EXT_framebuffer_object +#define need_GL_EXT_multi_draw_arrays +#define need_GL_EXT_secondary_color +#define need_GL_NV_vertex_program +#include "extension_helper.h" + +/** + * TODO HACK! FUGLY! + * Copied for intel extentions. + */ +const struct dri_extension card_extensions[] = { + {"GL_ARB_multisample", GL_ARB_multisample_functions}, + {"GL_ARB_multitexture", NULL}, + {"GL_ARB_point_parameters", GL_ARB_point_parameters_functions}, + {"GL_ARB_texture_border_clamp", NULL}, + {"GL_ARB_texture_compression", GL_ARB_texture_compression_functions}, + {"GL_ARB_texture_cube_map", NULL}, + {"GL_ARB_texture_env_add", NULL}, + {"GL_ARB_texture_env_combine", NULL}, + {"GL_ARB_texture_env_dot3", NULL}, + {"GL_ARB_texture_mirrored_repeat", NULL}, + {"GL_ARB_texture_rectangle", NULL}, + {"GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions}, + {"GL_ARB_pixel_buffer_object", NULL}, + {"GL_ARB_vertex_program", GL_ARB_vertex_program_functions}, + {"GL_ARB_window_pos", GL_ARB_window_pos_functions}, + {"GL_EXT_blend_color", GL_EXT_blend_color_functions}, + {"GL_EXT_blend_equation_separate", GL_EXT_blend_equation_separate_functions}, + {"GL_EXT_blend_func_separate", GL_EXT_blend_func_separate_functions}, + {"GL_EXT_blend_minmax", GL_EXT_blend_minmax_functions}, + {"GL_EXT_blend_subtract", NULL}, + {"GL_EXT_cull_vertex", GL_EXT_cull_vertex_functions}, + {"GL_EXT_fog_coord", GL_EXT_fog_coord_functions}, + {"GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions}, + {"GL_EXT_multi_draw_arrays", GL_EXT_multi_draw_arrays_functions}, + {"GL_EXT_packed_depth_stencil", NULL}, + {"GL_EXT_pixel_buffer_object", NULL}, + {"GL_EXT_secondary_color", GL_EXT_secondary_color_functions}, + {"GL_EXT_stencil_wrap", NULL}, + {"GL_EXT_texture_edge_clamp", NULL}, + {"GL_EXT_texture_env_combine", NULL}, + {"GL_EXT_texture_env_dot3", NULL}, + {"GL_EXT_texture_filter_anisotropic", NULL}, + {"GL_EXT_texture_lod_bias", NULL}, + {"GL_3DFX_texture_compression_FXT1", NULL}, + {"GL_APPLE_client_storage", NULL}, + {"GL_MESA_pack_invert", NULL}, + {"GL_MESA_ycbcr_texture", NULL}, + {"GL_NV_blend_square", NULL}, + {"GL_NV_vertex_program", GL_NV_vertex_program_functions}, + {"GL_NV_vertex_program1_1", NULL}, + {"GL_SGIS_generate_mipmap", NULL }, + {NULL, NULL} +}; + +_EGLContext * +drm_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, _EGLContext *share_list, const EGLint *attrib_list) +{ + struct drm_device *dev = lookup_drm_device(dpy); + struct drm_context *ctx; + struct drm_context *share = NULL; + struct st_context *st_share = NULL; + int i; + __GLcontextModes *visual; + + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { + switch (attrib_list[i]) { + /* no attribs defined for now */ + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglCreateContext"); + return EGL_NO_CONTEXT; + } + } + + ctx = (struct drm_context *) calloc(1, sizeof(struct drm_context)); + if (!ctx) + goto err_c; + + _eglInitContext(drv, &ctx->base, conf, attrib_list); + + ctx->pipe = dev->api->create_context(dev->api, dev->screen); + if (!ctx->pipe) + goto err_pipe; + + if (share) + st_share = share->st; + + visual = drm_visual_from_config(conf); + ctx->st = st_create_context(ctx->pipe, visual, st_share); + drm_visual_modes_destroy(visual); + + if (!ctx->st) + goto err_gl; + + return &ctx->base; + +err_gl: + ctx->pipe->destroy(ctx->pipe); +err_pipe: + free(ctx); +err_c: + return NULL; +} + +EGLBoolean +drm_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *context) +{ + struct drm_context *c = lookup_drm_context(context); + if (!_eglIsContextBound(&c->base)) { + st_destroy_context(c->st); + c->pipe->destroy(c->pipe); + free(c); + } + return EGL_TRUE; +} + +EGLBoolean +drm_make_current(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw, _EGLSurface *read, _EGLContext *context) +{ + struct drm_surface *readSurf = lookup_drm_surface(read); + struct drm_surface *drawSurf = lookup_drm_surface(draw); + struct drm_context *ctx = lookup_drm_context(context); + EGLBoolean b; + + b = _eglMakeCurrent(drv, dpy, draw, read, context); + if (!b) + return EGL_FALSE; + + if (ctx) { + if (!drawSurf || !readSurf) + return EGL_FALSE; + + drawSurf->user = ctx; + readSurf->user = ctx; + + st_make_current(ctx->st, drawSurf->stfb, readSurf->stfb); + + /* st_resize_framebuffer needs a bound context to work */ + st_resize_framebuffer(drawSurf->stfb, drawSurf->w, drawSurf->h); + st_resize_framebuffer(readSurf->stfb, readSurf->w, readSurf->h); + } else { + drawSurf->user = NULL; + readSurf->user = NULL; + + st_make_current(NULL, NULL, NULL); + } + + return EGL_TRUE; +} diff --git a/src/gallium/state_trackers/egl/egl_surface.c b/src/gallium/state_trackers/egl/egl_surface.c new file mode 100644 index 0000000000..69e2d6b708 --- /dev/null +++ b/src/gallium/state_trackers/egl/egl_surface.c @@ -0,0 +1,387 @@ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "egl_tracker.h" + +#include "egllog.h" + +#include "pipe/p_inlines.h" +#include "pipe/p_screen.h" +#include "pipe/p_context.h" + +#include "state_tracker/drm_api.h" + +/* + * Util functions + */ + +static drmModeModeInfoPtr +drm_find_mode(drmModeConnectorPtr connector, _EGLMode *mode) +{ + int i; + drmModeModeInfoPtr m = NULL; + + for (i = 0; i < connector->count_modes; i++) { + m = &connector->modes[i]; + if (m->hdisplay == mode->Width && m->vdisplay == mode->Height && m->vrefresh == mode->RefreshRate) + break; + m = &connector->modes[0]; /* if we can't find one, return first */ + } + + return m; +} + +static struct st_framebuffer * +drm_create_framebuffer(const __GLcontextModes *visual, + unsigned width, + unsigned height, + void *priv) +{ + enum pipe_format colorFormat, depthFormat, stencilFormat; + + if (visual->redBits == 5) + colorFormat = PIPE_FORMAT_R5G6B5_UNORM; + else + colorFormat = PIPE_FORMAT_A8R8G8B8_UNORM; + + if (visual->depthBits == 16) + depthFormat = PIPE_FORMAT_Z16_UNORM; + else if (visual->depthBits == 24) + depthFormat = PIPE_FORMAT_S8Z24_UNORM; + else + depthFormat = PIPE_FORMAT_NONE; + + if (visual->stencilBits == 8) + stencilFormat = PIPE_FORMAT_S8Z24_UNORM; + else + stencilFormat = PIPE_FORMAT_NONE; + + return st_create_framebuffer(visual, + colorFormat, + depthFormat, + stencilFormat, + width, + height, + priv); +} + +static void +drm_create_texture(_EGLDisplay *dpy, + struct drm_screen *scrn, + unsigned w, unsigned h) +{ + struct drm_device *dev = lookup_drm_device(dpy); + struct pipe_screen *screen = dev->screen; + struct pipe_surface *surface; + struct pipe_texture *texture; + struct pipe_texture templat; + struct pipe_buffer *buf = NULL; + unsigned pitch = 0; + + memset(&templat, 0, sizeof(templat)); + templat.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; + templat.tex_usage |= PIPE_TEXTURE_USAGE_PRIMARY; + templat.target = PIPE_TEXTURE_2D; + templat.last_level = 0; + templat.depth[0] = 1; + templat.format = PIPE_FORMAT_A8R8G8B8_UNORM; + templat.width[0] = w; + templat.height[0] = h; + pf_get_block(templat.format, &templat.block); + + texture = screen->texture_create(dev->screen, + &templat); + + if (!texture) + goto err_tex; + + surface = screen->get_tex_surface(screen, + texture, + 0, + 0, + 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + + if (!surface) + goto err_surf; + + scrn->tex = texture; + scrn->surface = surface; + scrn->front.width = w; + scrn->front.height = h; + scrn->front.pitch = pitch; + dev->api->local_handle_from_texture(dev->api, screen, texture, + &scrn->front.pitch, &scrn->front.handle); + if (0) + goto err_handle; + + return; + +err_handle: + pipe_surface_reference(&surface, NULL); +err_surf: + pipe_texture_reference(&texture, NULL); +err_tex: + pipe_buffer_reference(&buf, NULL); + return; +} + +/* + * Exported functions + */ + +void +drm_takedown_shown_screen(_EGLDisplay *dpy, struct drm_screen *screen) +{ + struct drm_device *dev = lookup_drm_device(dpy); + + screen->surf = NULL; + + drmModeSetCrtc( + dev->drmFD, + screen->crtcID, + 0, // FD + 0, 0, + NULL, 0, // List of output ids + NULL); + + drmModeRmFB(dev->drmFD, screen->fbID); + drmModeFreeFB(screen->fb); + screen->fb = NULL; + + pipe_surface_reference(&screen->surface, NULL); + pipe_texture_reference(&screen->tex, NULL); + pipe_buffer_reference(&screen->buffer, NULL); + + screen->shown = 0; +} + +_EGLSurface * +drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativeWindowType window, const EGLint *attrib_list) +{ + return NULL; +} + + +_EGLSurface * +drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativePixmapType pixmap, const EGLint *attrib_list) +{ + return NULL; +} + + +_EGLSurface * +drm_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, + const EGLint *attrib_list) +{ + int i; + int width = -1; + int height = -1; + struct drm_surface *surf = NULL; + __GLcontextModes *visual; + + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { + switch (attrib_list[i]) { + case EGL_WIDTH: + width = attrib_list[++i]; + break; + case EGL_HEIGHT: + height = attrib_list[++i]; + break; + default: + _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface"); + return EGL_NO_SURFACE; + } + } + + if (width < 1 || height < 1) { + _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface"); + return NULL; + } + + surf = (struct drm_surface *) calloc(1, sizeof(struct drm_surface)); + if (!surf) + goto err; + + if (!_eglInitSurface(drv, &surf->base, EGL_PBUFFER_BIT, conf, attrib_list)) + goto err_surf; + + surf->w = width; + surf->h = height; + + visual = drm_visual_from_config(conf); + surf->stfb = drm_create_framebuffer(visual, + width, + height, + (void*)surf); + drm_visual_modes_destroy(visual); + + return &surf->base; + +err_surf: + free(surf); +err: + return NULL; +} + +_EGLSurface * +drm_create_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *cfg, + const EGLint *attrib_list) +{ + EGLSurface surf = drm_create_pbuffer_surface(drv, dpy, cfg, attrib_list); + + return surf; +} + +EGLBoolean +drm_show_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy, + _EGLScreen *screen, + _EGLSurface *surface, _EGLMode *mode) +{ + struct drm_device *dev = lookup_drm_device(dpy); + struct drm_surface *surf = lookup_drm_surface(surface); + struct drm_screen *scrn = lookup_drm_screen(screen); + int ret; + unsigned int i, k; + + if (scrn->shown) + drm_takedown_shown_screen(dpy, scrn); + + + drm_create_texture(dpy, scrn, mode->Width, mode->Height); + if (!scrn->buffer) + return EGL_FALSE; + + ret = drmModeAddFB(dev->drmFD, + scrn->front.width, scrn->front.height, + 32, 32, scrn->front.pitch, + scrn->front.handle, + &scrn->fbID); + + if (ret) + goto err_bo; + + scrn->fb = drmModeGetFB(dev->drmFD, scrn->fbID); + if (!scrn->fb) + goto err_bo; + + /* find a fitting crtc */ + { + drmModeConnector *con = scrn->connector; + + scrn->mode = drm_find_mode(con, mode); + if (!scrn->mode) + goto err_fb; + + for (k = 0; k < con->count_encoders; k++) { + drmModeEncoder *enc = drmModeGetEncoder(dev->drmFD, con->encoders[k]); + for (i = 0; i < dev->res->count_crtcs; i++) { + if (enc->possible_crtcs & (1<<i)) { + /* save the ID */ + scrn->crtcID = dev->res->crtcs[i]; + + /* skip the rest */ + i = dev->res->count_crtcs; + k = dev->res->count_encoders; + } + } + drmModeFreeEncoder(enc); + } + } + + ret = drmModeSetCrtc(dev->drmFD, + scrn->crtcID, + scrn->fbID, + 0, 0, + &scrn->connectorID, 1, + scrn->mode); + + if (ret) + goto err_crtc; + + + if (scrn->dpms) + drmModeConnectorSetProperty(dev->drmFD, + scrn->connectorID, + scrn->dpms->prop_id, + DRM_MODE_DPMS_ON); + + surf->screen = scrn; + + scrn->surf = surf; + scrn->shown = 1; + + return EGL_TRUE; + +err_crtc: + scrn->crtcID = 0; + +err_fb: + drmModeRmFB(dev->drmFD, scrn->fbID); + drmModeFreeFB(scrn->fb); + scrn->fb = NULL; + +err_bo: + pipe_surface_reference(&scrn->surface, NULL); + pipe_texture_reference(&scrn->tex, NULL); + pipe_buffer_reference(&scrn->buffer, NULL); + + return EGL_FALSE; +} + +EGLBoolean +drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface) +{ + struct drm_surface *surf = lookup_drm_surface(surface); + if (!_eglIsSurfaceBound(&surf->base)) { + if (surf->screen) + drm_takedown_shown_screen(dpy, surf->screen); + st_unreference_framebuffer(surf->stfb); + free(surf); + } + return EGL_TRUE; +} + +EGLBoolean +drm_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw) +{ + struct drm_device *dev = lookup_drm_device(dpy); + struct drm_surface *surf = lookup_drm_surface(draw); + struct pipe_surface *back_surf; + + if (!surf) + return EGL_FALSE; + + /* error checking */ + if (!_eglSwapBuffers(drv, dpy, draw)) + return EGL_FALSE; + + st_get_framebuffer_surface(surf->stfb, ST_SURFACE_BACK_LEFT, &back_surf); + + if (back_surf) { + + st_notify_swapbuffers(surf->stfb); + + if (surf->screen) { + surf->user->pipe->surface_copy(surf->user->pipe, + surf->screen->surface, + 0, 0, + back_surf, + 0, 0, + surf->w, surf->h); + surf->user->pipe->flush(surf->user->pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_TEXTURE_CACHE, NULL); + +#ifdef DRM_MODE_FEATURE_DIRTYFB + /* TODO query connector property to see if this is needed */ + drmModeDirtyFB(dev->drmFD, surf->screen->fbID, NULL, 0); +#else + (void)dev; +#endif + + /* TODO more stuff here */ + } + } + + return EGL_TRUE; +} diff --git a/src/gallium/state_trackers/egl/egl_tracker.c b/src/gallium/state_trackers/egl/egl_tracker.c new file mode 100644 index 0000000000..5140755001 --- /dev/null +++ b/src/gallium/state_trackers/egl/egl_tracker.c @@ -0,0 +1,271 @@ + +#include "utils.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "egl_tracker.h" + +#include <fcntl.h> + +#include "egllog.h" +#include "state_tracker/drm_api.h" + +#include "pipe/p_screen.h" +#include "pipe/internal/p_winsys_screen.h" + +/** HACK */ +void* driDriverAPI; +extern const struct dri_extension card_extensions[]; + + +/* + * Exported functions + */ + +static void +drm_unload(_EGLDriver *drv) +{ + free(drv); +} + +/** + * The bootstrap function. Return a new drm_driver object and + * plug in API functions. + */ +_EGLDriver * +_eglMain(const char *args) +{ + _EGLDriver *drv; + + drv = (_EGLDriver *) calloc(1, sizeof(_EGLDriver)); + if (!drv) { + return NULL; + } + + /* First fill in the dispatch table with defaults */ + _eglInitDriverFallbacks(drv); + /* then plug in our Drm-specific functions */ + drv->API.Initialize = drm_initialize; + drv->API.Terminate = drm_terminate; + drv->API.CreateContext = drm_create_context; + drv->API.MakeCurrent = drm_make_current; + drv->API.CreateWindowSurface = drm_create_window_surface; + drv->API.CreatePixmapSurface = drm_create_pixmap_surface; + drv->API.CreatePbufferSurface = drm_create_pbuffer_surface; + drv->API.DestroySurface = drm_destroy_surface; + drv->API.DestroyContext = drm_destroy_context; + drv->API.CreateScreenSurfaceMESA = drm_create_screen_surface_mesa; + drv->API.ShowScreenSurfaceMESA = drm_show_screen_surface_mesa; + drv->API.SwapBuffers = drm_swap_buffers; + + drv->Name = "DRM/Gallium/Win"; + drv->Unload = drm_unload; + + return drv; +} + +static void +drm_get_device_id(struct drm_device *device) +{ + char path[512]; + FILE *file; + char *ret; + + /* TODO get the real minor */ + int minor = 0; + + device->deviceID = 0; + + snprintf(path, sizeof(path), "/sys/class/drm/card%d/device/device", minor); + file = fopen(path, "r"); + if (!file) { + _eglLog(_EGL_WARNING, "Could not retrive device ID\n"); + return; + } + + ret = fgets(path, sizeof( path ), file); + if (!ret) + return; + + sscanf(path, "%x", &device->deviceID); + fclose(file); +} + +static void +drm_update_res(struct drm_device *dev) +{ + drmModeFreeResources(dev->res); + dev->res = drmModeGetResources(dev->drmFD); +} + +static void +drm_add_modes_from_connector(_EGLScreen *screen, drmModeConnectorPtr connector) +{ + drmModeModeInfoPtr m = NULL; + int i; + + for (i = 0; i < connector->count_modes; i++) { + m = &connector->modes[i]; + _eglAddNewMode(screen, m->hdisplay, m->vdisplay, m->vrefresh, m->name); + } +} + +static void +drm_find_dpms(struct drm_device *dev, struct drm_screen *screen) +{ + drmModeConnectorPtr c = screen->connector; + drmModePropertyPtr p; + int i; + + for (i = 0; i < c->count_props; i++) { + p = drmModeGetProperty(dev->drmFD, c->props[i]); + if (!strcmp(p->name, "DPMS")) + break; + + drmModeFreeProperty(p); + p = NULL; + } + + screen->dpms = p; +} + +static int drm_open_minor(int minor) +{ + char buf[64]; + + sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); + return open(buf, O_RDWR, 0); +} + +EGLBoolean +drm_initialize(_EGLDriver *drv, _EGLDisplay *disp, EGLint *major, EGLint *minor) +{ + struct drm_device *dev; + struct drm_screen *screen = NULL; + drmModeConnectorPtr connector = NULL; + drmModeResPtr res = NULL; + unsigned count_connectors = 0; + int num_screens = 0; + EGLint i; + int fd; + + dev = (struct drm_device *) calloc(1, sizeof(struct drm_device)); + if (!dev) + return EGL_FALSE; + dev->api = drm_api_create(); + + /* try the first node */ + fd = drm_open_minor(0); + if (fd < 0) + goto err_fd; + + dev->drmFD = fd; + drm_get_device_id(dev); + + dev->screen = dev->api->create_screen(dev->api, dev->drmFD, NULL); + if (!dev->screen) + goto err_screen; + dev->winsys = dev->screen->winsys; + + /* TODO HACK */ + driInitExtensions(NULL, card_extensions, GL_FALSE); + + drm_update_res(dev); + res = dev->res; + if (res) + count_connectors = res->count_connectors; + else + _eglLog(_EGL_WARNING, "Could not retrive kms information\n"); + + for(i = 0; i < count_connectors && i < MAX_SCREENS; i++) { + connector = drmModeGetConnector(fd, res->connectors[i]); + + if (!connector) + continue; + + if (connector->connection != DRM_MODE_CONNECTED) { + drmModeFreeConnector(connector); + continue; + } + + screen = malloc(sizeof(struct drm_screen)); + memset(screen, 0, sizeof(*screen)); + screen->connector = connector; + screen->connectorID = connector->connector_id; + _eglInitScreen(&screen->base); + _eglAddScreen(disp, &screen->base); + drm_add_modes_from_connector(&screen->base, connector); + drm_find_dpms(dev, screen); + dev->screens[num_screens++] = screen; + } + dev->count_screens = num_screens; + + disp->DriverData = dev; + + /* for now we only have one config */ + _EGLConfig *config = calloc(1, sizeof(*config)); + memset(config, 1, sizeof(*config)); + _eglInitConfig(config, 1); + _eglSetConfigAttrib(config, EGL_RED_SIZE, 8); + _eglSetConfigAttrib(config, EGL_GREEN_SIZE, 8); + _eglSetConfigAttrib(config, EGL_BLUE_SIZE, 8); + _eglSetConfigAttrib(config, EGL_ALPHA_SIZE, 8); + _eglSetConfigAttrib(config, EGL_BUFFER_SIZE, 32); + _eglSetConfigAttrib(config, EGL_DEPTH_SIZE, 24); + _eglSetConfigAttrib(config, EGL_STENCIL_SIZE, 8); + _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT); + _eglAddConfig(disp, config); + + disp->ClientAPIsMask = EGL_OPENGL_BIT /*| EGL_OPENGL_ES_BIT*/; + /* enable supported extensions */ + disp->Extensions.MESA_screen_surface = EGL_TRUE; + disp->Extensions.MESA_copy_context = EGL_TRUE; + + *major = 1; + *minor = 4; + + return EGL_TRUE; + +err_screen: + drmClose(fd); +err_fd: + free(dev); + return EGL_FALSE; +} + +EGLBoolean +drm_terminate(_EGLDriver *drv, _EGLDisplay *dpy) +{ + struct drm_device *dev = lookup_drm_device(dpy); + struct drm_screen *screen; + int i = 0; + + _eglReleaseDisplayResources(drv, dpy); + _eglCleanupDisplay(dpy); + + drmFreeVersion(dev->version); + + for (i = 0; i < dev->count_screens; i++) { + screen = dev->screens[i]; + + if (screen->shown) + drm_takedown_shown_screen(dpy, screen); + + drmModeFreeProperty(screen->dpms); + drmModeFreeConnector(screen->connector); + _eglDestroyScreen(&screen->base); + dev->screens[i] = NULL; + } + + dev->screen->destroy(dev->screen); + dev->winsys = NULL; + + drmClose(dev->drmFD); + + dev->api->destroy(dev->api); + free(dev); + dpy->DriverData = NULL; + + return EGL_TRUE; +} diff --git a/src/gallium/state_trackers/egl/egl_tracker.h b/src/gallium/state_trackers/egl/egl_tracker.h new file mode 100644 index 0000000000..dd4730f957 --- /dev/null +++ b/src/gallium/state_trackers/egl/egl_tracker.h @@ -0,0 +1,197 @@ + +#ifndef _EGL_TRACKER_H_ +#define _EGL_TRACKER_H_ + +#include <stdint.h> + +#include "eglconfig.h" +#include "eglcontext.h" +#include "egldisplay.h" +#include "egldriver.h" +#include "eglglobals.h" +#include "eglmode.h" +#include "eglscreen.h" +#include "eglsurface.h" + +#include "xf86drm.h" +#include "xf86drmMode.h" + +#include "pipe/p_compiler.h" + +#include "state_tracker/st_public.h" + +#define MAX_SCREENS 16 + +struct pipe_winsys; +struct pipe_screen; +struct pipe_context; +struct state_tracker; + +struct drm_screen; +struct drm_context; + +struct drm_device +{ + /* + * pipe + */ + + struct drm_api *api; + struct pipe_winsys *winsys; + struct pipe_screen *screen; + + /* + * drm + */ + + int drmFD; + drmVersionPtr version; + int deviceID; + + drmModeResPtr res; + + struct drm_screen *screens[MAX_SCREENS]; + size_t count_screens; +}; + +struct drm_surface +{ + _EGLSurface base; /* base class/object */ + + /* + * pipe + */ + + + struct st_framebuffer *stfb; + + /* + * drm + */ + + struct drm_context *user; + struct drm_screen *screen; + + int w; + int h; +}; + +struct drm_context +{ + _EGLContext base; /* base class/object */ + + /* pipe */ + + struct pipe_context *pipe; + struct st_context *st; +}; + +struct drm_screen +{ + _EGLScreen base; + + /* + * pipe + */ + + struct pipe_buffer *buffer; + struct pipe_texture *tex; + struct pipe_surface *surface; + + /* + * drm + */ + + struct { + unsigned height; + unsigned width; + unsigned pitch; + unsigned handle; + } front; + + /* currently only support one connector */ + drmModeConnectorPtr connector; + uint32_t connectorID; + + /* dpms property */ + drmModePropertyPtr dpms; + + /* Has this screen been shown */ + int shown; + + /* Surface that is currently attached to this screen */ + struct drm_surface *surf; + + /* framebuffer */ + drmModeFBPtr fb; + uint32_t fbID; + + /* crtc and mode used */ + /*drmModeCrtcPtr crtc;*/ + uint32_t crtcID; + + drmModeModeInfoPtr mode; +}; + + +static INLINE struct drm_device * +lookup_drm_device(_EGLDisplay *d) +{ + return (struct drm_device *) d->DriverData; +} + + +static INLINE struct drm_context * +lookup_drm_context(_EGLContext *c) +{ + return (struct drm_context *) c; +} + + +static INLINE struct drm_surface * +lookup_drm_surface(_EGLSurface *s) +{ + return (struct drm_surface *) s; +} + +static INLINE struct drm_screen * +lookup_drm_screen(_EGLScreen *s) +{ + return (struct drm_screen *) s; +} + +/** + * egl_visual.h + */ +/*@{*/ +void drm_visual_modes_destroy(__GLcontextModes *modes); +__GLcontextModes* drm_visual_modes_create(unsigned count, size_t minimum_size); +__GLcontextModes* drm_visual_from_config(_EGLConfig *conf); +/*@}*/ + +/** + * egl_surface.h + */ +/*@{*/ +void drm_takedown_shown_screen(_EGLDisplay *dpy, struct drm_screen *screen); +/*@}*/ + +/** + * All function exported to the egl side. + */ +/*@{*/ +EGLBoolean drm_initialize(_EGLDriver *drv, _EGLDisplay *dpy, EGLint *major, EGLint *minor); +EGLBoolean drm_terminate(_EGLDriver *drv, _EGLDisplay *dpy); +_EGLContext *drm_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, _EGLContext *share_list, const EGLint *attrib_list); +EGLBoolean drm_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *context); +_EGLSurface *drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativeWindowType window, const EGLint *attrib_list); +_EGLSurface *drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativePixmapType pixmap, const EGLint *attrib_list); +_EGLSurface *drm_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, const EGLint *attrib_list); +_EGLSurface *drm_create_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, const EGLint *attrib_list); +EGLBoolean drm_show_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *screen, _EGLSurface *surface, _EGLMode *mode); +EGLBoolean drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface); +EGLBoolean drm_make_current(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw, _EGLSurface *read, _EGLContext *context); +EGLBoolean drm_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw); +/*@}*/ + +#endif diff --git a/src/gallium/state_trackers/egl/egl_visual.c b/src/gallium/state_trackers/egl/egl_visual.c new file mode 100644 index 0000000000..e59f893851 --- /dev/null +++ b/src/gallium/state_trackers/egl/egl_visual.c @@ -0,0 +1,85 @@ + +#include "egl_tracker.h" + +#include "egllog.h" + +void +drm_visual_modes_destroy(__GLcontextModes *modes) +{ + _eglLog(_EGL_DEBUG, "%s", __FUNCTION__); + + while (modes) { + __GLcontextModes * const next = modes->next; + free(modes); + modes = next; + } +} + +__GLcontextModes * +drm_visual_modes_create(unsigned count, size_t minimum_size) +{ + /* This code copied from libGLX, and modified */ + const size_t size = (minimum_size > sizeof(__GLcontextModes)) + ? minimum_size : sizeof(__GLcontextModes); + __GLcontextModes * head = NULL; + __GLcontextModes ** next; + unsigned i; + + _eglLog(_EGL_DEBUG, "%s %d %d", __FUNCTION__, count, minimum_size); + + next = & head; + for (i = 0 ; i < count ; i++) { + *next = (__GLcontextModes *) calloc(1, size); + if (*next == NULL) { + drm_visual_modes_destroy(head); + head = NULL; + break; + } + + (*next)->doubleBufferMode = 1; + (*next)->visualID = GLX_DONT_CARE; + (*next)->visualType = GLX_DONT_CARE; + (*next)->visualRating = GLX_NONE; + (*next)->transparentPixel = GLX_NONE; + (*next)->transparentRed = GLX_DONT_CARE; + (*next)->transparentGreen = GLX_DONT_CARE; + (*next)->transparentBlue = GLX_DONT_CARE; + (*next)->transparentAlpha = GLX_DONT_CARE; + (*next)->transparentIndex = GLX_DONT_CARE; + (*next)->xRenderable = GLX_DONT_CARE; + (*next)->fbconfigID = GLX_DONT_CARE; + (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML; + (*next)->bindToTextureRgb = GLX_DONT_CARE; + (*next)->bindToTextureRgba = GLX_DONT_CARE; + (*next)->bindToMipmapTexture = GLX_DONT_CARE; + (*next)->bindToTextureTargets = 0; + (*next)->yInverted = GLX_DONT_CARE; + + next = & ((*next)->next); + } + + return head; +} + +__GLcontextModes * +drm_visual_from_config(_EGLConfig *conf) +{ + __GLcontextModes *visual; + (void)conf; + + visual = drm_visual_modes_create(1, sizeof(*visual)); + visual->redBits = 8; + visual->greenBits = 8; + visual->blueBits = 8; + visual->alphaBits = 8; + + visual->rgbBits = 32; + visual->doubleBufferMode = 1; + + visual->depthBits = 24; + visual->haveDepthBuffer = visual->depthBits > 0; + visual->stencilBits = 8; + visual->haveStencilBuffer = visual->stencilBits > 0; + + return visual; +} diff --git a/src/gallium/state_trackers/es/Makefile b/src/gallium/state_trackers/es/Makefile new file mode 100644 index 0000000000..1ffabf339a --- /dev/null +++ b/src/gallium/state_trackers/es/Makefile @@ -0,0 +1,100 @@ +# src/gallium/state_trackers/es/Makefile + +# Build the ES 1/2 state tracker libraries +# This consists of core Mesa ES, plus GL/gallium state tracker. + +TOP = ../../../.. +include $(TOP)/configs/current + +GLES_1_VERSION_MAJOR = 1 +GLES_1_VERSION_MINOR = 1 +GLES_1_VERSION_PATCH = 0 + +GLES_2_VERSION_MAJOR = 2 +GLES_2_VERSION_MINOR = 0 +GLES_2_VERSION_PATCH = 0 + + +# Maybe move these into configs/default: +GLES_1_LIB = GLESv1_CM +GLES_1_LIB_NAME = lib$(GLES_1_LIB).so +GLES_2_LIB = GLESv2 +GLES_2_LIB_NAME = lib$(GLES_2_LIB).so + + +INCLUDE_DIRS = \ + -I$(TOP)/src/mesa \ + -I$(TOP)/include + +ES1_SOURCES = \ + st_es1.c \ + +ES1_OBJECTS = $(ES1_SOURCES:.c=.o) + +ES2_SOURCES = \ + st_es2.c \ + +ES2_OBJECTS = $(ES2_SOURCES:.c=.o) + + +# we only need the gallium libs that the state trackers directly use: +GALLIUM_LIBS = \ + $(TOP)/src/gallium/auxiliary/cso_cache/libcso_cache.a \ + $(TOP)/src/gallium/auxiliary/rtasm/librtasm.a \ + $(TOP)/src/gallium/auxiliary/tgsi/libtgsi.a \ + $(TOP)/src/gallium/auxiliary/util/libutil.a + +ES1_LIBS = \ + $(TOP)/src/mesa/es/libes1gallium.a \ + $(TOP)/src/mesa/es/libes1api.a + +ES2_LIBS = \ + $(TOP)/src/mesa/es/libes2gallium.a \ + $(TOP)/src/mesa/es/libes2api.a + +SYS_LIBS = -lm -pthread + + +.c.o: + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@ + + +# Default: make both GL ES 1.1 and GL ES 2.0 libraries +default: $(TOP)/$(LIB_DIR)/$(GLES_1_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLES_2_LIB_NAME) + +# Make the shared libs +$(TOP)/$(LIB_DIR)/$(GLES_1_LIB_NAME): $(ES1_OBJECTS) $(ES1_LIBS) + $(TOP)/bin/mklib -o $(GLES_1_LIB) \ + -major $(GLES_1_VERSION_MAJOR) \ + -minor $(GLES_1_VERSION_MINOR) \ + -patch $(GLES_1_VERSION_PATCH) \ + -install $(TOP)/$(LIB_DIR) \ + $(ES1_OBJECTS) \ + -Wl,--whole-archive $(ES1_LIBS) -Wl,--no-whole-archive \ + -Wl,--start-group $(GALLIUM_LIBS) -Wl,--end-group \ + $(SYS_LIBS) + +$(TOP)/$(LIB_DIR)/$(GLES_2_LIB_NAME): $(ES2_OBJECTS) $(ES1_LIBS) + $(TOP)/bin/mklib -o $(GLES_2_LIB) \ + -major $(GLES_2_VERSION_MAJOR) \ + -minor $(GLES_2_VERSION_MINOR) \ + -patch $(GLES_2_VERSION_PATCH) \ + -install $(TOP)/$(LIB_DIR) \ + $(ES2_OBJECTS) \ + -Wl,--whole-archive $(ES2_LIBS) -Wl,--no-whole-archive \ + -Wl,--start-group $(GALLIUM_LIBS) -Wl,--end-group \ + $(SYS_LIBS) + +install: default + $(INSTALL) -d $(INSTALL_DIR)/include/GLES + $(INSTALL) -m 644 $(TOP)/include/GLES/*.h $(INSTALL_DIR)/include/GLES + $(INSTALL) -d $(INSTALL_DIR)/include/GLES2 + $(INSTALL) -m 644 $(TOP)/include/GLES2/*.h $(INSTALL_DIR)/include/GLES2 + $(INSTALL) -d $(INSTALL_DIR)/$(LIB_DIR) + $(INSTALL) $(TOP)/$(LIB_DIR)/libGLESv1* $(INSTALL_DIR)/$(LIB_DIR) + $(INSTALL) $(TOP)/$(LIB_DIR)/libGLESv2* $(INSTALL_DIR)/$(LIB_DIR) + +clean: + -rm -f *.o *~ + -rm -f $(TOP)/$(LIB_DIR)/$(GLES_1_LIB_NAME)* $(TOP)/$(LIB_DIR)/$(GLES_2_LIB_NAME)* + -rm -f *.pyc diff --git a/src/gallium/state_trackers/es/st_es1.c b/src/gallium/state_trackers/es/st_es1.c new file mode 100644 index 0000000000..7f0c038957 --- /dev/null +++ b/src/gallium/state_trackers/es/st_es1.c @@ -0,0 +1 @@ +const int st_api_OpenGL_ES1 = 1; diff --git a/src/gallium/state_trackers/es/st_es2.c b/src/gallium/state_trackers/es/st_es2.c new file mode 100644 index 0000000000..78e3791fbe --- /dev/null +++ b/src/gallium/state_trackers/es/st_es2.c @@ -0,0 +1 @@ +const int st_api_OpenGL_ES2 = 1; diff --git a/src/gallium/state_trackers/g3dvl/Makefile b/src/gallium/state_trackers/g3dvl/Makefile new file mode 100644 index 0000000000..f9f4d6be3c --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/Makefile @@ -0,0 +1,21 @@ +TARGET = libg3dvl.a +OBJECTS = vl_display.o vl_screen.o vl_context.o vl_surface.o vl_shader_build.o vl_util.o vl_basic_csc.o \ + vl_r16snorm_mc_buf.o +GALLIUMDIR = ../.. + +CFLAGS += -g -Wall -Werror-implicit-function-declaration -fPIC \ + -I${GALLIUMDIR}/include \ + -I${GALLIUMDIR}/auxiliary \ + -I${GALLIUMDIR}/winsys/g3dvl \ + +############################################# + +.PHONY = all clean + +all: ${TARGET} + +${TARGET}: ${OBJECTS} + ar rcs $@ $^ + +clean: + rm -rf ${OBJECTS} ${TARGET} diff --git a/src/gallium/state_trackers/g3dvl/vl_basic_csc.c b/src/gallium/state_trackers/g3dvl/vl_basic_csc.c new file mode 100644 index 0000000000..20d682de3f --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_basic_csc.c @@ -0,0 +1,714 @@ +#define VL_INTERNAL +#include "vl_basic_csc.h" +#include <assert.h> +#include <pipe/p_context.h> +#include <pipe/p_state.h> +#include <pipe/p_inlines.h> +#include <tgsi/tgsi_parse.h> +#include <tgsi/tgsi_build.h> +#include <util/u_memory.h> +#include "vl_csc.h" +#include "vl_surface.h" +#include "vl_shader_build.h" +#include "vl_types.h" + +struct vlVertexShaderConsts +{ + struct vlVertex4f dst_scale; + struct vlVertex4f dst_trans; + struct vlVertex4f src_scale; + struct vlVertex4f src_trans; +}; + +struct vlFragmentShaderConsts +{ + struct vlVertex4f bias; + float matrix[16]; +}; + +struct vlBasicCSC +{ + struct vlCSC base; + + struct pipe_context *pipe; + struct pipe_viewport_state viewport; + struct pipe_framebuffer_state framebuffer; + struct pipe_texture *framebuffer_tex; + void *sampler; + void *vertex_shader, *fragment_shader; + struct pipe_vertex_buffer vertex_bufs[2]; + struct pipe_vertex_element vertex_elems[2]; + struct pipe_constant_buffer vs_const_buf, fs_const_buf; +}; + +static int vlResizeFrameBuffer +( + struct vlCSC *csc, + unsigned int width, + unsigned int height +) +{ + struct vlBasicCSC *basic_csc; + struct pipe_context *pipe; + struct pipe_texture template; + + assert(csc); + + basic_csc = (struct vlBasicCSC*)csc; + pipe = basic_csc->pipe; + + if (basic_csc->framebuffer.width == width && basic_csc->framebuffer.height == height) + return 0; + + basic_csc->viewport.scale[0] = width; + basic_csc->viewport.scale[1] = height; + basic_csc->viewport.scale[2] = 1; + basic_csc->viewport.scale[3] = 1; + basic_csc->viewport.translate[0] = 0; + basic_csc->viewport.translate[1] = 0; + basic_csc->viewport.translate[2] = 0; + basic_csc->viewport.translate[3] = 0; + + if (basic_csc->framebuffer_tex) + { + pipe_surface_reference(&basic_csc->framebuffer.cbufs[0], NULL); + pipe_texture_reference(&basic_csc->framebuffer_tex, NULL); + } + + memset(&template, 0, sizeof(struct pipe_texture)); + template.target = PIPE_TEXTURE_2D; + template.format = PIPE_FORMAT_A8R8G8B8_UNORM; + template.last_level = 0; + template.width[0] = width; + template.height[0] = height; + template.depth[0] = 1; + pf_get_block(template.format, &template.block); + template.tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET; + + basic_csc->framebuffer_tex = pipe->screen->texture_create(pipe->screen, &template); + + basic_csc->framebuffer.width = width; + basic_csc->framebuffer.height = height; + basic_csc->framebuffer.cbufs[0] = pipe->screen->get_tex_surface + ( + pipe->screen, + basic_csc->framebuffer_tex, + 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE + ); + + /* Clear to black, in case video doesn't fill the entire window */ + pipe->set_framebuffer_state(pipe, &basic_csc->framebuffer); + pipe->clear(pipe, PIPE_CLEAR_COLOR, 0, 0.0f, 0); + + return 0; +} + +static int vlBegin +( + struct vlCSC *csc +) +{ + struct vlBasicCSC *basic_csc; + struct pipe_context *pipe; + + assert(csc); + + basic_csc = (struct vlBasicCSC*)csc; + pipe = basic_csc->pipe; + + pipe->set_framebuffer_state(pipe, &basic_csc->framebuffer); + pipe->set_viewport_state(pipe, &basic_csc->viewport); + pipe->bind_sampler_states(pipe, 1, (void**)&basic_csc->sampler); + /* Source texture set in vlPutPictureCSC() */ + pipe->bind_vs_state(pipe, basic_csc->vertex_shader); + pipe->bind_fs_state(pipe, basic_csc->fragment_shader); + pipe->set_vertex_buffers(pipe, 2, basic_csc->vertex_bufs); + pipe->set_vertex_elements(pipe, 2, basic_csc->vertex_elems); + pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &basic_csc->vs_const_buf); + pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &basic_csc->fs_const_buf); + + return 0; +} + +static int vlPutPictureCSC +( + struct vlCSC *csc, + struct vlSurface *surface, + int srcx, + int srcy, + int srcw, + int srch, + int destx, + int desty, + int destw, + int desth, + enum vlPictureType picture_type +) +{ + struct vlBasicCSC *basic_csc; + struct pipe_context *pipe; + struct vlVertexShaderConsts *vs_consts; + + assert(csc); + assert(surface); + + basic_csc = (struct vlBasicCSC*)csc; + pipe = basic_csc->pipe; + + vs_consts = pipe_buffer_map + ( + pipe->screen, + basic_csc->vs_const_buf.buffer, + PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_DISCARD + ); + + vs_consts->dst_scale.x = destw / (float)basic_csc->framebuffer.cbufs[0]->width; + vs_consts->dst_scale.y = desth / (float)basic_csc->framebuffer.cbufs[0]->height; + vs_consts->dst_scale.z = 1; + vs_consts->dst_scale.w = 1; + vs_consts->dst_trans.x = destx / (float)basic_csc->framebuffer.cbufs[0]->width; + vs_consts->dst_trans.y = desty / (float)basic_csc->framebuffer.cbufs[0]->height; + vs_consts->dst_trans.z = 0; + vs_consts->dst_trans.w = 0; + + vs_consts->src_scale.x = srcw / (float)surface->texture->width[0]; + vs_consts->src_scale.y = srch / (float)surface->texture->height[0]; + vs_consts->src_scale.z = 1; + vs_consts->src_scale.w = 1; + vs_consts->src_trans.x = srcx / (float)surface->texture->width[0]; + vs_consts->src_trans.y = srcy / (float)surface->texture->height[0]; + vs_consts->src_trans.z = 0; + vs_consts->src_trans.w = 0; + + pipe_buffer_unmap(pipe->screen, basic_csc->vs_const_buf.buffer); + + pipe->set_sampler_textures(pipe, 1, &surface->texture); + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLE_STRIP, 0, 4); + + return 0; +} + +static int vlEnd +( + struct vlCSC *csc +) +{ + assert(csc); + + return 0; +} + +static struct pipe_surface* vlGetFrameBuffer +( + struct vlCSC *csc +) +{ + struct vlBasicCSC *basic_csc; + + assert(csc); + + basic_csc = (struct vlBasicCSC*)csc; + + return basic_csc->framebuffer.cbufs[0]; +} + +static int vlDestroy +( + struct vlCSC *csc +) +{ + struct vlBasicCSC *basic_csc; + struct pipe_context *pipe; + unsigned int i; + + assert(csc); + + basic_csc = (struct vlBasicCSC*)csc; + pipe = basic_csc->pipe; + + if (basic_csc->framebuffer_tex) + { + pipe_surface_reference(&basic_csc->framebuffer.cbufs[0], NULL); + pipe_texture_reference(&basic_csc->framebuffer_tex, NULL); + } + + pipe->delete_sampler_state(pipe, basic_csc->sampler); + pipe->delete_vs_state(pipe, basic_csc->vertex_shader); + pipe->delete_fs_state(pipe, basic_csc->fragment_shader); + + for (i = 0; i < 2; ++i) + pipe_buffer_reference(&basic_csc->vertex_bufs[i].buffer, NULL); + + pipe_buffer_reference(&basic_csc->vs_const_buf.buffer, NULL); + pipe_buffer_reference(&basic_csc->fs_const_buf.buffer, NULL); + + FREE(basic_csc); + + return 0; +} + +/* + * Represents 2 triangles in a strip in normalized coords. + * Used to render the surface onto the frame buffer. + */ +static const struct vlVertex2f surface_verts[4] = +{ + {0.0f, 0.0f}, + {0.0f, 1.0f}, + {1.0f, 0.0f}, + {1.0f, 1.0f} +}; + +/* + * Represents texcoords for the above. We can use the position values directly. + * TODO: Duplicate these in the shader, no need to create a buffer. + */ +static const struct vlVertex2f *surface_texcoords = surface_verts; + +/* + * Identity color conversion constants, for debugging + */ +static const struct vlFragmentShaderConsts identity = +{ + { + 0.0f, 0.0f, 0.0f, 0.0f + }, + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + } +}; + +/* + * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [16,235] + */ +static const struct vlFragmentShaderConsts bt_601 = +{ + { + 0.0f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 1.0f, 0.0f, 1.371f, 0.0f, + 1.0f, -0.336f, -0.698f, 0.0f, + 1.0f, 1.732f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + } +}; + +/* + * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [0,255] + */ +static const struct vlFragmentShaderConsts bt_601_full = +{ + { + 0.062745098f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 1.164f, 0.0f, 1.596f, 0.0f, + 1.164f, -0.391f, -0.813f, 0.0f, + 1.164f, 2.018f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + } +}; + +/* + * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [16,235] + */ +static const struct vlFragmentShaderConsts bt_709 = +{ + { + 0.0f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 1.0f, 0.0f, 1.540f, 0.0f, + 1.0f, -0.183f, -0.459f, 0.0f, + 1.0f, 1.816f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + } +}; + +/* + * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where: + * Y is in [16,235], Cb and Cr are in [16,240] + * R, G, and B are in [0,255] + */ +const struct vlFragmentShaderConsts bt_709_full = +{ + { + 0.062745098f, 0.501960784f, 0.501960784f, 0.0f + }, + { + 1.164f, 0.0f, 1.793f, 0.0f, + 1.164f, -0.213f, -0.534f, 0.0f, + 1.164f, 2.115f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + } +}; + +static int vlCreateVertexShader +( + struct vlBasicCSC *csc +) +{ + const unsigned int max_tokens = 50; + + struct pipe_context *pipe; + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(csc); + + pipe = csc->pipe; + tokens = (struct tgsi_token*)MALLOC(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_VERTEX, header); + + ti = 3; + + /* + * decl i0 ; Vertex pos + * decl i1 ; Vertex texcoords + */ + for (i = 0; i < 2; i++) + { + decl = vl_decl_input(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * decl c0 ; Scaling vector to scale vertex pos rect to destination size + * decl c1 ; Translation vector to move vertex pos rect into position + * decl c2 ; Scaling vector to scale texcoord rect to source size + * decl c3 ; Translation vector to move texcoord rect into position + */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 3); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl o0 ; Vertex pos + * decl o1 ; Vertex texcoords + */ + for (i = 0; i < 2; i++) + { + decl = vl_decl_output(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* decl t0, t1 */ + decl = vl_decl_temps(0, 1); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * madd o0, i0, c0, c1 ; Scale and translate unit output rect to destination size and pos + * madd o1, i1, c2, c3 ; Scale and translate unit texcoord rect to source size and pos + */ + for (i = 0; i < 2; ++i) + { + inst = vl_inst4(TGSI_OPCODE_MADD, TGSI_FILE_OUTPUT, i, TGSI_FILE_INPUT, i, TGSI_FILE_CONSTANT, i * 2, TGSI_FILE_CONSTANT, i * 2 + 1); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + vs.tokens = tokens; + csc->vertex_shader = pipe->create_vs_state(pipe, &vs); + FREE(tokens); + + return 0; +} + +static int vlCreateFragmentShader +( + struct vlBasicCSC *csc +) +{ + const unsigned int max_tokens = 50; + + struct pipe_context *pipe; + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(csc); + + pipe = csc->pipe; + tokens = (struct tgsi_token*)MALLOC(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_FRAGMENT, header); + + ti = 3; + + /* decl i0 ; Texcoords for s0 */ + decl = vl_decl_interpolated_input(TGSI_SEMANTIC_GENERIC, 1, 0, 0, TGSI_INTERPOLATE_LINEAR); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl c0 ; Bias vector for CSC + * decl c1-c4 ; CSC matrix c1-c4 + */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 4); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl o0 ; Fragment color */ + decl = vl_decl_output(TGSI_SEMANTIC_COLOR, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl t0 */ + decl = vl_decl_temps(0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl s0 ; Sampler for tex containing picture to display */ + decl = vl_decl_samplers(0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* tex2d t0, i0, s0 ; Read src pixel */ + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_INPUT, 0, TGSI_FILE_SAMPLER, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* sub t0, t0, c0 ; Subtract bias vector from pixel */ + inst = vl_inst3(TGSI_OPCODE_SUB, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* + * dp4 o0.x, t0, c1 ; Multiply pixel by the color conversion matrix + * dp4 o0.y, t0, c2 + * dp4 o0.z, t0, c3 + */ + for (i = 0; i < 3; ++i) + { + inst = vl_inst3(TGSI_OPCODE_DP4, TGSI_FILE_OUTPUT, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, i + 1); + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + fs.tokens = tokens; + csc->fragment_shader = pipe->create_fs_state(pipe, &fs); + FREE(tokens); + + return 0; +} + +static int vlCreateDataBufs +( + struct vlBasicCSC *csc +) +{ + struct pipe_context *pipe; + + assert(csc); + + pipe = csc->pipe; + + /* + * Create our vertex buffer and vertex buffer element + * VB contains 4 vertices that render a quad covering the entire window + * to display a rendered surface + * Quad is rendered as a tri strip + */ + csc->vertex_bufs[0].stride = sizeof(struct vlVertex2f); + csc->vertex_bufs[0].max_index = 3; + csc->vertex_bufs[0].buffer_offset = 0; + csc->vertex_bufs[0].buffer = pipe_buffer_create + ( + pipe->screen, + 1, + PIPE_BUFFER_USAGE_VERTEX, + sizeof(struct vlVertex2f) * 4 + ); + + memcpy + ( + pipe_buffer_map(pipe->screen, csc->vertex_bufs[0].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + surface_verts, + sizeof(struct vlVertex2f) * 4 + ); + + pipe_buffer_unmap(pipe->screen, csc->vertex_bufs[0].buffer); + + csc->vertex_elems[0].src_offset = 0; + csc->vertex_elems[0].vertex_buffer_index = 0; + csc->vertex_elems[0].nr_components = 2; + csc->vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* + * Create our texcoord buffer and texcoord buffer element + * Texcoord buffer contains the TCs for mapping the rendered surface to the 4 vertices + */ + csc->vertex_bufs[1].stride = sizeof(struct vlVertex2f); + csc->vertex_bufs[1].max_index = 3; + csc->vertex_bufs[1].buffer_offset = 0; + csc->vertex_bufs[1].buffer = pipe_buffer_create + ( + pipe->screen, + 1, + PIPE_BUFFER_USAGE_VERTEX, + sizeof(struct vlVertex2f) * 4 + ); + + memcpy + ( + pipe_buffer_map(pipe->screen, csc->vertex_bufs[1].buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + surface_texcoords, + sizeof(struct vlVertex2f) * 4 + ); + + pipe_buffer_unmap(pipe->screen, csc->vertex_bufs[1].buffer); + + csc->vertex_elems[1].src_offset = 0; + csc->vertex_elems[1].vertex_buffer_index = 1; + csc->vertex_elems[1].nr_components = 2; + csc->vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* + * Create our vertex shader's constant buffer + * Const buffer contains scaling and translation vectors + */ + csc->vs_const_buf.buffer = pipe_buffer_create + ( + pipe->screen, + 1, + PIPE_BUFFER_USAGE_CONSTANT | PIPE_BUFFER_USAGE_DISCARD, + sizeof(struct vlVertexShaderConsts) + ); + + /* + * Create our fragment shader's constant buffer + * Const buffer contains the color conversion matrix and bias vectors + */ + csc->fs_const_buf.buffer = pipe_buffer_create + ( + pipe->screen, + 1, + PIPE_BUFFER_USAGE_CONSTANT, + sizeof(struct vlFragmentShaderConsts) + ); + + /* + * TODO: Refactor this into a seperate function, + * allow changing the CSC matrix at runtime to switch between regular & full versions + */ + memcpy + ( + pipe_buffer_map(pipe->screen, csc->fs_const_buf.buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + &bt_601_full, + sizeof(struct vlFragmentShaderConsts) + ); + + pipe_buffer_unmap(pipe->screen, csc->fs_const_buf.buffer); + + return 0; +} + +static int vlInit +( + struct vlBasicCSC *csc +) +{ + struct pipe_context *pipe; + struct pipe_sampler_state sampler; + + assert(csc); + + pipe = csc->pipe; + + /* Delay creating the FB until vlPutPictureCSC() so we know window size */ + csc->framebuffer_tex = NULL; + csc->framebuffer.width = 0; + csc->framebuffer.height = 0; + csc->framebuffer.nr_cbufs = 1; + csc->framebuffer.cbufs[0] = NULL; + csc->framebuffer.zsbuf = NULL; + + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; + sampler.compare_mode = PIPE_TEX_COMPARE_NONE; + sampler.compare_func = PIPE_FUNC_ALWAYS; + sampler.normalized_coords = 1; + /*sampler.prefilter = ;*/ + /*sampler.lod_bias = ;*/ + /*sampler.min_lod = ;*/ + /*sampler.max_lod = ;*/ + /*sampler.border_color[i] = ;*/ + /*sampler.max_anisotropy = ;*/ + csc->sampler = pipe->create_sampler_state(pipe, &sampler); + + vlCreateVertexShader(csc); + vlCreateFragmentShader(csc); + vlCreateDataBufs(csc); + + return 0; +} + +int vlCreateBasicCSC +( + struct pipe_context *pipe, + struct vlCSC **csc +) +{ + struct vlBasicCSC *basic_csc; + + assert(pipe); + assert(csc); + + basic_csc = CALLOC_STRUCT(vlBasicCSC); + + if (!basic_csc) + return 1; + + basic_csc->base.vlResizeFrameBuffer = &vlResizeFrameBuffer; + basic_csc->base.vlBegin = &vlBegin; + basic_csc->base.vlPutPicture = &vlPutPictureCSC; + basic_csc->base.vlEnd = &vlEnd; + basic_csc->base.vlGetFrameBuffer = &vlGetFrameBuffer; + basic_csc->base.vlDestroy = &vlDestroy; + basic_csc->pipe = pipe; + + vlInit(basic_csc); + + *csc = &basic_csc->base; + + return 0; +} diff --git a/src/gallium/state_trackers/g3dvl/vl_basic_csc.h b/src/gallium/state_trackers/g3dvl/vl_basic_csc.h new file mode 100644 index 0000000000..2e17f1d814 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_basic_csc.h @@ -0,0 +1,13 @@ +#ifndef vl_basic_csc_h +#define vl_basic_csc_h + +struct pipe_context; +struct vlCSC; + +int vlCreateBasicCSC +( + struct pipe_context *pipe, + struct vlCSC **csc +); + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_context.c b/src/gallium/state_trackers/g3dvl/vl_context.c new file mode 100644 index 0000000000..5cfd233c4c --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_context.c @@ -0,0 +1,205 @@ +#define VL_INTERNAL +#include "vl_context.h" +#include <assert.h> +#include <pipe/p_context.h> +#include <pipe/p_state.h> +#include <util/u_memory.h> +#include "vl_render.h" +#include "vl_r16snorm_mc_buf.h" +#include "vl_csc.h" +#include "vl_basic_csc.h" + +static int vlInitCommon(struct vlContext *context) +{ + struct pipe_context *pipe; + struct pipe_rasterizer_state rast; + struct pipe_blend_state blend; + struct pipe_depth_stencil_alpha_state dsa; + unsigned int i; + + assert(context); + + pipe = context->pipe; + + rast.flatshade = 1; + rast.flatshade_first = 0; + rast.light_twoside = 0; + rast.front_winding = PIPE_WINDING_CCW; + rast.cull_mode = PIPE_WINDING_CW; + rast.fill_cw = PIPE_POLYGON_MODE_FILL; + rast.fill_ccw = PIPE_POLYGON_MODE_FILL; + rast.offset_cw = 0; + rast.offset_ccw = 0; + rast.scissor = 0; + rast.poly_smooth = 0; + rast.poly_stipple_enable = 0; + rast.point_sprite = 0; + rast.point_size_per_vertex = 0; + rast.multisample = 0; + rast.line_smooth = 0; + rast.line_stipple_enable = 0; + rast.line_stipple_factor = 0; + rast.line_stipple_pattern = 0; + rast.line_last_pixel = 0; + rast.bypass_vs_clip_and_viewport = 0; + rast.line_width = 1; + rast.point_smooth = 0; + rast.point_size = 1; + rast.offset_units = 1; + rast.offset_scale = 1; + /*rast.sprite_coord_mode[i] = ;*/ + context->raster = pipe->create_rasterizer_state(pipe, &rast); + pipe->bind_rasterizer_state(pipe, context->raster); + + blend.blend_enable = 0; + blend.rgb_func = PIPE_BLEND_ADD; + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_func = PIPE_BLEND_ADD; + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + blend.logicop_enable = 0; + blend.logicop_func = PIPE_LOGICOP_CLEAR; + /* Needed to allow color writes to FB, even if blending disabled */ + blend.colormask = PIPE_MASK_RGBA; + blend.dither = 0; + context->blend = pipe->create_blend_state(pipe, &blend); + pipe->bind_blend_state(pipe, context->blend); + + dsa.depth.enabled = 0; + dsa.depth.writemask = 0; + dsa.depth.func = PIPE_FUNC_ALWAYS; + dsa.depth.occlusion_count = 0; + for (i = 0; i < 2; ++i) + { + dsa.stencil[i].enabled = 0; + dsa.stencil[i].func = PIPE_FUNC_ALWAYS; + dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[i].ref_value = 0; + dsa.stencil[i].valuemask = 0; + dsa.stencil[i].writemask = 0; + } + dsa.alpha.enabled = 0; + dsa.alpha.func = PIPE_FUNC_ALWAYS; + dsa.alpha.ref_value = 0; + context->dsa = pipe->create_depth_stencil_alpha_state(pipe, &dsa); + pipe->bind_depth_stencil_alpha_state(pipe, context->dsa); + + return 0; +} + +int vlCreateContext +( + struct vlScreen *screen, + struct pipe_context *pipe, + unsigned int picture_width, + unsigned int picture_height, + enum vlFormat picture_format, + enum vlProfile profile, + enum vlEntryPoint entry_point, + struct vlContext **context +) +{ + struct vlContext *ctx; + + assert(screen); + assert(context); + assert(pipe); + + ctx = CALLOC_STRUCT(vlContext); + + if (!ctx) + return 1; + + ctx->screen = screen; + ctx->pipe = pipe; + ctx->picture_width = picture_width; + ctx->picture_height = picture_height; + ctx->picture_format = picture_format; + ctx->profile = profile; + ctx->entry_point = entry_point; + + vlInitCommon(ctx); + + vlCreateR16SNormBufferedMC(pipe, picture_width, picture_height, picture_format, &ctx->render); + vlCreateBasicCSC(pipe, &ctx->csc); + + *context = ctx; + + return 0; +} + +int vlDestroyContext +( + struct vlContext *context +) +{ + assert(context); + + /* XXX: Must unbind shaders before we can delete them for some reason */ + context->pipe->bind_vs_state(context->pipe, NULL); + context->pipe->bind_fs_state(context->pipe, NULL); + + context->render->vlDestroy(context->render); + context->csc->vlDestroy(context->csc); + + context->pipe->delete_blend_state(context->pipe, context->blend); + context->pipe->delete_rasterizer_state(context->pipe, context->raster); + context->pipe->delete_depth_stencil_alpha_state(context->pipe, context->dsa); + + FREE(context); + + return 0; +} + +struct vlScreen* vlContextGetScreen +( + struct vlContext *context +) +{ + assert(context); + + return context->screen; +} + +struct pipe_context* vlGetPipeContext +( + struct vlContext *context +) +{ + assert(context); + + return context->pipe; +} + +unsigned int vlGetPictureWidth +( + struct vlContext *context +) +{ + assert(context); + + return context->picture_width; +} + +unsigned int vlGetPictureHeight +( + struct vlContext *context +) +{ + assert(context); + + return context->picture_height; +} + +enum vlFormat vlGetPictureFormat +( + struct vlContext *context +) +{ + assert(context); + + return context->picture_format; +} diff --git a/src/gallium/state_trackers/g3dvl/vl_context.h b/src/gallium/state_trackers/g3dvl/vl_context.h new file mode 100644 index 0000000000..3d14634c44 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_context.h @@ -0,0 +1,73 @@ +#ifndef vl_context_h +#define vl_context_h + +#include "vl_types.h" + +struct pipe_context; + +#ifdef VL_INTERNAL +struct vlRender; +struct vlCSC; + +struct vlContext +{ + struct vlScreen *screen; + struct pipe_context *pipe; + unsigned int picture_width; + unsigned int picture_height; + enum vlFormat picture_format; + enum vlProfile profile; + enum vlEntryPoint entry_point; + + void *raster; + void *dsa; + void *blend; + + struct vlRender *render; + struct vlCSC *csc; +}; +#endif + +int vlCreateContext +( + struct vlScreen *screen, + struct pipe_context *pipe, + unsigned int picture_width, + unsigned int picture_height, + enum vlFormat picture_format, + enum vlProfile profile, + enum vlEntryPoint entry_point, + struct vlContext **context +); + +int vlDestroyContext +( + struct vlContext *context +); + +struct vlScreen* vlContextGetScreen +( + struct vlContext *context +); + +struct pipe_context* vlGetPipeContext +( + struct vlContext *context +); + +unsigned int vlGetPictureWidth +( + struct vlContext *context +); + +unsigned int vlGetPictureHeight +( + struct vlContext *context +); + +enum vlFormat vlGetPictureFormat +( + struct vlContext *context +); + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_csc.h b/src/gallium/state_trackers/g3dvl/vl_csc.h new file mode 100644 index 0000000000..36417a2792 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_csc.h @@ -0,0 +1,53 @@ +#ifndef vl_csc_h +#define vl_csc_h + +#include "vl_types.h" + +struct pipe_surface; + +struct vlCSC +{ + int (*vlResizeFrameBuffer) + ( + struct vlCSC *csc, + unsigned int width, + unsigned int height + ); + + int (*vlBegin) + ( + struct vlCSC *csc + ); + + int (*vlPutPicture) + ( + struct vlCSC *csc, + struct vlSurface *surface, + int srcx, + int srcy, + int srcw, + int srch, + int destx, + int desty, + int destw, + int desth, + enum vlPictureType picture_type + ); + + int (*vlEnd) + ( + struct vlCSC *csc + ); + + struct pipe_surface* (*vlGetFrameBuffer) + ( + struct vlCSC *csc + ); + + int (*vlDestroy) + ( + struct vlCSC *csc + ); +}; + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_defs.h b/src/gallium/state_trackers/g3dvl/vl_defs.h new file mode 100644 index 0000000000..d612d02502 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_defs.h @@ -0,0 +1,11 @@ +#ifndef vl_defs_h +#define vl_defs_h + +#define VL_BLOCK_WIDTH 8 +#define VL_BLOCK_HEIGHT 8 +#define VL_BLOCK_SIZE (VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT) +#define VL_MACROBLOCK_WIDTH 16 +#define VL_MACROBLOCK_HEIGHT 16 +#define VL_MACROBLOCK_SIZE (VL_MACROBLOCK_WIDTH * VL_MACROBLOCK_HEIGHT) + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_display.c b/src/gallium/state_trackers/g3dvl/vl_display.c new file mode 100644 index 0000000000..dce06de758 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_display.c @@ -0,0 +1,48 @@ +#define VL_INTERNAL +#include "vl_display.h" +#include <assert.h> +#include <util/u_memory.h> + +int vlCreateDisplay +( + vlNativeDisplay native_display, + struct vlDisplay **display +) +{ + struct vlDisplay *dpy; + + assert(native_display); + assert(display); + + dpy = CALLOC_STRUCT(vlDisplay); + + if (!dpy) + return 1; + + dpy->native = native_display; + *display = dpy; + + return 0; +} + +int vlDestroyDisplay +( + struct vlDisplay *display +) +{ + assert(display); + + FREE(display); + + return 0; +} + +vlNativeDisplay vlGetNativeDisplay +( + struct vlDisplay *display +) +{ + assert(display); + + return display->native; +} diff --git a/src/gallium/state_trackers/g3dvl/vl_display.h b/src/gallium/state_trackers/g3dvl/vl_display.h new file mode 100644 index 0000000000..e11fd40799 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_display.h @@ -0,0 +1,29 @@ +#ifndef vl_display_h +#define vl_display_h + +#include "vl_types.h" + +#ifdef VL_INTERNAL +struct vlDisplay +{ + vlNativeDisplay native; +}; +#endif + +int vlCreateDisplay +( + vlNativeDisplay native_display, + struct vlDisplay **display +); + +int vlDestroyDisplay +( + struct vlDisplay *display +); + +vlNativeDisplay vlGetNativeDisplay +( + struct vlDisplay *display +); + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_r16snorm_mc_buf.c b/src/gallium/state_trackers/g3dvl/vl_r16snorm_mc_buf.c new file mode 100644 index 0000000000..23631adb69 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_r16snorm_mc_buf.c @@ -0,0 +1,1155 @@ +#define VL_INTERNAL +#include "vl_r16snorm_mc_buf.h" +#include <assert.h> +#include <pipe/p_context.h> +#include <pipe/p_screen.h> +#include <pipe/p_state.h> +#include <pipe/p_inlines.h> +#include <tgsi/tgsi_parse.h> +#include <tgsi/tgsi_build.h> +#include <util/u_math.h> +#include <util/u_memory.h> +#include "vl_render.h" +#include "vl_shader_build.h" +#include "vl_surface.h" +#include "vl_util.h" +#include "vl_types.h" +#include "vl_defs.h" + +const unsigned int DEFAULT_BUF_ALIGNMENT = 1; + +enum vlMacroBlockTypeEx +{ + vlMacroBlockExTypeIntra, + vlMacroBlockExTypeFwdPredictedFrame, + vlMacroBlockExTypeFwdPredictedField, + vlMacroBlockExTypeBkwdPredictedFrame, + vlMacroBlockExTypeBkwdPredictedField, + vlMacroBlockExTypeBiPredictedFrame, + vlMacroBlockExTypeBiPredictedField, + + vlNumMacroBlockExTypes +}; + +struct vlVertexShaderConsts +{ + struct vlVertex4f denorm; +}; + +struct vlFragmentShaderConsts +{ + struct vlVertex4f multiplier; + struct vlVertex4f div; +}; + +struct vlMacroBlockVertexStream0 +{ + struct vlVertex2f pos; + struct vlVertex2f luma_tc; + struct vlVertex2f cb_tc; + struct vlVertex2f cr_tc; +}; + +struct vlR16SnormBufferedMC +{ + struct vlRender base; + + unsigned int picture_width; + unsigned int picture_height; + enum vlFormat picture_format; + unsigned int macroblocks_per_picture; + + struct vlSurface *buffered_surface; + struct vlSurface *past_surface; + struct vlSurface *future_surface; + struct vlVertex2f surface_tex_inv_size; + struct vlVertex2f zero_block[3]; + unsigned int num_macroblocks; + struct vlMpeg2MacroBlock *macroblocks; + struct pipe_transfer *tex_transfer[3]; + short *texels[3]; + + struct pipe_context *pipe; + struct pipe_viewport_state viewport; + struct pipe_framebuffer_state render_target; + + union + { + void *all[5]; + struct + { + void *y; + void *cb; + void *cr; + void *ref[2]; + }; + } samplers; + + union + { + struct pipe_texture *all[5]; + struct + { + struct pipe_texture *y; + struct pipe_texture *cb; + struct pipe_texture *cr; + struct pipe_texture *ref[2]; + }; + } textures; + + union + { + struct pipe_vertex_buffer all[3]; + struct + { + struct pipe_vertex_buffer ycbcr; + struct pipe_vertex_buffer ref[2]; + }; + } vertex_bufs; + + void *i_vs, *p_vs[2], *b_vs[2]; + void *i_fs, *p_fs[2], *b_fs[2]; + struct pipe_vertex_element vertex_elems[8]; + struct pipe_constant_buffer vs_const_buf; + struct pipe_constant_buffer fs_const_buf; +}; + +static inline int vlBegin +( + struct vlRender *render +) +{ + assert(render); + + return 0; +} + +static inline int vlGrabFrameCodedBlock(short *src, short *dst, unsigned int dst_pitch) +{ + unsigned int y; + + for (y = 0; y < VL_BLOCK_HEIGHT; ++y) + memcpy + ( + dst + y * dst_pitch, + src + y * VL_BLOCK_WIDTH, + VL_BLOCK_WIDTH * 2 + ); + + return 0; +} + +static inline int vlGrabFieldCodedBlock(short *src, short *dst, unsigned int dst_pitch) +{ + unsigned int y; + + for (y = 0; y < VL_BLOCK_HEIGHT; ++y) + memcpy + ( + dst + y * dst_pitch * 2, + src + y * VL_BLOCK_WIDTH, + VL_BLOCK_WIDTH * 2 + ); + + return 0; +} + +static inline int vlGrabNoBlock(short *dst, unsigned int dst_pitch) +{ + unsigned int y; + + for (y = 0; y < VL_BLOCK_HEIGHT; ++y) + memset + ( + dst + y * dst_pitch, + 0, + VL_BLOCK_WIDTH * 2 + ); + + return 0; +} + +static inline int vlGrabBlocks +( + struct vlR16SnormBufferedMC *mc, + unsigned int mbx, + unsigned int mby, + enum vlDCTType dct_type, + unsigned int coded_block_pattern, + short *blocks +) +{ + short *texels; + unsigned int tex_pitch; + unsigned int x, y, tb = 0, sb = 0; + unsigned int mbpx = mbx * VL_MACROBLOCK_WIDTH, mbpy = mby * VL_MACROBLOCK_HEIGHT; + + assert(mc); + assert(blocks); + + tex_pitch = mc->tex_transfer[0]->stride / mc->tex_transfer[0]->block.size; + texels = mc->texels[0] + mbpy * tex_pitch + mbpx; + + for (y = 0; y < 2; ++y) + { + for (x = 0; x < 2; ++x, ++tb) + { + if ((coded_block_pattern >> (5 - tb)) & 1) + { + short *cur_block = blocks + sb * VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT; + + if (dct_type == vlDCTTypeFrameCoded) + { + vlGrabFrameCodedBlock + ( + cur_block, + texels + y * tex_pitch * VL_BLOCK_HEIGHT + x * VL_BLOCK_WIDTH, + tex_pitch + ); + } + else + { + vlGrabFieldCodedBlock + ( + cur_block, + texels + y * tex_pitch + x * VL_BLOCK_WIDTH, + tex_pitch + ); + } + + ++sb; + } + else if (mc->zero_block[0].x < 0.0f) + { + vlGrabNoBlock(texels + y * tex_pitch * VL_BLOCK_HEIGHT + x * VL_BLOCK_WIDTH, tex_pitch); + + mc->zero_block[0].x = (mbpx + x * 8) * mc->surface_tex_inv_size.x; + mc->zero_block[0].y = (mbpy + y * 8) * mc->surface_tex_inv_size.y; + } + } + } + + /* TODO: Implement 422, 444 */ + mbpx >>= 1; + mbpy >>= 1; + + for (tb = 0; tb < 2; ++tb) + { + tex_pitch = mc->tex_transfer[tb + 1]->stride / mc->tex_transfer[tb + 1]->block.size; + texels = mc->texels[tb + 1] + mbpy * tex_pitch + mbpx; + + if ((coded_block_pattern >> (1 - tb)) & 1) + { + short *cur_block = blocks + sb * VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT; + + vlGrabFrameCodedBlock + ( + cur_block, + texels, + tex_pitch + ); + + ++sb; + } + else if (mc->zero_block[tb + 1].x < 0.0f) + { + vlGrabNoBlock(texels, tex_pitch); + + mc->zero_block[tb + 1].x = (mbpx << 1) * mc->surface_tex_inv_size.x; + mc->zero_block[tb + 1].y = (mbpy << 1) * mc->surface_tex_inv_size.y; + } + } + + return 0; +} + +static inline enum vlMacroBlockTypeEx vlGetMacroBlockTypeEx(struct vlMpeg2MacroBlock *mb) +{ + assert(mb); + + switch (mb->mb_type) + { + case vlMacroBlockTypeIntra: + return vlMacroBlockExTypeIntra; + case vlMacroBlockTypeFwdPredicted: + return mb->mo_type == vlMotionTypeFrame ? + vlMacroBlockExTypeFwdPredictedFrame : vlMacroBlockExTypeFwdPredictedField; + case vlMacroBlockTypeBkwdPredicted: + return mb->mo_type == vlMotionTypeFrame ? + vlMacroBlockExTypeBkwdPredictedFrame : vlMacroBlockExTypeBkwdPredictedField; + case vlMacroBlockTypeBiPredicted: + return mb->mo_type == vlMotionTypeFrame ? + vlMacroBlockExTypeBiPredictedFrame : vlMacroBlockExTypeBiPredictedField; + default: + assert(0); + } + + /* Unreachable */ + return -1; +} + +static inline int vlGrabMacroBlock +( + struct vlR16SnormBufferedMC *mc, + struct vlMpeg2MacroBlock *macroblock +) +{ + assert(mc); + assert(macroblock); + assert(mc->num_macroblocks < mc->macroblocks_per_picture); + + mc->macroblocks[mc->num_macroblocks].mbx = macroblock->mbx; + mc->macroblocks[mc->num_macroblocks].mby = macroblock->mby; + mc->macroblocks[mc->num_macroblocks].mb_type = macroblock->mb_type; + mc->macroblocks[mc->num_macroblocks].mo_type = macroblock->mo_type; + mc->macroblocks[mc->num_macroblocks].dct_type = macroblock->dct_type; + mc->macroblocks[mc->num_macroblocks].PMV[0][0][0] = macroblock->PMV[0][0][0]; + mc->macroblocks[mc->num_macroblocks].PMV[0][0][1] = macroblock->PMV[0][0][1]; + mc->macroblocks[mc->num_macroblocks].PMV[0][1][0] = macroblock->PMV[0][1][0]; + mc->macroblocks[mc->num_macroblocks].PMV[0][1][1] = macroblock->PMV[0][1][1]; + mc->macroblocks[mc->num_macroblocks].PMV[1][0][0] = macroblock->PMV[1][0][0]; + mc->macroblocks[mc->num_macroblocks].PMV[1][0][1] = macroblock->PMV[1][0][1]; + mc->macroblocks[mc->num_macroblocks].PMV[1][1][0] = macroblock->PMV[1][1][0]; + mc->macroblocks[mc->num_macroblocks].PMV[1][1][1] = macroblock->PMV[1][1][1]; + mc->macroblocks[mc->num_macroblocks].cbp = macroblock->cbp; + mc->macroblocks[mc->num_macroblocks].blocks = macroblock->blocks; + + vlGrabBlocks + ( + mc, + macroblock->mbx, + macroblock->mby, + macroblock->dct_type, + macroblock->cbp, + macroblock->blocks + ); + + mc->num_macroblocks++; + + return 0; +} + +#define SET_BLOCK(vb, cbp, mbx, mby, unitx, unity, ofsx, ofsy, hx, hy, lm, cbm, crm, zb) \ + do { \ + (vb)[0].pos.x = (mbx) * (unitx) + (ofsx); (vb)[0].pos.y = (mby) * (unity) + (ofsy); \ + (vb)[1].pos.x = (mbx) * (unitx) + (ofsx); (vb)[1].pos.y = (mby) * (unity) + (ofsy) + (hy); \ + (vb)[2].pos.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[2].pos.y = (mby) * (unity) + (ofsy); \ + (vb)[3].pos.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[3].pos.y = (mby) * (unity) + (ofsy); \ + (vb)[4].pos.x = (mbx) * (unitx) + (ofsx); (vb)[4].pos.y = (mby) * (unity) + (ofsy) + (hy); \ + (vb)[5].pos.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[5].pos.y = (mby) * (unity) + (ofsy) + (hy); \ + \ + if ((cbp) & (lm)) \ + { \ + (vb)[0].luma_tc.x = (mbx) * (unitx) + (ofsx); (vb)[0].luma_tc.y = (mby) * (unity) + (ofsy); \ + (vb)[1].luma_tc.x = (mbx) * (unitx) + (ofsx); (vb)[1].luma_tc.y = (mby) * (unity) + (ofsy) + (hy); \ + (vb)[2].luma_tc.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[2].luma_tc.y = (mby) * (unity) + (ofsy); \ + (vb)[3].luma_tc.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[3].luma_tc.y = (mby) * (unity) + (ofsy); \ + (vb)[4].luma_tc.x = (mbx) * (unitx) + (ofsx); (vb)[4].luma_tc.y = (mby) * (unity) + (ofsy) + (hy); \ + (vb)[5].luma_tc.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[5].luma_tc.y = (mby) * (unity) + (ofsy) + (hy); \ + } \ + else \ + { \ + (vb)[0].luma_tc.x = (zb)[0].x; (vb)[0].luma_tc.y = (zb)[0].y; \ + (vb)[1].luma_tc.x = (zb)[0].x; (vb)[1].luma_tc.y = (zb)[0].y + (hy); \ + (vb)[2].luma_tc.x = (zb)[0].x + (hx); (vb)[2].luma_tc.y = (zb)[0].y; \ + (vb)[3].luma_tc.x = (zb)[0].x + (hx); (vb)[3].luma_tc.y = (zb)[0].y; \ + (vb)[4].luma_tc.x = (zb)[0].x; (vb)[4].luma_tc.y = (zb)[0].y + (hy); \ + (vb)[5].luma_tc.x = (zb)[0].x + (hx); (vb)[5].luma_tc.y = (zb)[0].y + (hy); \ + } \ + \ + if ((cbp) & (cbm)) \ + { \ + (vb)[0].cb_tc.x = (mbx) * (unitx) + (ofsx); (vb)[0].cb_tc.y = (mby) * (unity) + (ofsy); \ + (vb)[1].cb_tc.x = (mbx) * (unitx) + (ofsx); (vb)[1].cb_tc.y = (mby) * (unity) + (ofsy) + (hy); \ + (vb)[2].cb_tc.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[2].cb_tc.y = (mby) * (unity) + (ofsy); \ + (vb)[3].cb_tc.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[3].cb_tc.y = (mby) * (unity) + (ofsy); \ + (vb)[4].cb_tc.x = (mbx) * (unitx) + (ofsx); (vb)[4].cb_tc.y = (mby) * (unity) + (ofsy) + (hy); \ + (vb)[5].cb_tc.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[5].cb_tc.y = (mby) * (unity) + (ofsy) + (hy); \ + } \ + else \ + { \ + (vb)[0].cb_tc.x = (zb)[1].x; (vb)[0].cb_tc.y = (zb)[1].y; \ + (vb)[1].cb_tc.x = (zb)[1].x; (vb)[1].cb_tc.y = (zb)[1].y + (hy); \ + (vb)[2].cb_tc.x = (zb)[1].x + (hx); (vb)[2].cb_tc.y = (zb)[1].y; \ + (vb)[3].cb_tc.x = (zb)[1].x + (hx); (vb)[3].cb_tc.y = (zb)[1].y; \ + (vb)[4].cb_tc.x = (zb)[1].x; (vb)[4].cb_tc.y = (zb)[1].y + (hy); \ + (vb)[5].cb_tc.x = (zb)[1].x + (hx); (vb)[5].cb_tc.y = (zb)[1].y + (hy); \ + } \ + \ + if ((cbp) & (crm)) \ + { \ + (vb)[0].cr_tc.x = (mbx) * (unitx) + (ofsx); (vb)[0].cr_tc.y = (mby) * (unity) + (ofsy); \ + (vb)[1].cr_tc.x = (mbx) * (unitx) + (ofsx); (vb)[1].cr_tc.y = (mby) * (unity) + (ofsy) + (hy); \ + (vb)[2].cr_tc.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[2].cr_tc.y = (mby) * (unity) + (ofsy); \ + (vb)[3].cr_tc.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[3].cr_tc.y = (mby) * (unity) + (ofsy); \ + (vb)[4].cr_tc.x = (mbx) * (unitx) + (ofsx); (vb)[4].cr_tc.y = (mby) * (unity) + (ofsy) + (hy); \ + (vb)[5].cr_tc.x = (mbx) * (unitx) + (ofsx) + (hx); (vb)[5].cr_tc.y = (mby) * (unity) + (ofsy) + (hy); \ + } \ + else \ + { \ + (vb)[0].cr_tc.x = (zb)[2].x; (vb)[0].cr_tc.y = (zb)[2].y; \ + (vb)[1].cr_tc.x = (zb)[2].x; (vb)[1].cr_tc.y = (zb)[2].y + (hy); \ + (vb)[2].cr_tc.x = (zb)[2].x + (hx); (vb)[2].cr_tc.y = (zb)[2].y; \ + (vb)[3].cr_tc.x = (zb)[2].x + (hx); (vb)[3].cr_tc.y = (zb)[2].y; \ + (vb)[4].cr_tc.x = (zb)[2].x; (vb)[4].cr_tc.y = (zb)[2].y + (hy); \ + (vb)[5].cr_tc.x = (zb)[2].x + (hx); (vb)[5].cr_tc.y = (zb)[2].y + (hy); \ + } \ + } while (0) + +static inline int vlGenMacroblockVerts +( + struct vlR16SnormBufferedMC *mc, + struct vlMpeg2MacroBlock *macroblock, + unsigned int pos, + struct vlMacroBlockVertexStream0 *ycbcr_vb, + struct vlVertex2f **ref_vb +) +{ + struct vlVertex2f mo_vec[2]; + unsigned int i; + + assert(mc); + assert(macroblock); + assert(ycbcr_vb); + assert(pos < mc->macroblocks_per_picture); + + switch (macroblock->mb_type) + { + case vlMacroBlockTypeBiPredicted: + { + struct vlVertex2f *vb; + + assert(ref_vb && ref_vb[1]); + + vb = ref_vb[1] + pos * 2 * 24; + + mo_vec[0].x = macroblock->PMV[0][1][0] * 0.5f * mc->surface_tex_inv_size.x; + mo_vec[0].y = macroblock->PMV[0][1][1] * 0.5f * mc->surface_tex_inv_size.y; + + if (macroblock->mo_type == vlMotionTypeFrame) + { + for (i = 0; i < 24 * 2; i += 2) + { + vb[i].x = mo_vec[0].x; + vb[i].y = mo_vec[0].y; + } + } + else + { + mo_vec[1].x = macroblock->PMV[1][1][0] * 0.5f * mc->surface_tex_inv_size.x; + mo_vec[1].y = macroblock->PMV[1][1][1] * 0.5f * mc->surface_tex_inv_size.y; + + for (i = 0; i < 24 * 2; i += 2) + { + vb[i].x = mo_vec[0].x; + vb[i].y = mo_vec[0].y; + vb[i + 1].x = mo_vec[1].x; + vb[i + 1].y = mo_vec[1].y; + } + } + + /* fall-through */ + } + case vlMacroBlockTypeFwdPredicted: + case vlMacroBlockTypeBkwdPredicted: + { + struct vlVertex2f *vb; + + assert(ref_vb && ref_vb[0]); + + vb = ref_vb[0] + pos * 2 * 24; + + if (macroblock->mb_type == vlMacroBlockTypeBkwdPredicted) + { + mo_vec[0].x = macroblock->PMV[0][1][0] * 0.5f * mc->surface_tex_inv_size.x; + mo_vec[0].y = macroblock->PMV[0][1][1] * 0.5f * mc->surface_tex_inv_size.y; + + if (macroblock->mo_type == vlMotionTypeField) + { + mo_vec[1].x = macroblock->PMV[1][1][0] * 0.5f * mc->surface_tex_inv_size.x; + mo_vec[1].y = macroblock->PMV[1][1][1] * 0.5f * mc->surface_tex_inv_size.y; + } + } + else + { + mo_vec[0].x = macroblock->PMV[0][0][0] * 0.5f * mc->surface_tex_inv_size.x; + mo_vec[0].y = macroblock->PMV[0][0][1] * 0.5f * mc->surface_tex_inv_size.y; + + if (macroblock->mo_type == vlMotionTypeField) + { + mo_vec[1].x = macroblock->PMV[1][0][0] * 0.5f * mc->surface_tex_inv_size.x; + mo_vec[1].y = macroblock->PMV[1][0][1] * 0.5f * mc->surface_tex_inv_size.y; + } + } + + if (macroblock->mo_type == vlMotionTypeFrame) + { + for (i = 0; i < 24 * 2; i += 2) + { + vb[i].x = mo_vec[0].x; + vb[i].y = mo_vec[0].y; + } + } + else + { + for (i = 0; i < 24 * 2; i += 2) + { + vb[i].x = mo_vec[0].x; + vb[i].y = mo_vec[0].y; + vb[i + 1].x = mo_vec[1].x; + vb[i + 1].y = mo_vec[1].y; + } + } + + /* fall-through */ + } + case vlMacroBlockTypeIntra: + { + const struct vlVertex2f unit = + { + mc->surface_tex_inv_size.x * VL_MACROBLOCK_WIDTH, + mc->surface_tex_inv_size.y * VL_MACROBLOCK_HEIGHT + }; + const struct vlVertex2f half = + { + mc->surface_tex_inv_size.x * (VL_MACROBLOCK_WIDTH / 2), + mc->surface_tex_inv_size.y * (VL_MACROBLOCK_HEIGHT / 2) + }; + + struct vlMacroBlockVertexStream0 *vb; + + vb = ycbcr_vb + pos * 24; + + SET_BLOCK + ( + vb, + macroblock->cbp, macroblock->mbx, macroblock->mby, + unit.x, unit.y, 0, 0, half.x, half.y, + 32, 2, 1, mc->zero_block + ); + + SET_BLOCK + ( + vb + 6, + macroblock->cbp, macroblock->mbx, macroblock->mby, + unit.x, unit.y, half.x, 0, half.x, half.y, + 16, 2, 1, mc->zero_block + ); + + SET_BLOCK + ( + vb + 12, + macroblock->cbp, macroblock->mbx, macroblock->mby, + unit.x, unit.y, 0, half.y, half.x, half.y, + 8, 2, 1, mc->zero_block + ); + + SET_BLOCK + ( + vb + 18, + macroblock->cbp, macroblock->mbx, macroblock->mby, + unit.x, unit.y, half.x, half.y, half.x, half.y, + 4, 2, 1, mc->zero_block + ); + + break; + } + default: + assert(0); + } + + return 0; +} + +static int vlFlush +( + struct vlRender *render +) +{ + struct vlR16SnormBufferedMC *mc; + struct pipe_context *pipe; + struct vlVertexShaderConsts *vs_consts; + unsigned int num_macroblocks[vlNumMacroBlockExTypes] = {0}; + unsigned int offset[vlNumMacroBlockExTypes]; + unsigned int vb_start = 0; + unsigned int i; + + assert(render); + + mc = (struct vlR16SnormBufferedMC*)render; + + if (!mc->buffered_surface) + return 0; + + if (mc->num_macroblocks < mc->macroblocks_per_picture) + return 0; + + assert(mc->num_macroblocks <= mc->macroblocks_per_picture); + + pipe = mc->pipe; + + for (i = 0; i < mc->num_macroblocks; ++i) + { + enum vlMacroBlockTypeEx mb_type_ex = vlGetMacroBlockTypeEx(&mc->macroblocks[i]); + + num_macroblocks[mb_type_ex]++; + } + + offset[0] = 0; + + for (i = 1; i < vlNumMacroBlockExTypes; ++i) + offset[i] = offset[i - 1] + num_macroblocks[i - 1]; + + { + struct vlMacroBlockVertexStream0 *ycbcr_vb; + struct vlVertex2f *ref_vb[2]; + + ycbcr_vb = (struct vlMacroBlockVertexStream0*)pipe_buffer_map + ( + pipe->screen, + mc->vertex_bufs.ycbcr.buffer, + PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_DISCARD + ); + + for (i = 0; i < 2; ++i) + ref_vb[i] = (struct vlVertex2f*)pipe_buffer_map + ( + pipe->screen, + mc->vertex_bufs.ref[i].buffer, + PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_DISCARD + ); + + for (i = 0; i < mc->num_macroblocks; ++i) + { + enum vlMacroBlockTypeEx mb_type_ex = vlGetMacroBlockTypeEx(&mc->macroblocks[i]); + + vlGenMacroblockVerts(mc, &mc->macroblocks[i], offset[mb_type_ex], ycbcr_vb, ref_vb); + + offset[mb_type_ex]++; + } + + pipe_buffer_unmap(pipe->screen, mc->vertex_bufs.ycbcr.buffer); + for (i = 0; i < 2; ++i) + pipe_buffer_unmap(pipe->screen, mc->vertex_bufs.ref[i].buffer); + } + + for (i = 0; i < 3; ++i) + { + pipe->screen->transfer_unmap(pipe->screen, mc->tex_transfer[i]); + pipe->screen->tex_transfer_destroy(mc->tex_transfer[i]); + } + + mc->render_target.cbufs[0] = pipe->screen->get_tex_surface + ( + pipe->screen, + mc->buffered_surface->texture, + 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE + ); + + pipe->set_framebuffer_state(pipe, &mc->render_target); + pipe->set_viewport_state(pipe, &mc->viewport); + vs_consts = pipe_buffer_map + ( + pipe->screen, + mc->vs_const_buf.buffer, + PIPE_BUFFER_USAGE_CPU_WRITE | PIPE_BUFFER_USAGE_DISCARD + ); + + vs_consts->denorm.x = mc->buffered_surface->texture->width[0]; + vs_consts->denorm.y = mc->buffered_surface->texture->height[0]; + + pipe_buffer_unmap(pipe->screen, mc->vs_const_buf.buffer); + pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &mc->vs_const_buf); + pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &mc->fs_const_buf); + + if (num_macroblocks[vlMacroBlockExTypeIntra] > 0) + { + pipe->set_vertex_buffers(pipe, 1, mc->vertex_bufs.all); + pipe->set_vertex_elements(pipe, 4, mc->vertex_elems); + pipe->set_sampler_textures(pipe, 3, mc->textures.all); + pipe->bind_sampler_states(pipe, 3, mc->samplers.all); + pipe->bind_vs_state(pipe, mc->i_vs); + pipe->bind_fs_state(pipe, mc->i_fs); + + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLES, vb_start, num_macroblocks[vlMacroBlockExTypeIntra] * 24); + vb_start += num_macroblocks[vlMacroBlockExTypeIntra] * 24; + } + + if (num_macroblocks[vlMacroBlockExTypeFwdPredictedFrame] > 0) + { + pipe->set_vertex_buffers(pipe, 2, mc->vertex_bufs.all); + pipe->set_vertex_elements(pipe, 6, mc->vertex_elems); + mc->textures.ref[0] = mc->past_surface->texture; + pipe->set_sampler_textures(pipe, 4, mc->textures.all); + pipe->bind_sampler_states(pipe, 4, mc->samplers.all); + pipe->bind_vs_state(pipe, mc->p_vs[0]); + pipe->bind_fs_state(pipe, mc->p_fs[0]); + + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLES, vb_start, num_macroblocks[vlMacroBlockExTypeFwdPredictedFrame] * 24); + vb_start += num_macroblocks[vlMacroBlockExTypeFwdPredictedFrame] * 24; + } + + if (num_macroblocks[vlMacroBlockExTypeFwdPredictedField] > 0) + { + pipe->set_vertex_buffers(pipe, 2, mc->vertex_bufs.all); + pipe->set_vertex_elements(pipe, 6, mc->vertex_elems); + mc->textures.ref[0] = mc->past_surface->texture; + pipe->set_sampler_textures(pipe, 4, mc->textures.all); + pipe->bind_sampler_states(pipe, 4, mc->samplers.all); + pipe->bind_vs_state(pipe, mc->p_vs[1]); + pipe->bind_fs_state(pipe, mc->p_fs[1]); + + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLES, vb_start, num_macroblocks[vlMacroBlockExTypeFwdPredictedField] * 24); + vb_start += num_macroblocks[vlMacroBlockExTypeFwdPredictedField] * 24; + } + + if (num_macroblocks[vlMacroBlockExTypeBkwdPredictedFrame] > 0) + { + pipe->set_vertex_buffers(pipe, 2, mc->vertex_bufs.all); + pipe->set_vertex_elements(pipe, 6, mc->vertex_elems); + mc->textures.ref[0] = mc->future_surface->texture; + pipe->set_sampler_textures(pipe, 4, mc->textures.all); + pipe->bind_sampler_states(pipe, 4, mc->samplers.all); + pipe->bind_vs_state(pipe, mc->p_vs[0]); + pipe->bind_fs_state(pipe, mc->p_fs[0]); + + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLES, vb_start, num_macroblocks[vlMacroBlockExTypeBkwdPredictedFrame] * 24); + vb_start += num_macroblocks[vlMacroBlockExTypeBkwdPredictedFrame] * 24; + } + + if (num_macroblocks[vlMacroBlockExTypeBkwdPredictedField] > 0) + { + pipe->set_vertex_buffers(pipe, 2, mc->vertex_bufs.all); + pipe->set_vertex_elements(pipe, 6, mc->vertex_elems); + mc->textures.ref[0] = mc->future_surface->texture; + pipe->set_sampler_textures(pipe, 4, mc->textures.all); + pipe->bind_sampler_states(pipe, 4, mc->samplers.all); + pipe->bind_vs_state(pipe, mc->p_vs[1]); + pipe->bind_fs_state(pipe, mc->p_fs[1]); + + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLES, vb_start, num_macroblocks[vlMacroBlockExTypeBkwdPredictedField] * 24); + vb_start += num_macroblocks[vlMacroBlockExTypeBkwdPredictedField] * 24; + } + + if (num_macroblocks[vlMacroBlockExTypeBiPredictedFrame] > 0) + { + pipe->set_vertex_buffers(pipe, 3, mc->vertex_bufs.all); + pipe->set_vertex_elements(pipe, 8, mc->vertex_elems); + mc->textures.ref[0] = mc->past_surface->texture; + mc->textures.ref[1] = mc->future_surface->texture; + pipe->set_sampler_textures(pipe, 5, mc->textures.all); + pipe->bind_sampler_states(pipe, 5, mc->samplers.all); + pipe->bind_vs_state(pipe, mc->b_vs[0]); + pipe->bind_fs_state(pipe, mc->b_fs[0]); + + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLES, vb_start, num_macroblocks[vlMacroBlockExTypeBiPredictedFrame] * 24); + vb_start += num_macroblocks[vlMacroBlockExTypeBiPredictedFrame] * 24; + } + + if (num_macroblocks[vlMacroBlockExTypeBiPredictedField] > 0) + { + pipe->set_vertex_buffers(pipe, 3, mc->vertex_bufs.all); + pipe->set_vertex_elements(pipe, 8, mc->vertex_elems); + mc->textures.ref[0] = mc->past_surface->texture; + mc->textures.ref[1] = mc->future_surface->texture; + pipe->set_sampler_textures(pipe, 5, mc->textures.all); + pipe->bind_sampler_states(pipe, 5, mc->samplers.all); + pipe->bind_vs_state(pipe, mc->b_vs[1]); + pipe->bind_fs_state(pipe, mc->b_fs[1]); + + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLES, vb_start, num_macroblocks[vlMacroBlockExTypeBiPredictedField] * 24); + vb_start += num_macroblocks[vlMacroBlockExTypeBiPredictedField] * 24; + } + + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, &mc->buffered_surface->render_fence); + pipe_surface_reference(&mc->render_target.cbufs[0], NULL); + + for (i = 0; i < 3; ++i) + mc->zero_block[i].x = -1.0f; + + mc->buffered_surface = NULL; + mc->num_macroblocks = 0; + + return 0; +} + +static int vlRenderMacroBlocksMpeg2R16SnormBuffered +( + struct vlRender *render, + struct vlMpeg2MacroBlockBatch *batch, + struct vlSurface *surface +) +{ + struct vlR16SnormBufferedMC *mc; + bool new_surface = false; + unsigned int i; + + assert(render); + + mc = (struct vlR16SnormBufferedMC*)render; + + if (mc->buffered_surface) + { + if (mc->buffered_surface != surface) + { + vlFlush(&mc->base); + new_surface = true; + } + } + else + new_surface = true; + + if (new_surface) + { + mc->buffered_surface = surface; + mc->past_surface = batch->past_surface; + mc->future_surface = batch->future_surface; + mc->surface_tex_inv_size.x = 1.0f / surface->texture->width[0]; + mc->surface_tex_inv_size.y = 1.0f / surface->texture->height[0]; + + for (i = 0; i < 3; ++i) + { + mc->tex_transfer[i] = mc->pipe->screen->get_tex_transfer + ( + mc->pipe->screen, + mc->textures.all[i], + 0, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, + surface->texture->width[0], + surface->texture->height[0] + ); + + mc->texels[i] = mc->pipe->screen->transfer_map(mc->pipe->screen, mc->tex_transfer[i]); + } + } + + for (i = 0; i < batch->num_macroblocks; ++i) + vlGrabMacroBlock(mc, &batch->macroblocks[i]); + + return 0; +} + +static inline int vlEnd +( + struct vlRender *render +) +{ + assert(render); + + return 0; +} + +static int vlDestroy +( + struct vlRender *render +) +{ + struct vlR16SnormBufferedMC *mc; + struct pipe_context *pipe; + unsigned int i; + + assert(render); + + mc = (struct vlR16SnormBufferedMC*)render; + pipe = mc->pipe; + + for (i = 0; i < 5; ++i) + pipe->delete_sampler_state(pipe, mc->samplers.all[i]); + + for (i = 0; i < 3; ++i) + pipe_buffer_reference(&mc->vertex_bufs.all[i].buffer, NULL); + + /* Textures 3 & 4 are not created directly, no need to release them here */ + for (i = 0; i < 3; ++i) + pipe_texture_reference(&mc->textures.all[i], NULL); + + pipe->delete_vs_state(pipe, mc->i_vs); + pipe->delete_fs_state(pipe, mc->i_fs); + + for (i = 0; i < 2; ++i) + { + pipe->delete_vs_state(pipe, mc->p_vs[i]); + pipe->delete_fs_state(pipe, mc->p_fs[i]); + pipe->delete_vs_state(pipe, mc->b_vs[i]); + pipe->delete_fs_state(pipe, mc->b_fs[i]); + } + + pipe_buffer_reference(&mc->vs_const_buf.buffer, NULL); + pipe_buffer_reference(&mc->fs_const_buf.buffer, NULL); + + FREE(mc->macroblocks); + FREE(mc); + + return 0; +} + +/* + * Muliplier renormalizes block samples from 16 bits to 12 bits. + * Divider is used when calculating Y % 2 for choosing top or bottom + * field for P or B macroblocks. + * TODO: Use immediates. + */ +static const struct vlFragmentShaderConsts fs_consts = +{ + {32767.0f / 255.0f, 32767.0f / 255.0f, 32767.0f / 255.0f, 0.0f}, + {0.5f, 2.0f, 0.0f, 0.0f} +}; + +#include "vl_r16snorm_mc_buf_shaders.inc" + +static int vlCreateDataBufs +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int mbw = align(mc->picture_width, VL_MACROBLOCK_WIDTH) / VL_MACROBLOCK_WIDTH; + const unsigned int mbh = align(mc->picture_height, VL_MACROBLOCK_HEIGHT) / VL_MACROBLOCK_HEIGHT; + + struct pipe_context *pipe; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + mc->macroblocks_per_picture = mbw * mbh; + + /* Create our vertex buffers */ + mc->vertex_bufs.ycbcr.stride = sizeof(struct vlVertex2f) * 4; + mc->vertex_bufs.ycbcr.max_index = 24 * mc->macroblocks_per_picture - 1; + mc->vertex_bufs.ycbcr.buffer_offset = 0; + mc->vertex_bufs.ycbcr.buffer = pipe_buffer_create + ( + pipe->screen, + DEFAULT_BUF_ALIGNMENT, + PIPE_BUFFER_USAGE_VERTEX | PIPE_BUFFER_USAGE_DISCARD, + sizeof(struct vlVertex2f) * 4 * 24 * mc->macroblocks_per_picture + ); + + for (i = 1; i < 3; ++i) + { + mc->vertex_bufs.all[i].stride = sizeof(struct vlVertex2f) * 2; + mc->vertex_bufs.all[i].max_index = 24 * mc->macroblocks_per_picture - 1; + mc->vertex_bufs.all[i].buffer_offset = 0; + mc->vertex_bufs.all[i].buffer = pipe_buffer_create + ( + pipe->screen, + DEFAULT_BUF_ALIGNMENT, + PIPE_BUFFER_USAGE_VERTEX | PIPE_BUFFER_USAGE_DISCARD, + sizeof(struct vlVertex2f) * 2 * 24 * mc->macroblocks_per_picture + ); + } + + /* Position element */ + mc->vertex_elems[0].src_offset = 0; + mc->vertex_elems[0].vertex_buffer_index = 0; + mc->vertex_elems[0].nr_components = 2; + mc->vertex_elems[0].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* Luma, texcoord element */ + mc->vertex_elems[1].src_offset = sizeof(struct vlVertex2f); + mc->vertex_elems[1].vertex_buffer_index = 0; + mc->vertex_elems[1].nr_components = 2; + mc->vertex_elems[1].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* Chroma Cr texcoord element */ + mc->vertex_elems[2].src_offset = sizeof(struct vlVertex2f) * 2; + mc->vertex_elems[2].vertex_buffer_index = 0; + mc->vertex_elems[2].nr_components = 2; + mc->vertex_elems[2].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* Chroma Cb texcoord element */ + mc->vertex_elems[3].src_offset = sizeof(struct vlVertex2f) * 3; + mc->vertex_elems[3].vertex_buffer_index = 0; + mc->vertex_elems[3].nr_components = 2; + mc->vertex_elems[3].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* First ref surface top field texcoord element */ + mc->vertex_elems[4].src_offset = 0; + mc->vertex_elems[4].vertex_buffer_index = 1; + mc->vertex_elems[4].nr_components = 2; + mc->vertex_elems[4].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* First ref surface bottom field texcoord element */ + mc->vertex_elems[5].src_offset = sizeof(struct vlVertex2f); + mc->vertex_elems[5].vertex_buffer_index = 1; + mc->vertex_elems[5].nr_components = 2; + mc->vertex_elems[5].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* Second ref surface top field texcoord element */ + mc->vertex_elems[6].src_offset = 0; + mc->vertex_elems[6].vertex_buffer_index = 2; + mc->vertex_elems[6].nr_components = 2; + mc->vertex_elems[6].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* Second ref surface bottom field texcoord element */ + mc->vertex_elems[7].src_offset = sizeof(struct vlVertex2f); + mc->vertex_elems[7].vertex_buffer_index = 2; + mc->vertex_elems[7].nr_components = 2; + mc->vertex_elems[7].src_format = PIPE_FORMAT_R32G32_FLOAT; + + /* Create our constant buffer */ + mc->vs_const_buf.buffer = pipe_buffer_create + ( + pipe->screen, + DEFAULT_BUF_ALIGNMENT, + PIPE_BUFFER_USAGE_CONSTANT | PIPE_BUFFER_USAGE_DISCARD, + sizeof(struct vlVertexShaderConsts) + ); + + mc->fs_const_buf.buffer = pipe_buffer_create + ( + pipe->screen, + DEFAULT_BUF_ALIGNMENT, + PIPE_BUFFER_USAGE_CONSTANT, + sizeof(struct vlFragmentShaderConsts) + ); + + memcpy + ( + pipe_buffer_map(pipe->screen, mc->fs_const_buf.buffer, PIPE_BUFFER_USAGE_CPU_WRITE), + &fs_consts, + sizeof(struct vlFragmentShaderConsts) + ); + + pipe_buffer_unmap(pipe->screen, mc->fs_const_buf.buffer); + + mc->macroblocks = MALLOC(sizeof(struct vlMpeg2MacroBlock) * mc->macroblocks_per_picture); + + return 0; +} + +static int vlInit +( + struct vlR16SnormBufferedMC *mc +) +{ + struct pipe_context *pipe; + struct pipe_sampler_state sampler; + struct pipe_texture template; + unsigned int filters[5]; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + + mc->buffered_surface = NULL; + mc->past_surface = NULL; + mc->future_surface = NULL; + for (i = 0; i < 3; ++i) + mc->zero_block[i].x = -1.0f; + mc->num_macroblocks = 0; + + /* For MC we render to textures, which are rounded up to nearest POT */ + mc->viewport.scale[0] = vlRoundUpPOT(mc->picture_width); + mc->viewport.scale[1] = vlRoundUpPOT(mc->picture_height); + mc->viewport.scale[2] = 1; + mc->viewport.scale[3] = 1; + mc->viewport.translate[0] = 0; + mc->viewport.translate[1] = 0; + mc->viewport.translate[2] = 0; + mc->viewport.translate[3] = 0; + + mc->render_target.width = vlRoundUpPOT(mc->picture_width); + mc->render_target.height = vlRoundUpPOT(mc->picture_height); + mc->render_target.nr_cbufs = 1; + /* FB for MC stage is a vlSurface created by the user, set at render time */ + mc->render_target.zsbuf = NULL; + + filters[0] = PIPE_TEX_FILTER_NEAREST; + /* FIXME: Linear causes discoloration around block edges */ + filters[1] = /*mc->picture_format == vlFormatYCbCr444 ?*/ PIPE_TEX_FILTER_NEAREST /*: PIPE_TEX_FILTER_LINEAR*/; + filters[2] = /*mc->picture_format == vlFormatYCbCr444 ?*/ PIPE_TEX_FILTER_NEAREST /*: PIPE_TEX_FILTER_LINEAR*/; + filters[3] = PIPE_TEX_FILTER_LINEAR; + filters[4] = PIPE_TEX_FILTER_LINEAR; + + for (i = 0; i < 5; ++i) + { + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.min_img_filter = filters[i]; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = filters[i]; + sampler.compare_mode = PIPE_TEX_COMPARE_NONE; + sampler.compare_func = PIPE_FUNC_ALWAYS; + sampler.normalized_coords = 1; + /*sampler.prefilter = ;*/ + /*sampler.lod_bias = ;*/ + sampler.min_lod = 0; + /*sampler.max_lod = ;*/ + /*sampler.border_color[i] = ;*/ + /*sampler.max_anisotropy = ;*/ + mc->samplers.all[i] = pipe->create_sampler_state(pipe, &sampler); + } + + memset(&template, 0, sizeof(struct pipe_texture)); + template.target = PIPE_TEXTURE_2D; + template.format = PIPE_FORMAT_R16_SNORM; + template.last_level = 0; + template.width[0] = vlRoundUpPOT(mc->picture_width); + template.height[0] = vlRoundUpPOT(mc->picture_height); + template.depth[0] = 1; + pf_get_block(template.format, &template.block); + template.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER | PIPE_TEXTURE_USAGE_DYNAMIC; + + mc->textures.y = pipe->screen->texture_create(pipe->screen, &template); + + if (mc->picture_format == vlFormatYCbCr420) + { + template.width[0] = vlRoundUpPOT(mc->picture_width / 2); + template.height[0] = vlRoundUpPOT(mc->picture_height / 2); + } + else if (mc->picture_format == vlFormatYCbCr422) + template.height[0] = vlRoundUpPOT(mc->picture_height / 2); + + mc->textures.cb = pipe->screen->texture_create(pipe->screen, &template); + mc->textures.cr = pipe->screen->texture_create(pipe->screen, &template); + + /* textures.all[3] & textures.all[4] are assigned from vlSurfaces for P and B macroblocks at render time */ + + vlCreateVertexShaderIMB(mc); + vlCreateFragmentShaderIMB(mc); + vlCreateVertexShaderFramePMB(mc); + vlCreateVertexShaderFieldPMB(mc); + vlCreateFragmentShaderFramePMB(mc); + vlCreateFragmentShaderFieldPMB(mc); + vlCreateVertexShaderFrameBMB(mc); + vlCreateVertexShaderFieldBMB(mc); + vlCreateFragmentShaderFrameBMB(mc); + vlCreateFragmentShaderFieldBMB(mc); + vlCreateDataBufs(mc); + + return 0; +} + +int vlCreateR16SNormBufferedMC +( + struct pipe_context *pipe, + unsigned int picture_width, + unsigned int picture_height, + enum vlFormat picture_format, + struct vlRender **render +) +{ + struct vlR16SnormBufferedMC *mc; + + assert(pipe); + assert(render); + + mc = CALLOC_STRUCT(vlR16SnormBufferedMC); + + mc->base.vlBegin = &vlBegin; + mc->base.vlRenderMacroBlocksMpeg2 = &vlRenderMacroBlocksMpeg2R16SnormBuffered; + mc->base.vlEnd = &vlEnd; + mc->base.vlFlush = &vlFlush; + mc->base.vlDestroy = &vlDestroy; + mc->pipe = pipe; + mc->picture_width = picture_width; + mc->picture_height = picture_height; + + vlInit(mc); + + *render = &mc->base; + + return 0; +} diff --git a/src/gallium/state_trackers/g3dvl/vl_r16snorm_mc_buf.h b/src/gallium/state_trackers/g3dvl/vl_r16snorm_mc_buf.h new file mode 100644 index 0000000000..27177d64ca --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_r16snorm_mc_buf.h @@ -0,0 +1,18 @@ +#ifndef vl_r16snorm_mc_buf_h +#define vl_r16snorm_mc_buf_h + +#include "vl_types.h" + +struct pipe_context; +struct vlRender; + +int vlCreateR16SNormBufferedMC +( + struct pipe_context *pipe, + unsigned int picture_width, + unsigned int picture_height, + enum vlFormat picture_format, + struct vlRender **render +); + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_r16snorm_mc_buf_shaders.inc b/src/gallium/state_trackers/g3dvl/vl_r16snorm_mc_buf_shaders.inc new file mode 100644 index 0000000000..ef4a4b2add --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_r16snorm_mc_buf_shaders.inc @@ -0,0 +1,1185 @@ +static int vlCreateVertexShaderIMB +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int max_tokens = 50; + + struct pipe_context *pipe; + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_VERTEX, header); + + ti = 3; + + /* + * decl i0 ; Vertex pos + * decl i1 ; Luma texcoords + * decl i2 ; Chroma Cb texcoords + * decl i3 ; Chroma Cr texcoords + */ + for (i = 0; i < 4; i++) + { + decl = vl_decl_input(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * decl o0 ; Vertex pos + * decl o1 ; Luma texcoords + * decl o2 ; Chroma Cb texcoords + * decl o3 ; Chroma Cr texcoords + */ + for (i = 0; i < 4; i++) + { + decl = vl_decl_output(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * mov o0, i0 ; Move input vertex pos to output + * mov o1, i1 ; Move input luma texcoords to output + * mov o2, i2 ; Move input chroma Cb texcoords to output + * mov o3, i3 ; Move input chroma Cr texcoords to output + */ + for (i = 0; i < 4; ++i) + { + inst = vl_inst2(TGSI_OPCODE_MOV, TGSI_FILE_OUTPUT, i, TGSI_FILE_INPUT, i); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + vs.tokens = tokens; + mc->i_vs = pipe->create_vs_state(pipe, &vs); + free(tokens); + + return 0; +} + +static int vlCreateFragmentShaderIMB +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int max_tokens = 100; + + struct pipe_context *pipe; + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_FRAGMENT, header); + + ti = 3; + + /* + * decl i0 ; Luma texcoords + * decl i1 ; Chroma Cb texcoords + * decl i2 ; Chroma Cr texcoords + */ + for (i = 0; i < 3; ++i) + { + decl = vl_decl_interpolated_input(TGSI_SEMANTIC_GENERIC, i + 1, i, i, TGSI_INTERPOLATE_LINEAR); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* decl c0 ; Scaling factor, rescales 16-bit snorm to 9-bit snorm */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl o0 ; Fragment color */ + decl = vl_decl_output(TGSI_SEMANTIC_COLOR, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl t0, t1 */ + decl = vl_decl_temps(0, 1); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl s0 ; Sampler for luma texture + * decl s1 ; Sampler for chroma Cb texture + * decl s2 ; Sampler for chroma Cr texture + */ + for (i = 0; i < 3; ++i) + { + decl = vl_decl_samplers(i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header,max_tokens - ti); + } + + /* + * tex2d t1, i0, s0 ; Read texel from luma texture + * mov t0.x, t1.x ; Move luma sample into .x component + * tex2d t1, i1, s1 ; Read texel from chroma Cb texture + * mov t0.y, t1.x ; Move Cb sample into .y component + * tex2d t1, i2, s2 ; Read texel from chroma Cr texture + * mov t0.z, t1.x ; Move Cr sample into .z component + */ + for (i = 0; i < 3; ++i) + { + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_INPUT, i, TGSI_FILE_SAMPLER, i); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + inst = vl_inst2(TGSI_OPCODE_MOV, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 1); + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* mul o0, t0, c0 ; Rescale texel to correct range */ + inst = vl_inst3(TGSI_OPCODE_MUL, TGSI_FILE_OUTPUT, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + fs.tokens = tokens; + mc->i_fs = pipe->create_fs_state(pipe, &fs); + free(tokens); + + return 0; +} + +static int vlCreateVertexShaderFramePMB +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int max_tokens = 100; + + struct pipe_context *pipe; + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_VERTEX, header); + + ti = 3; + + /* + * decl i0 ; Vertex pos + * decl i1 ; Luma texcoords + * decl i2 ; Chroma Cb texcoords + * decl i3 ; Chroma Cr texcoords + * decl i4 ; Ref surface top field texcoords + * decl i5 ; Ref surface bottom field texcoords (unused, packed in the same stream) + */ + for (i = 0; i < 6; i++) + { + decl = vl_decl_input(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * decl o0 ; Vertex pos + * decl o1 ; Luma texcoords + * decl o2 ; Chroma Cb texcoords + * decl o3 ; Chroma Cr texcoords + * decl o4 ; Ref macroblock texcoords + */ + for (i = 0; i < 5; i++) + { + decl = vl_decl_output(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * mov o0, i0 ; Move input vertex pos to output + * mov o1, i1 ; Move input luma texcoords to output + * mov o2, i2 ; Move input chroma Cb texcoords to output + * mov o3, i3 ; Move input chroma Cr texcoords to output + */ + for (i = 0; i < 4; ++i) + { + inst = vl_inst2(TGSI_OPCODE_MOV, TGSI_FILE_OUTPUT, i, TGSI_FILE_INPUT, i); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* add o4, i0, i4 ; Translate vertex pos by motion vec to form ref macroblock texcoords */ + inst = vl_inst3(TGSI_OPCODE_ADD, TGSI_FILE_OUTPUT, 4, TGSI_FILE_INPUT, 0, TGSI_FILE_INPUT, 4); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + vs.tokens = tokens; + mc->p_vs[0] = pipe->create_vs_state(pipe, &vs); + free(tokens); + + return 0; +} + +static int vlCreateVertexShaderFieldPMB +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int max_tokens = 100; + + struct pipe_context *pipe; + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_VERTEX, header); + + ti = 3; + + /* + * decl i0 ; Vertex pos + * decl i1 ; Luma texcoords + * decl i2 ; Chroma Cb texcoords + * decl i3 ; Chroma Cr texcoords + * decl i4 ; Ref macroblock top field texcoords + * decl i5 ; Ref macroblock bottom field texcoords + */ + for (i = 0; i < 6; i++) + { + decl = vl_decl_input(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* decl c0 ; Render target dimensions */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl o0 ; Vertex pos + * decl o1 ; Luma texcoords + * decl o2 ; Chroma Cb texcoords + * decl o3 ; Chroma Cr texcoords + * decl o4 ; Ref macroblock top field texcoords + * decl o5 ; Ref macroblock bottom field texcoords + * decl o6 ; Denormalized vertex pos + */ + for (i = 0; i < 7; i++) + { + decl = vl_decl_output(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * mov o0, i0 ; Move input vertex pos to output + * mov o1, i1 ; Move input luma texcoords to output + * mov o2, i2 ; Move input chroma Cb texcoords to output + * mov o3, i3 ; Move input chroma Cr texcoords to output + */ + for (i = 0; i < 4; ++i) + { + inst = vl_inst2(TGSI_OPCODE_MOV, TGSI_FILE_OUTPUT, i, TGSI_FILE_INPUT, i); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* + * add o4, i0, i4 ; Translate vertex pos by motion vec to form top field macroblock texcoords + * add o5, i0, i5 ; Translate vertex pos by motion vec to form bottom field macroblock texcoords + */ + for (i = 0; i < 2; ++i) + { + inst = vl_inst3(TGSI_OPCODE_ADD, TGSI_FILE_OUTPUT, i + 4, TGSI_FILE_INPUT, 0, TGSI_FILE_INPUT, i + 4); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* mul o6, i0, c0 ; Denorm vertex pos */ + inst = vl_inst3(TGSI_OPCODE_MUL, TGSI_FILE_OUTPUT, 6, TGSI_FILE_INPUT, 0, TGSI_FILE_CONSTANT, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + vs.tokens = tokens; + mc->p_vs[1] = pipe->create_vs_state(pipe, &vs); + free(tokens); + + return 0; +} + +static int vlCreateFragmentShaderFramePMB +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int max_tokens = 100; + + struct pipe_context *pipe; + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_FRAGMENT, header); + + ti = 3; + + /* + * decl i0 ; Luma texcoords + * decl i1 ; Chroma Cb texcoords + * decl i2 ; Chroma Cr texcoords + * decl i3 ; Ref macroblock texcoords + */ + for (i = 0; i < 4; ++i) + { + decl = vl_decl_interpolated_input(TGSI_SEMANTIC_GENERIC, i + 1, i, i, TGSI_INTERPOLATE_LINEAR); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* decl c0 ; Scaling factor, rescales 16-bit snorm to 9-bit snorm */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl o0 ; Fragment color */ + decl = vl_decl_output(TGSI_SEMANTIC_COLOR, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl t0, t1 */ + decl = vl_decl_temps(0, 1); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl s0 ; Sampler for luma texture + * decl s1 ; Sampler for chroma Cb texture + * decl s2 ; Sampler for chroma Cr texture + * decl s3 ; Sampler for ref surface texture + */ + for (i = 0; i < 4; ++i) + { + decl = vl_decl_samplers(i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * tex2d t1, i0, s0 ; Read texel from luma texture + * mov t0.x, t1.x ; Move luma sample into .x component + * tex2d t1, i1, s1 ; Read texel from chroma Cb texture + * mov t0.y, t1.x ; Move Cb sample into .y component + * tex2d t1, i2, s2 ; Read texel from chroma Cr texture + * mov t0.z, t1.x ; Move Cr sample into .z component + */ + for (i = 0; i < 3; ++i) + { + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_INPUT, i, TGSI_FILE_SAMPLER, i); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + inst = vl_inst2(TGSI_OPCODE_MOV, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 1); + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* mul t0, t0, c0 ; Rescale texel to correct range */ + inst = vl_inst3(TGSI_OPCODE_MUL, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* tex2d t1, i3, s3 ; Read texel from ref macroblock */ + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_INPUT, 3, TGSI_FILE_SAMPLER, 3); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* add o0, t0, t1 ; Add ref and differential to form final output */ + inst = vl_inst3(TGSI_OPCODE_ADD, TGSI_FILE_OUTPUT, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 1); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + fs.tokens = tokens; + mc->p_fs[0] = pipe->create_fs_state(pipe, &fs); + free(tokens); + + return 0; +} + +static int vlCreateFragmentShaderFieldPMB +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int max_tokens = 200; + + struct pipe_context *pipe; + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_FRAGMENT, header); + + ti = 3; + + /* + * decl i0 ; Luma texcoords + * decl i1 ; Chroma Cb texcoords + * decl i2 ; Chroma Cr texcoords + * decl i3 ; Ref macroblock top field texcoords + * decl i4 ; Ref macroblock bottom field texcoords + * decl i5 ; Denormalized vertex pos + */ + for (i = 0; i < 6; ++i) + { + decl = vl_decl_interpolated_input(TGSI_SEMANTIC_GENERIC, i + 1, i, i, TGSI_INTERPOLATE_LINEAR); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * decl c0 ; Scaling factor, rescales 16-bit snorm to 9-bit snorm + * decl c1 ; Constants 1/2 & 2 in .x, .y channels for Y-mod-2 top/bottom field selection + */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 1); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl o0 ; Fragment color */ + decl = vl_decl_output(TGSI_SEMANTIC_COLOR, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl t0-t4 */ + decl = vl_decl_temps(0, 4); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl s0 ; Sampler for luma texture + * decl s1 ; Sampler for chroma Cb texture + * decl s2 ; Sampler for chroma Cr texture + * decl s3 ; Sampler for ref surface texture + */ + for (i = 0; i < 4; ++i) + { + decl = vl_decl_samplers(i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * tex2d t1, i0, s0 ; Read texel from luma texture + * mov t0.x, t1.x ; Move luma sample into .x component + * tex2d t1, i1, s1 ; Read texel from chroma Cb texture + * mov t0.y, t1.x ; Move Cb sample into .y component + * tex2d t1, i2, s2 ; Read texel from chroma Cr texture + * mov t0.z, t1.x ; Move Cr sample into .z component + */ + for (i = 0; i < 3; ++i) + { + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_INPUT, i, TGSI_FILE_SAMPLER, i); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + inst = vl_inst2(TGSI_OPCODE_MOV, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 1); + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* mul t0, t0, c0 ; Rescale texel to correct range */ + inst = vl_inst3(TGSI_OPCODE_MUL, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* + * tex2d t1, i3, s3 ; Read texel from ref macroblock top field + * tex2d t2, i4, s3 ; Read texel from ref macroblock bottom field + */ + for (i = 0; i < 2; ++i) + { + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, i + 1, TGSI_FILE_INPUT, i + 3, TGSI_FILE_SAMPLER, 3); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* XXX: Pos values off by 0.5? */ + /* sub t4, i5.y, c1.x ; Sub 0.5 from denormalized pos */ + inst = vl_inst3(TGSI_OPCODE_SUB, TGSI_FILE_TEMPORARY, 4, TGSI_FILE_INPUT, 5, TGSI_FILE_CONSTANT, 1); + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[0].SrcRegister.SwizzleW = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[1].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleW = TGSI_SWIZZLE_X; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* mul t3, t4, c1.x ; Multiply pos Y-coord by 1/2 */ + inst = vl_inst3(TGSI_OPCODE_MUL, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 4, TGSI_FILE_CONSTANT, 1); + inst.FullSrcRegisters[1].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleW = TGSI_SWIZZLE_X; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* floor t3, t3 ; Get rid of fractional part */ + inst = vl_inst2(TGSI_OPCODE_FLOOR, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 3); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* mul t3, t3, c1.y ; Multiply by 2 */ + inst = vl_inst3(TGSI_OPCODE_MUL, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_CONSTANT, 1); + inst.FullSrcRegisters[1].SrcRegister.SwizzleX = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[1].SrcRegister.SwizzleY = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[1].SrcRegister.SwizzleZ = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[1].SrcRegister.SwizzleW = TGSI_SWIZZLE_Y; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* sub t3, t4, t3 ; Subtract from original Y to get Y % 2 */ + inst = vl_inst3(TGSI_OPCODE_SUB, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 4, TGSI_FILE_TEMPORARY, 3); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* TODO: Move to conditional tex fetch on t3 instead of lerp */ + /* lerp t1, t3, t1, t2 ; Choose between top and bottom fields based on Y % 2 */ + inst = vl_inst4(TGSI_OPCODE_LERP, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_TEMPORARY, 2); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* add o0, t0, t1 ; Add ref and differential to form final output */ + inst = vl_inst3(TGSI_OPCODE_ADD, TGSI_FILE_OUTPUT, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 1); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + fs.tokens = tokens; + mc->p_fs[1] = pipe->create_fs_state(pipe, &fs); + free(tokens); + + return 0; +} + +static int vlCreateVertexShaderFrameBMB +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int max_tokens = 100; + + struct pipe_context *pipe; + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_VERTEX, header); + + ti = 3; + + /* + * decl i0 ; Vertex pos + * decl i1 ; Luma texcoords + * decl i2 ; Chroma Cb texcoords + * decl i3 ; Chroma Cr texcoords + * decl i4 ; First ref macroblock top field texcoords + * decl i5 ; First ref macroblock bottom field texcoords (unused, packed in the same stream) + * decl i6 ; Second ref macroblock top field texcoords + * decl i7 ; Second ref macroblock bottom field texcoords (unused, packed in the same stream) + */ + for (i = 0; i < 8; i++) + { + decl = vl_decl_input(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * decl o0 ; Vertex pos + * decl o1 ; Luma texcoords + * decl o2 ; Chroma Cb texcoords + * decl o3 ; Chroma Cr texcoords + * decl o4 ; First ref macroblock texcoords + * decl o5 ; Second ref macroblock texcoords + */ + for (i = 0; i < 6; i++) + { + decl = vl_decl_output(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * mov o0, i0 ; Move input vertex pos to output + * mov o1, i1 ; Move input luma texcoords to output + * mov o2, i2 ; Move input chroma Cb texcoords to output + * mov o3, i3 ; Move input chroma Cr texcoords to output + */ + for (i = 0; i < 4; ++i) + { + inst = vl_inst2(TGSI_OPCODE_MOV, TGSI_FILE_OUTPUT, i, TGSI_FILE_INPUT, i); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* + * add o4, i0, i4 ; Translate vertex pos by motion vec to form first ref macroblock texcoords + * add o5, i0, i6 ; Translate vertex pos by motion vec to form second ref macroblock texcoords + */ + for (i = 0; i < 2; ++i) + { + inst = vl_inst3(TGSI_OPCODE_ADD, TGSI_FILE_OUTPUT, i + 4, TGSI_FILE_INPUT, 0, TGSI_FILE_INPUT, (i + 2) * 2); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + vs.tokens = tokens; + mc->b_vs[0] = pipe->create_vs_state(pipe, &vs); + free(tokens); + + return 0; +} + +static int vlCreateVertexShaderFieldBMB +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int max_tokens = 100; + + struct pipe_context *pipe; + struct pipe_shader_state vs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_VERTEX, header); + + ti = 3; + + /* + * decl i0 ; Vertex pos + * decl i1 ; Luma texcoords + * decl i2 ; Chroma Cb texcoords + * decl i3 ; Chroma Cr texcoords + * decl i4 ; First ref macroblock top field texcoords + * decl i5 ; First ref macroblock bottom field texcoords + * decl i6 ; Second ref macroblock top field texcoords + * decl i7 ; Second ref macroblock bottom field texcoords + */ + for (i = 0; i < 8; i++) + { + decl = vl_decl_input(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* decl c0 ; Render target dimensions */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl o0 ; Vertex pos + * decl o1 ; Luma texcoords + * decl o2 ; Chroma Cb texcoords + * decl o3 ; Chroma Cr texcoords + * decl o4 ; First ref macroblock top field texcoords + * decl o5 ; First ref macroblock Bottom field texcoords + * decl o6 ; Second ref macroblock top field texcoords + * decl o7 ; Second ref macroblock Bottom field texcoords + * decl o8 ; Denormalized vertex pos + */ + for (i = 0; i < 9; i++) + { + decl = vl_decl_output(i == 0 ? TGSI_SEMANTIC_POSITION : TGSI_SEMANTIC_GENERIC, i, i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* decl t0, t1 */ + decl = vl_decl_temps(0, 1); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * mov o0, i0 ; Move input vertex pos to output + * mov o1, i1 ; Move input luma texcoords to output + * mov o2, i2 ; Move input chroma Cb texcoords to output + * mov o3, i3 ; Move input chroma Cr texcoords to output + */ + for (i = 0; i < 4; ++i) + { + inst = vl_inst2(TGSI_OPCODE_MOV, TGSI_FILE_OUTPUT, i, TGSI_FILE_INPUT, i); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* + * add o4, i0, i4 ; Translate vertex pos by motion vec to form first top field macroblock texcoords + * add o5, i0, i5 ; Translate vertex pos by motion vec to form first bottom field macroblock texcoords + * add o6, i0, i6 ; Translate vertex pos by motion vec to form second top field macroblock texcoords + * add o7, i0, i7 ; Translate vertex pos by motion vec to form second bottom field macroblock texcoords + */ + for (i = 0; i < 4; ++i) + { + inst = vl_inst3(TGSI_OPCODE_ADD, TGSI_FILE_OUTPUT, i + 4, TGSI_FILE_INPUT, 0, TGSI_FILE_INPUT, i + 4); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* mul o8, i0, c0 ; Denorm vertex pos */ + inst = vl_inst3(TGSI_OPCODE_MUL, TGSI_FILE_OUTPUT, 8, TGSI_FILE_INPUT, 0, TGSI_FILE_CONSTANT, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + vs.tokens = tokens; + mc->b_vs[1] = pipe->create_vs_state(pipe, &vs); + free(tokens); + + return 0; +} + +static int vlCreateFragmentShaderFrameBMB +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int max_tokens = 100; + + struct pipe_context *pipe; + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_FRAGMENT, header); + + ti = 3; + + /* + * decl i0 ; Luma texcoords + * decl i1 ; Chroma Cb texcoords + * decl i2 ; Chroma Cr texcoords + * decl i3 ; First ref macroblock texcoords + * decl i4 ; Second ref macroblock texcoords + */ + for (i = 0; i < 5; ++i) + { + decl = vl_decl_interpolated_input(TGSI_SEMANTIC_GENERIC, i + 1, i, i, TGSI_INTERPOLATE_LINEAR); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * decl c0 ; Scaling factor, rescales 16-bit snorm to 9-bit snorm + * decl c1 ; Constant 1/2 in .x channel to use as weight to blend past and future texels + */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 1); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl o0 ; Fragment color */ + decl = vl_decl_output(TGSI_SEMANTIC_COLOR, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl t0-t2 */ + decl = vl_decl_temps(0, 2); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl s0 ; Sampler for luma texture + * decl s1 ; Sampler for chroma Cb texture + * decl s2 ; Sampler for chroma Cr texture + * decl s3 ; Sampler for first ref surface texture + * decl s4 ; Sampler for second ref surface texture + */ + for (i = 0; i < 5; ++i) + { + decl = vl_decl_samplers(i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * tex2d t1, i0, s0 ; Read texel from luma texture + * mov t0.x, t1.x ; Move luma sample into .x component + * tex2d t1, i1, s1 ; Read texel from chroma Cb texture + * mov t0.y, t1.x ; Move Cb sample into .y component + * tex2d t1, i2, s2 ; Read texel from chroma Cr texture + * mov t0.z, t1.x ; Move Cr sample into .z component + */ + for (i = 0; i < 3; ++i) + { + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_INPUT, i, TGSI_FILE_SAMPLER, i); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + inst = vl_inst2(TGSI_OPCODE_MOV, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 1); + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* mul t0, t0, c0 ; Rescale texel to correct range */ + inst = vl_inst3(TGSI_OPCODE_MUL, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* + * tex2d t1, i3, s3 ; Read texel from first ref macroblock + * tex2d t2, i4, s4 ; Read texel from second ref macroblock + */ + for (i = 0; i < 2; ++i) + { + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, i + 1, TGSI_FILE_INPUT, i + 3, TGSI_FILE_SAMPLER, i + 3); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* lerp t1, c1.x, t1, t2 ; Blend past and future texels */ + inst = vl_inst4(TGSI_OPCODE_LERP, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_CONSTANT, 1, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_TEMPORARY, 2); + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleW = TGSI_SWIZZLE_X; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* add o0, t0, t1 ; Add past/future ref and differential to form final output */ + inst = vl_inst3(TGSI_OPCODE_ADD, TGSI_FILE_OUTPUT, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 1); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + fs.tokens = tokens; + mc->b_fs[0] = pipe->create_fs_state(pipe, &fs); + free(tokens); + + return 0; +} + +static int vlCreateFragmentShaderFieldBMB +( + struct vlR16SnormBufferedMC *mc +) +{ + const unsigned int max_tokens = 200; + + struct pipe_context *pipe; + struct pipe_shader_state fs; + struct tgsi_token *tokens; + struct tgsi_header *header; + + struct tgsi_full_declaration decl; + struct tgsi_full_instruction inst; + + unsigned int ti; + unsigned int i; + + assert(mc); + + pipe = mc->pipe; + tokens = (struct tgsi_token*)malloc(max_tokens * sizeof(struct tgsi_token)); + + /* Version */ + *(struct tgsi_version*)&tokens[0] = tgsi_build_version(); + /* Header */ + header = (struct tgsi_header*)&tokens[1]; + *header = tgsi_build_header(); + /* Processor */ + *(struct tgsi_processor*)&tokens[2] = tgsi_build_processor(TGSI_PROCESSOR_FRAGMENT, header); + + ti = 3; + + /* + * decl i0 ; Luma texcoords + * decl i1 ; Chroma Cb texcoords + * decl i2 ; Chroma Cr texcoords + * decl i3 ; First ref macroblock top field texcoords + * decl i4 ; First ref macroblock bottom field texcoords + * decl i5 ; Second ref macroblock top field texcoords + * decl i6 ; Second ref macroblock bottom field texcoords + * decl i7 ; Denormalized vertex pos + */ + for (i = 0; i < 8; ++i) + { + decl = vl_decl_interpolated_input(TGSI_SEMANTIC_GENERIC, i + 1, i, i, TGSI_INTERPOLATE_LINEAR); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * decl c0 ; Scaling factor, rescales 16-bit snorm to 9-bit snorm + * decl c1 ; Constants 1/2 & 2 in .x, .y channels to use as weight to blend past and future texels + * ; and for Y-mod-2 top/bottom field selection + */ + decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 1); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl o0 ; Fragment color */ + decl = vl_decl_output(TGSI_SEMANTIC_COLOR, 0, 0, 0); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* decl t0-t5 */ + decl = vl_decl_temps(0, 5); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + + /* + * decl s0 ; Sampler for luma texture + * decl s1 ; Sampler for chroma Cb texture + * decl s2 ; Sampler for chroma Cr texture + * decl s3 ; Sampler for first ref surface texture + * decl s4 ; Sampler for second ref surface texture + */ + for (i = 0; i < 5; ++i) + { + decl = vl_decl_samplers(i, i); + ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti); + } + + /* + * tex2d t1, i0, s0 ; Read texel from luma texture + * mov t0.x, t1.x ; Move luma sample into .x component + * tex2d t1, i1, s1 ; Read texel from chroma Cb texture + * mov t0.y, t1.x ; Move Cb sample into .y component + * tex2d t1, i2, s2 ; Read texel from chroma Cr texture + * mov t0.z, t1.x ; Move Cr sample into .z component + */ + for (i = 0; i < 3; ++i) + { + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_INPUT, i, TGSI_FILE_SAMPLER, i); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + inst = vl_inst2(TGSI_OPCODE_MOV, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 1); + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* mul t0, t0, c0 ; Rescale texel to correct range */ + inst = vl_inst3(TGSI_OPCODE_MUL, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, 0); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* XXX: Pos values off by 0.5? */ + /* sub t4, i7.y, c1.x ; Sub 0.5 from denormalized pos */ + inst = vl_inst3(TGSI_OPCODE_SUB, TGSI_FILE_TEMPORARY, 4, TGSI_FILE_INPUT, 7, TGSI_FILE_CONSTANT, 1); + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[0].SrcRegister.SwizzleW = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[1].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleW = TGSI_SWIZZLE_X; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* mul t3, t4, c1.x ; Multiply pos Y-coord by 1/2 */ + inst = vl_inst3(TGSI_OPCODE_MUL, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 4, TGSI_FILE_CONSTANT, 1); + inst.FullSrcRegisters[1].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[1].SrcRegister.SwizzleW = TGSI_SWIZZLE_X; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* floor t3, t3 ; Get rid of fractional part */ + inst = vl_inst2(TGSI_OPCODE_FLOOR, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 3); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* mul t3, t3, c1.y ; Multiply by 2 */ + inst = vl_inst3( TGSI_OPCODE_MUL, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_CONSTANT, 1); + inst.FullSrcRegisters[1].SrcRegister.SwizzleX = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[1].SrcRegister.SwizzleY = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[1].SrcRegister.SwizzleZ = TGSI_SWIZZLE_Y; + inst.FullSrcRegisters[1].SrcRegister.SwizzleW = TGSI_SWIZZLE_Y; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* sub t3, t4, t3 ; Subtract from original Y to get Y % 2 */ + inst = vl_inst3(TGSI_OPCODE_SUB, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 4, TGSI_FILE_TEMPORARY, 3); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* + * tex2d t1, i3, s3 ; Read texel from past ref macroblock top field + * tex2d t2, i4, s3 ; Read texel from past ref macroblock bottom field + */ + for (i = 0; i < 2; ++i) + { + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, i + 1, TGSI_FILE_INPUT, i + 3, TGSI_FILE_SAMPLER, 3); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* TODO: Move to conditional tex fetch on t3 instead of lerp */ + /* lerp t1, t3, t1, t2 ; Choose between top and bottom fields based on Y % 2 */ + inst = vl_inst4(TGSI_OPCODE_LERP, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_TEMPORARY, 2); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* + * tex2d t4, i5, s4 ; Read texel from future ref macroblock top field + * tex2d t5, i6, s4 ; Read texel from future ref macroblock bottom field + */ + for (i = 0; i < 2; ++i) + { + inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, i + 4, TGSI_FILE_INPUT, i + 5, TGSI_FILE_SAMPLER, 4); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + } + + /* TODO: Move to conditional tex fetch on t3 instead of lerp */ + /* lerp t2, t3, t4, t5 ; Choose between top and bottom fields based on Y % 2 */ + inst = vl_inst4(TGSI_OPCODE_LERP, TGSI_FILE_TEMPORARY, 2, TGSI_FILE_TEMPORARY, 3, TGSI_FILE_TEMPORARY, 4, TGSI_FILE_TEMPORARY, 5); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* lerp t1, c1.x, t1, t2 ; Blend past and future texels */ + inst = vl_inst4(TGSI_OPCODE_LERP, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_CONSTANT, 1, TGSI_FILE_TEMPORARY, 1, TGSI_FILE_TEMPORARY, 2); + inst.FullSrcRegisters[0].SrcRegister.SwizzleX = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleY = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleZ = TGSI_SWIZZLE_X; + inst.FullSrcRegisters[0].SrcRegister.SwizzleW = TGSI_SWIZZLE_X; + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* add o0, t0, t1 ; Add past/future ref and differential to form final output */ + inst = vl_inst3(TGSI_OPCODE_ADD, TGSI_FILE_OUTPUT, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 1); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + /* end */ + inst = vl_end(); + ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti); + + fs.tokens = tokens; + mc->b_fs[1] = pipe->create_fs_state(pipe, &fs); + free(tokens); + + return 0; +} diff --git a/src/gallium/state_trackers/g3dvl/vl_render.h b/src/gallium/state_trackers/g3dvl/vl_render.h new file mode 100644 index 0000000000..166030b498 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_render.h @@ -0,0 +1,38 @@ +#ifndef vl_render_h +#define vl_render_h + +#include "vl_types.h" + +struct pipe_surface; + +struct vlRender +{ + int (*vlBegin) + ( + struct vlRender *render + ); + + int (*vlRenderMacroBlocksMpeg2) + ( + struct vlRender *render, + struct vlMpeg2MacroBlockBatch *batch, + struct vlSurface *surface + ); + + int (*vlEnd) + ( + struct vlRender *render + ); + + int (*vlFlush) + ( + struct vlRender *render + ); + + int (*vlDestroy) + ( + struct vlRender *render + ); +}; + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_screen.c b/src/gallium/state_trackers/g3dvl/vl_screen.c new file mode 100644 index 0000000000..ade8643a66 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_screen.c @@ -0,0 +1,115 @@ +#define VL_INTERNAL +#include "vl_screen.h" +#include <assert.h> +#include <util/u_memory.h> + +int vlCreateScreen +( + struct vlDisplay *display, + int screen, + struct pipe_screen *pscreen, + struct vlScreen **vl_screen +) +{ + struct vlScreen *scrn; + + assert(display); + assert(pscreen); + assert(vl_screen); + + scrn = CALLOC_STRUCT(vlScreen); + + if (!scrn) + return 1; + + scrn->display = display; + scrn->ordinal = screen; + scrn->pscreen = pscreen; + *vl_screen = scrn; + + return 0; +} + +int vlDestroyScreen +( + struct vlScreen *screen +) +{ + assert(screen); + + FREE(screen); + + return 0; +} + +struct vlDisplay* vlGetDisplay +( + struct vlScreen *screen +) +{ + assert(screen); + + return screen->display; +} + +struct pipe_screen* vlGetPipeScreen +( + struct vlScreen *screen +) +{ + assert(screen); + + return screen->pscreen; +} + +unsigned int vlGetMaxProfiles +( + struct vlScreen *screen +) +{ + assert(screen); + + return vlProfileCount; +} + +int vlQueryProfiles +( + struct vlScreen *screen, + enum vlProfile *profiles +) +{ + assert(screen); + assert(profiles); + + profiles[0] = vlProfileMpeg2Simple; + profiles[1] = vlProfileMpeg2Main; + + return 0; +} + +unsigned int vlGetMaxEntryPoints +( + struct vlScreen *screen +) +{ + assert(screen); + + return vlEntryPointCount; +} + +int vlQueryEntryPoints +( + struct vlScreen *screen, + enum vlProfile profile, + enum vlEntryPoint *entry_points +) +{ + assert(screen); + assert(entry_points); + + entry_points[0] = vlEntryPointIDCT; + entry_points[1] = vlEntryPointMC; + entry_points[2] = vlEntryPointCSC; + + return 0; +} diff --git a/src/gallium/state_trackers/g3dvl/vl_screen.h b/src/gallium/state_trackers/g3dvl/vl_screen.h new file mode 100644 index 0000000000..98f3d429b6 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_screen.h @@ -0,0 +1,63 @@ +#ifndef vl_screen_h +#define vl_screen_h + +#include "vl_types.h" + +struct pipe_screen; + +#ifdef VL_INTERNAL +struct vlScreen +{ + struct vlDisplay *display; + unsigned int ordinal; + struct pipe_screen *pscreen; +}; +#endif + +int vlCreateScreen +( + struct vlDisplay *display, + int screen, + struct pipe_screen *pscreen, + struct vlScreen **vl_screen +); + +int vlDestroyScreen +( + struct vlScreen *screen +); + +struct vlDisplay* vlGetDisplay +( + struct vlScreen *screen +); + +struct pipe_screen* vlGetPipeScreen +( + struct vlScreen *screen +); + +unsigned int vlGetMaxProfiles +( + struct vlScreen *screen +); + +int vlQueryProfiles +( + struct vlScreen *screen, + enum vlProfile *profiles +); + +unsigned int vlGetMaxEntryPoints +( + struct vlScreen *screen +); + +int vlQueryEntryPoints +( + struct vlScreen *screen, + enum vlProfile profile, + enum vlEntryPoint *entry_points +); + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_shader_build.c b/src/gallium/state_trackers/g3dvl/vl_shader_build.c new file mode 100644 index 0000000000..51f1721a33 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_shader_build.c @@ -0,0 +1,215 @@ +#include "vl_shader_build.h" +#include <assert.h> +#include <tgsi/tgsi_parse.h> +#include <tgsi/tgsi_build.h> + +struct tgsi_full_declaration vl_decl_input(unsigned int name, unsigned int index, unsigned int first, unsigned int last) +{ + struct tgsi_full_declaration decl = tgsi_default_full_declaration(); + + decl.Declaration.File = TGSI_FILE_INPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = name; + decl.Semantic.SemanticIndex = index; + decl.DeclarationRange.First = first; + decl.DeclarationRange.Last = last; + + return decl; +} + +struct tgsi_full_declaration vl_decl_interpolated_input +( + unsigned int name, + unsigned int index, + unsigned int first, + unsigned int last, + int interpolation +) +{ + struct tgsi_full_declaration decl = tgsi_default_full_declaration(); + + assert + ( + interpolation == TGSI_INTERPOLATE_CONSTANT || + interpolation == TGSI_INTERPOLATE_LINEAR || + interpolation == TGSI_INTERPOLATE_PERSPECTIVE + ); + + decl.Declaration.File = TGSI_FILE_INPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = name; + decl.Semantic.SemanticIndex = index; + decl.Declaration.Interpolate = interpolation;; + decl.DeclarationRange.First = first; + decl.DeclarationRange.Last = last; + + return decl; +} + +struct tgsi_full_declaration vl_decl_constants(unsigned int name, unsigned int index, unsigned int first, unsigned int last) +{ + struct tgsi_full_declaration decl = tgsi_default_full_declaration(); + + decl.Declaration.File = TGSI_FILE_CONSTANT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = name; + decl.Semantic.SemanticIndex = index; + decl.DeclarationRange.First = first; + decl.DeclarationRange.Last = last; + + return decl; +} + +struct tgsi_full_declaration vl_decl_output(unsigned int name, unsigned int index, unsigned int first, unsigned int last) +{ + struct tgsi_full_declaration decl = tgsi_default_full_declaration(); + + decl.Declaration.File = TGSI_FILE_OUTPUT; + decl.Declaration.Semantic = 1; + decl.Semantic.SemanticName = name; + decl.Semantic.SemanticIndex = index; + decl.DeclarationRange.First = first; + decl.DeclarationRange.Last = last; + + return decl; +} + +struct tgsi_full_declaration vl_decl_temps(unsigned int first, unsigned int last) +{ + struct tgsi_full_declaration decl = tgsi_default_full_declaration(); + + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_TEMPORARY; + decl.DeclarationRange.First = first; + decl.DeclarationRange.Last = last; + + return decl; +} + +struct tgsi_full_declaration vl_decl_samplers(unsigned int first, unsigned int last) +{ + struct tgsi_full_declaration decl = tgsi_default_full_declaration(); + + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_SAMPLER; + decl.DeclarationRange.First = first; + decl.DeclarationRange.Last = last; + + return decl; +} + +struct tgsi_full_instruction vl_inst2 +( + int opcode, + enum tgsi_file_type dst_file, + unsigned int dst_index, + enum tgsi_file_type src_file, + unsigned int src_index +) +{ + struct tgsi_full_instruction inst = tgsi_default_full_instruction(); + + inst.Instruction.Opcode = opcode; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = dst_file; + inst.FullDstRegisters[0].DstRegister.Index = dst_index; + inst.Instruction.NumSrcRegs = 1; + inst.FullSrcRegisters[0].SrcRegister.File = src_file; + inst.FullSrcRegisters[0].SrcRegister.Index = src_index; + + return inst; +} + +struct tgsi_full_instruction vl_inst3 +( + int opcode, + enum tgsi_file_type dst_file, + unsigned int dst_index, + enum tgsi_file_type src1_file, + unsigned int src1_index, + enum tgsi_file_type src2_file, + unsigned int src2_index +) +{ + struct tgsi_full_instruction inst = tgsi_default_full_instruction(); + + inst.Instruction.Opcode = opcode; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = dst_file; + inst.FullDstRegisters[0].DstRegister.Index = dst_index; + inst.Instruction.NumSrcRegs = 2; + inst.FullSrcRegisters[0].SrcRegister.File = src1_file; + inst.FullSrcRegisters[0].SrcRegister.Index = src1_index; + inst.FullSrcRegisters[1].SrcRegister.File = src2_file; + inst.FullSrcRegisters[1].SrcRegister.Index = src2_index; + + return inst; +} + +struct tgsi_full_instruction vl_tex +( + int tex, + enum tgsi_file_type dst_file, + unsigned int dst_index, + enum tgsi_file_type src1_file, + unsigned int src1_index, + enum tgsi_file_type src2_file, + unsigned int src2_index +) +{ + struct tgsi_full_instruction inst = tgsi_default_full_instruction(); + + inst.Instruction.Opcode = TGSI_OPCODE_TEX; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = dst_file; + inst.FullDstRegisters[0].DstRegister.Index = dst_index; + inst.Instruction.NumSrcRegs = 2; + inst.InstructionExtTexture.Texture = tex; + inst.FullSrcRegisters[0].SrcRegister.File = src1_file; + inst.FullSrcRegisters[0].SrcRegister.Index = src1_index; + inst.FullSrcRegisters[1].SrcRegister.File = src2_file; + inst.FullSrcRegisters[1].SrcRegister.Index = src2_index; + + return inst; +} + +struct tgsi_full_instruction vl_inst4 +( + int opcode, + enum tgsi_file_type dst_file, + unsigned int dst_index, + enum tgsi_file_type src1_file, + unsigned int src1_index, + enum tgsi_file_type src2_file, + unsigned int src2_index, + enum tgsi_file_type src3_file, + unsigned int src3_index +) +{ + struct tgsi_full_instruction inst = tgsi_default_full_instruction(); + + inst.Instruction.Opcode = opcode; + inst.Instruction.NumDstRegs = 1; + inst.FullDstRegisters[0].DstRegister.File = dst_file; + inst.FullDstRegisters[0].DstRegister.Index = dst_index; + inst.Instruction.NumSrcRegs = 3; + inst.FullSrcRegisters[0].SrcRegister.File = src1_file; + inst.FullSrcRegisters[0].SrcRegister.Index = src1_index; + inst.FullSrcRegisters[1].SrcRegister.File = src2_file; + inst.FullSrcRegisters[1].SrcRegister.Index = src2_index; + inst.FullSrcRegisters[2].SrcRegister.File = src3_file; + inst.FullSrcRegisters[2].SrcRegister.Index = src3_index; + + return inst; +} + +struct tgsi_full_instruction vl_end(void) +{ + struct tgsi_full_instruction inst = tgsi_default_full_instruction(); + + inst.Instruction.Opcode = TGSI_OPCODE_END; + inst.Instruction.NumDstRegs = 0; + inst.Instruction.NumSrcRegs = 0; + + return inst; +} diff --git a/src/gallium/state_trackers/g3dvl/vl_shader_build.h b/src/gallium/state_trackers/g3dvl/vl_shader_build.h new file mode 100644 index 0000000000..dc615cb156 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_shader_build.h @@ -0,0 +1,61 @@ +#ifndef vl_shader_build_h +#define vl_shader_build_h + +#include <pipe/p_shader_tokens.h> + +struct tgsi_full_declaration vl_decl_input(unsigned int name, unsigned int index, unsigned int first, unsigned int last); +struct tgsi_full_declaration vl_decl_interpolated_input +( + unsigned int name, + unsigned int index, + unsigned int first, + unsigned int last, + int interpolation +); +struct tgsi_full_declaration vl_decl_constants(unsigned int name, unsigned int index, unsigned int first, unsigned int last); +struct tgsi_full_declaration vl_decl_output(unsigned int name, unsigned int index, unsigned int first, unsigned int last); +struct tgsi_full_declaration vl_decl_temps(unsigned int first, unsigned int last); +struct tgsi_full_declaration vl_decl_samplers(unsigned int first, unsigned int last); +struct tgsi_full_instruction vl_inst2 +( + int opcode, + enum tgsi_file_type dst_file, + unsigned int dst_index, + enum tgsi_file_type src_file, + unsigned int src_index +); +struct tgsi_full_instruction vl_inst3 +( + int opcode, + enum tgsi_file_type dst_file, + unsigned int dst_index, + enum tgsi_file_type src1_file, + unsigned int src1_index, + enum tgsi_file_type src2_file, + unsigned int src2_index +); +struct tgsi_full_instruction vl_tex +( + int tex, + enum tgsi_file_type dst_file, + unsigned int dst_index, + enum tgsi_file_type src1_file, + unsigned int src1_index, + enum tgsi_file_type src2_file, + unsigned int src2_index +); +struct tgsi_full_instruction vl_inst4 +( + int opcode, + enum tgsi_file_type dst_file, + unsigned int dst_index, + enum tgsi_file_type src1_file, + unsigned int src1_index, + enum tgsi_file_type src2_file, + unsigned int src2_index, + enum tgsi_file_type src3_file, + unsigned int src3_index +); +struct tgsi_full_instruction vl_end(void); + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_surface.c b/src/gallium/state_trackers/g3dvl/vl_surface.c new file mode 100644 index 0000000000..7f60852cae --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_surface.c @@ -0,0 +1,242 @@ +#define VL_INTERNAL +#include "vl_surface.h" +#include <assert.h> +#include <string.h> +#include <pipe/p_screen.h> +#include <pipe/p_state.h> +#include <pipe/p_inlines.h> +#include <util/u_memory.h> +#include <vl_winsys.h> +#include "vl_screen.h" +#include "vl_context.h" +#include "vl_render.h" +#include "vl_csc.h" +#include "vl_util.h" + +int vlCreateSurface +( + struct vlScreen *screen, + unsigned int width, + unsigned int height, + enum vlFormat format, + struct vlSurface **surface +) +{ + struct vlSurface *sfc; + struct pipe_texture template; + + assert(screen); + assert(surface); + + sfc = CALLOC_STRUCT(vlSurface); + + if (!sfc) + return 1; + + sfc->screen = screen; + sfc->width = width; + sfc->height = height; + sfc->format = format; + + memset(&template, 0, sizeof(struct pipe_texture)); + template.target = PIPE_TEXTURE_2D; + template.format = PIPE_FORMAT_A8R8G8B8_UNORM; + template.last_level = 0; + template.width[0] = vlRoundUpPOT(sfc->width); + template.height[0] = vlRoundUpPOT(sfc->height); + template.depth[0] = 1; + pf_get_block(template.format, &template.block); + template.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER | PIPE_TEXTURE_USAGE_RENDER_TARGET; + + sfc->texture = vlGetPipeScreen(screen)->texture_create(vlGetPipeScreen(screen), &template); + + if (!sfc->texture) + { + FREE(sfc); + return 1; + } + + *surface = sfc; + + return 0; +} + +int vlDestroySurface +( + struct vlSurface *surface +) +{ + assert(surface); + + pipe_texture_reference(&surface->texture, NULL); + FREE(surface); + + return 0; +} + +int vlRenderMacroBlocksMpeg2 +( + struct vlMpeg2MacroBlockBatch *batch, + struct vlSurface *surface +) +{ + assert(batch); + assert(surface); + assert(surface->context); + + surface->context->render->vlBegin(surface->context->render); + + surface->context->render->vlRenderMacroBlocksMpeg2 + ( + surface->context->render, + batch, + surface + ); + + surface->context->render->vlEnd(surface->context->render); + + return 0; +} + +int vlPutPicture +( + struct vlSurface *surface, + vlNativeDrawable drawable, + int srcx, + int srcy, + int srcw, + int srch, + int destx, + int desty, + int destw, + int desth, + int drawable_w, + int drawable_h, + enum vlPictureType picture_type +) +{ + struct vlCSC *csc; + struct pipe_context *pipe; + + assert(surface); + assert(surface->context); + + surface->context->render->vlFlush(surface->context->render); + + csc = surface->context->csc; + pipe = surface->context->pipe; + + csc->vlResizeFrameBuffer(csc, drawable_w, drawable_h); + + csc->vlBegin(csc); + + csc->vlPutPicture + ( + csc, + surface, + srcx, + srcy, + srcw, + srch, + destx, + desty, + destw, + desth, + picture_type + ); + + csc->vlEnd(csc); + + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, &surface->disp_fence); + + bind_pipe_drawable(pipe, drawable); + + pipe->screen->flush_frontbuffer + ( + pipe->screen, + csc->vlGetFrameBuffer(csc), + pipe->priv + ); + + return 0; +} + +int vlSurfaceGetStatus +( + struct vlSurface *surface, + enum vlResourceStatus *status +) +{ + assert(surface); + assert(surface->context); + assert(status); + + if (surface->render_fence && !surface->context->pipe->screen->fence_signalled(surface->context->pipe->screen, surface->render_fence, 0)) + { + *status = vlResourceStatusRendering; + return 0; + } + + if (surface->disp_fence && !surface->context->pipe->screen->fence_signalled(surface->context->pipe->screen, surface->disp_fence, 0)) + { + *status = vlResourceStatusDisplaying; + return 0; + } + + *status = vlResourceStatusFree; + + return 0; +} + +int vlSurfaceFlush +( + struct vlSurface *surface +) +{ + assert(surface); + assert(surface->context); + + surface->context->render->vlFlush(surface->context->render); + + return 0; +} + +int vlSurfaceSync +( + struct vlSurface *surface +) +{ + assert(surface); + assert(surface->context); + assert(surface->render_fence); + + surface->context->pipe->screen->fence_finish(surface->context->pipe->screen, surface->render_fence, 0); + + return 0; +} + +struct vlScreen* vlSurfaceGetScreen +( + struct vlSurface *surface +) +{ + assert(surface); + + return surface->screen; +} + +struct vlContext* vlBindToContext +( + struct vlSurface *surface, + struct vlContext *context +) +{ + struct vlContext *old; + + assert(surface); + + old = surface->context; + surface->context = context; + + return old; +} diff --git a/src/gallium/state_trackers/g3dvl/vl_surface.h b/src/gallium/state_trackers/g3dvl/vl_surface.h new file mode 100644 index 0000000000..133e1515ef --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_surface.h @@ -0,0 +1,86 @@ +#ifndef vl_surface_h +#define vl_surface_h + +#include "vl_types.h" + +#ifdef VL_INTERNAL +struct pipe_texture; + +struct vlSurface +{ + struct vlScreen *screen; + struct vlContext *context; + unsigned int width; + unsigned int height; + enum vlFormat format; + struct pipe_texture *texture; + struct pipe_fence_handle *render_fence; + struct pipe_fence_handle *disp_fence; +}; +#endif + +int vlCreateSurface +( + struct vlScreen *screen, + unsigned int width, + unsigned int height, + enum vlFormat format, + struct vlSurface **surface +); + +int vlDestroySurface +( + struct vlSurface *surface +); + +int vlRenderMacroBlocksMpeg2 +( + struct vlMpeg2MacroBlockBatch *batch, + struct vlSurface *surface +); + +int vlPutPicture +( + struct vlSurface *surface, + vlNativeDrawable drawable, + int srcx, + int srcy, + int srcw, + int srch, + int destx, + int desty, + int destw, + int desth, + int drawable_w, + int drawable_h, + enum vlPictureType picture_type +); + +int vlSurfaceGetStatus +( + struct vlSurface *surface, + enum vlResourceStatus *status +); + +int vlSurfaceFlush +( + struct vlSurface *surface +); + +int vlSurfaceSync +( + struct vlSurface *surface +); + +struct vlScreen* vlSurfaceGetScreen +( + struct vlSurface *surface +); + +struct vlContext* vlBindToContext +( + struct vlSurface *surface, + struct vlContext *context +); + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_types.h b/src/gallium/state_trackers/g3dvl/vl_types.h new file mode 100644 index 0000000000..274e1f7437 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_types.h @@ -0,0 +1,115 @@ +#ifndef vl_types_h +#define vl_types_h + +#if 1 /*#ifdef X11*/ +#include <X11/Xlib.h> + +typedef Display* vlNativeDisplay; +typedef Drawable vlNativeDrawable; +#endif + +struct vlDisplay; +struct vlScreen; +struct vlContext; +struct vlSurface; + +enum vlResourceStatus +{ + vlResourceStatusFree, + vlResourceStatusRendering, + vlResourceStatusDisplaying +}; + +enum vlProfile +{ + vlProfileMpeg2Simple, + vlProfileMpeg2Main, + + vlProfileCount +}; + +enum vlEntryPoint +{ + vlEntryPointIDCT, + vlEntryPointMC, + vlEntryPointCSC, + + vlEntryPointCount +}; + +enum vlFormat +{ + vlFormatYCbCr420, + vlFormatYCbCr422, + vlFormatYCbCr444 +}; + +enum vlPictureType +{ + vlPictureTypeTopField, + vlPictureTypeBottomField, + vlPictureTypeFrame +}; + +enum vlMotionType +{ + vlMotionTypeField, + vlMotionTypeFrame, + vlMotionTypeDualPrime, + vlMotionType16x8 +}; + +enum vlFieldOrder +{ + vlFieldOrderFirst, + vlFieldOrderSecond +}; + +enum vlDCTType +{ + vlDCTTypeFrameCoded, + vlDCTTypeFieldCoded +}; + +struct vlVertex2f +{ + float x, y; +}; + +struct vlVertex4f +{ + float x, y, z, w; +}; + +enum vlMacroBlockType +{ + vlMacroBlockTypeIntra, + vlMacroBlockTypeFwdPredicted, + vlMacroBlockTypeBkwdPredicted, + vlMacroBlockTypeBiPredicted, + + vlNumMacroBlockTypes +}; + +struct vlMpeg2MacroBlock +{ + unsigned int mbx, mby; + enum vlMacroBlockType mb_type; + enum vlMotionType mo_type; + enum vlDCTType dct_type; + int PMV[2][2][2]; + unsigned int cbp; + short *blocks; +}; + +struct vlMpeg2MacroBlockBatch +{ + struct vlSurface *past_surface; + struct vlSurface *future_surface; + enum vlPictureType picture_type; + enum vlFieldOrder field_order; + unsigned int num_macroblocks; + struct vlMpeg2MacroBlock *macroblocks; +}; + +#endif diff --git a/src/gallium/state_trackers/g3dvl/vl_util.c b/src/gallium/state_trackers/g3dvl/vl_util.c new file mode 100644 index 0000000000..50aa9af66f --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_util.c @@ -0,0 +1,16 @@ +#include "vl_util.h" +#include <assert.h> + +unsigned int vlRoundUpPOT(unsigned int x) +{ + unsigned int i; + + assert(x > 0); + + --x; + + for (i = 1; i < sizeof(unsigned int) * 8; i <<= 1) + x |= x >> i; + + return x + 1; +} diff --git a/src/gallium/state_trackers/g3dvl/vl_util.h b/src/gallium/state_trackers/g3dvl/vl_util.h new file mode 100644 index 0000000000..bc98e79df4 --- /dev/null +++ b/src/gallium/state_trackers/g3dvl/vl_util.h @@ -0,0 +1,6 @@ +#ifndef vl_util_h +#define vl_util_h + +unsigned int vlRoundUpPOT(unsigned int x); + +#endif diff --git a/src/gallium/state_trackers/glx/Makefile b/src/gallium/state_trackers/glx/Makefile new file mode 100644 index 0000000000..f779035763 --- /dev/null +++ b/src/gallium/state_trackers/glx/Makefile @@ -0,0 +1,25 @@ +TOP = ../../../.. +include $(TOP)/configs/current + + +SUBDIRS = xlib + + +default: subdirs + + +subdirs: + @for dir in $(SUBDIRS) ; do \ + if [ -d $$dir ] ; then \ + (cd $$dir && $(MAKE)) || exit 1 ; \ + fi \ + done + + +clean: + rm -f `find . -name \*.[oa]` + rm -f `find . -name depend` + + +# Dummy install target +install: diff --git a/src/gallium/state_trackers/glx/xlib/Makefile b/src/gallium/state_trackers/glx/xlib/Makefile new file mode 100644 index 0000000000..7b2adc62c3 --- /dev/null +++ b/src/gallium/state_trackers/glx/xlib/Makefile @@ -0,0 +1,16 @@ +TOP = ../../../../.. +include $(TOP)/configs/current + +LIBNAME = xlib + +LIBRARY_INCLUDES = \ + -I$(TOP)/include \ + -I$(TOP)/src/mesa + +C_SOURCES = \ + glx_api.c \ + glx_getproc.c \ + glx_usefont.c \ + xm_api.c + +include ../../../Makefile.template diff --git a/src/gallium/state_trackers/glx/xlib/SConscript b/src/gallium/state_trackers/glx/xlib/SConscript new file mode 100644 index 0000000000..fa96df357d --- /dev/null +++ b/src/gallium/state_trackers/glx/xlib/SConscript @@ -0,0 +1,27 @@ +####################################################################### +# SConscript for xlib state_tracker + +Import('*') + +if env['platform'] == 'linux' \ + and 'mesa' in env['statetrackers']: + + env = env.Clone() + + env.Append(CPPPATH = [ + '#/src/mesa', + '#/src/mesa/main', + ]) + + env.Append(CPPDEFINES = ['USE_XSHM']) + + st_xlib = env.ConvenienceLibrary( + target = 'st_xlib', + source = [ + 'glx_api.c', + 'glx_getproc.c', + 'glx_usefont.c', + 'xm_api.c', + ] + ) + Export('st_xlib') diff --git a/src/gallium/state_trackers/glx/xlib/glx_api.c b/src/gallium/state_trackers/glx/xlib/glx_api.c new file mode 100644 index 0000000000..d1a98f8991 --- /dev/null +++ b/src/gallium/state_trackers/glx/xlib/glx_api.c @@ -0,0 +1,2629 @@ +/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * "Fake" GLX API implemented in terms of the XMesa*() functions. + */ + + + +#define GLX_GLXEXT_PROTOTYPES +#include "GL/glx.h" + +#include "xm_api.h" +#include "main/context.h" +#include "main/config.h" +#include "main/macros.h" +#include "main/imports.h" +#include "main/version.h" +#include "state_tracker/st_context.h" +#include "state_tracker/st_public.h" + + +/* This indicates the client-side GLX API and GLX encoder version. */ +#define CLIENT_MAJOR_VERSION 1 +#define CLIENT_MINOR_VERSION 4 /* but don't have 1.3's pbuffers, etc yet */ + +/* This indicates the server-side GLX decoder version. + * GLX 1.4 indicates OpenGL 1.3 support + */ +#define SERVER_MAJOR_VERSION 1 +#define SERVER_MINOR_VERSION 4 + +/* This is appended onto the glXGetClient/ServerString version strings. */ +#define MESA_GLX_VERSION "Mesa " MESA_VERSION_STRING + +/* Who implemented this GLX? */ +#define VENDOR "Brian Paul" + +#define EXTENSIONS \ + "GLX_MESA_copy_sub_buffer " \ + "GLX_MESA_pixmap_colormap " \ + "GLX_MESA_release_buffers " \ + "GLX_ARB_get_proc_address " \ + "GLX_EXT_texture_from_pixmap " \ + "GLX_EXT_visual_info " \ + "GLX_EXT_visual_rating " \ + /*"GLX_SGI_video_sync "*/ \ + "GLX_SGIX_fbconfig " \ + "GLX_SGIX_pbuffer " + +#define DEFAULT_DIRECT GL_TRUE + + + +/** + * The GLXContext typedef is defined as a pointer to this structure. + */ +struct __GLXcontextRec +{ + Display *currentDpy; + GLboolean isDirect; + GLXDrawable currentDrawable; + GLXDrawable currentReadable; + XID xid; + + XMesaContext xmesaContext; +}; + + + +static pipe_tsd ContextTSD; + +/** Set current context for calling thread */ +static void +SetCurrentContext(GLXContext c) +{ + pipe_tsd_set(&ContextTSD, c); +} + +/** Get current context for calling thread */ +static GLXContext +GetCurrentContext(void) +{ + return pipe_tsd_get(&ContextTSD); +} + + + +/**********************************************************************/ +/*** GLX Visual Code ***/ +/**********************************************************************/ + +#define DONT_CARE -1 + + +static XMesaVisual *VisualTable = NULL; +static int NumVisuals = 0; + + + +/* Macro to handle c_class vs class field name in XVisualInfo struct */ +#if defined(__cplusplus) || defined(c_plusplus) +#define CLASS c_class +#else +#define CLASS class +#endif + + + +/* + * Test if the given XVisualInfo is usable for Mesa rendering. + */ +static GLboolean +is_usable_visual( XVisualInfo *vinfo ) +{ + switch (vinfo->CLASS) { + case StaticGray: + case GrayScale: + /* Any StaticGray/GrayScale visual works in RGB or CI mode */ + return GL_TRUE; + case StaticColor: + case PseudoColor: + /* Any StaticColor/PseudoColor visual of at least 4 bits */ + if (vinfo->depth>=4) { + return GL_TRUE; + } + else { + return GL_FALSE; + } + case TrueColor: + case DirectColor: + /* Any depth of TrueColor or DirectColor works in RGB mode */ + return GL_TRUE; + default: + /* This should never happen */ + return GL_FALSE; + } +} + + +/* + * Given an XVisualInfo and RGB, Double, and Depth buffer flags, save the + * configuration in our list of GLX visuals. + */ +static XMesaVisual +save_glx_visual( Display *dpy, XVisualInfo *vinfo, + GLboolean rgbFlag, GLboolean alphaFlag, GLboolean dbFlag, + GLboolean stereoFlag, + GLint depth_size, GLint stencil_size, + GLint accumRedSize, GLint accumGreenSize, + GLint accumBlueSize, GLint accumAlphaSize, + GLint level, GLint numAuxBuffers ) +{ + GLboolean ximageFlag = GL_TRUE; + XMesaVisual xmvis; + GLint i; + GLboolean comparePointers; + + if (dbFlag) { + /* Check if the MESA_BACK_BUFFER env var is set */ + char *backbuffer = _mesa_getenv("MESA_BACK_BUFFER"); + if (backbuffer) { + if (backbuffer[0]=='p' || backbuffer[0]=='P') { + ximageFlag = GL_FALSE; + } + else if (backbuffer[0]=='x' || backbuffer[0]=='X') { + ximageFlag = GL_TRUE; + } + else { + _mesa_warning(NULL, "Mesa: invalid value for MESA_BACK_BUFFER environment variable, using an XImage."); + } + } + } + + if (stereoFlag) { + /* stereo not supported */ + return NULL; + } + + if (stencil_size > 0 && depth_size > 0) + depth_size = 24; + + /* Comparing IDs uses less memory but sometimes fails. */ + /* XXX revisit this after 3.0 is finished. */ + if (_mesa_getenv("MESA_GLX_VISUAL_HACK")) + comparePointers = GL_TRUE; + else + comparePointers = GL_FALSE; + + /* Force the visual to have an alpha channel */ + if (rgbFlag && _mesa_getenv("MESA_GLX_FORCE_ALPHA")) + alphaFlag = GL_TRUE; + + /* First check if a matching visual is already in the list */ + for (i=0; i<NumVisuals; i++) { + XMesaVisual v = VisualTable[i]; + if (v->display == dpy + && v->mesa_visual.level == level + && v->mesa_visual.numAuxBuffers == numAuxBuffers + && v->ximage_flag == ximageFlag + && v->mesa_visual.rgbMode == rgbFlag + && v->mesa_visual.doubleBufferMode == dbFlag + && v->mesa_visual.stereoMode == stereoFlag + && (v->mesa_visual.alphaBits > 0) == alphaFlag + && (v->mesa_visual.depthBits >= depth_size || depth_size == 0) + && (v->mesa_visual.stencilBits >= stencil_size || stencil_size == 0) + && (v->mesa_visual.accumRedBits >= accumRedSize || accumRedSize == 0) + && (v->mesa_visual.accumGreenBits >= accumGreenSize || accumGreenSize == 0) + && (v->mesa_visual.accumBlueBits >= accumBlueSize || accumBlueSize == 0) + && (v->mesa_visual.accumAlphaBits >= accumAlphaSize || accumAlphaSize == 0)) { + /* now either compare XVisualInfo pointers or visual IDs */ + if ((!comparePointers && v->visinfo->visualid == vinfo->visualid) + || (comparePointers && v->vishandle == vinfo)) { + return v; + } + } + } + + /* Create a new visual and add it to the list. */ + + xmvis = XMesaCreateVisual( dpy, vinfo, rgbFlag, alphaFlag, dbFlag, + stereoFlag, ximageFlag, + depth_size, stencil_size, + accumRedSize, accumBlueSize, + accumBlueSize, accumAlphaSize, 0, level, + GLX_NONE_EXT ); + if (xmvis) { + /* Save a copy of the pointer now so we can find this visual again + * if we need to search for it in find_glx_visual(). + */ + xmvis->vishandle = vinfo; + /* Allocate more space for additional visual */ + VisualTable = (XMesaVisual *) _mesa_realloc( VisualTable, + sizeof(XMesaVisual) * NumVisuals, + sizeof(XMesaVisual) * (NumVisuals + 1)); + /* add xmvis to the list */ + VisualTable[NumVisuals] = xmvis; + NumVisuals++; + /* XXX minor hack, because XMesaCreateVisual doesn't support an + * aux buffers parameter. + */ + xmvis->mesa_visual.numAuxBuffers = numAuxBuffers; + } + return xmvis; +} + + +/** + * Return the default number of bits for the Z buffer. + * If defined, use the MESA_GLX_DEPTH_BITS env var value. + * Otherwise, use the DEFAULT_SOFTWARE_DEPTH_BITS constant. + * XXX probably do the same thing for stencil, accum, etc. + */ +static GLint +default_depth_bits(void) +{ + int zBits; + const char *zEnv = _mesa_getenv("MESA_GLX_DEPTH_BITS"); + if (zEnv) + zBits = _mesa_atoi(zEnv); + else + zBits = DEFAULT_SOFTWARE_DEPTH_BITS; + return zBits; +} + +static GLint +default_alpha_bits(void) +{ + int aBits; + const char *aEnv = _mesa_getenv("MESA_GLX_ALPHA_BITS"); + if (aEnv) + aBits = _mesa_atoi(aEnv); + else + aBits = 0; + return aBits; +} + +static GLint +default_accum_bits(void) +{ + return 16; +} + + + +/* + * Create a GLX visual from a regular XVisualInfo. + * This is called when Fake GLX is given an XVisualInfo which wasn't + * returned by glXChooseVisual. Since this is the first time we're + * considering this visual we'll take a guess at reasonable values + * for depth buffer size, stencil size, accum size, etc. + * This is the best we can do with a client-side emulation of GLX. + */ +static XMesaVisual +create_glx_visual( Display *dpy, XVisualInfo *visinfo ) +{ + GLint zBits = default_depth_bits(); + GLint accBits = default_accum_bits(); + GLboolean alphaFlag = default_alpha_bits() > 0; + + if (is_usable_visual( visinfo )) { + /* Configure this visual as RGB, double-buffered, depth-buffered. */ + /* This is surely wrong for some people's needs but what else */ + /* can be done? They should use glXChooseVisual(). */ + return save_glx_visual( dpy, visinfo, + GL_TRUE, /* rgb */ + alphaFlag, /* alpha */ + GL_TRUE, /* double */ + GL_FALSE, /* stereo */ + zBits, + STENCIL_BITS, + accBits, /* r */ + accBits, /* g */ + accBits, /* b */ + accBits, /* a */ + 0, /* level */ + 0 /* numAux */ + ); + } + else { + _mesa_warning(NULL, "Mesa: error in glXCreateContext: bad visual\n"); + return NULL; + } +} + + + +/* + * Find the GLX visual associated with an XVisualInfo. + */ +static XMesaVisual +find_glx_visual( Display *dpy, XVisualInfo *vinfo ) +{ + int i; + + /* try to match visual id */ + for (i=0;i<NumVisuals;i++) { + if (VisualTable[i]->display==dpy + && VisualTable[i]->visinfo->visualid == vinfo->visualid) { + return VisualTable[i]; + } + } + + /* if that fails, try to match pointers */ + for (i=0;i<NumVisuals;i++) { + if (VisualTable[i]->display==dpy && VisualTable[i]->vishandle==vinfo) { + return VisualTable[i]; + } + } + + return NULL; +} + + +/** + * Try to get an X visual which matches the given arguments. + */ +static XVisualInfo * +get_visual( Display *dpy, int scr, unsigned int depth, int xclass ) +{ + XVisualInfo temp, *vis; + long mask; + int n; + unsigned int default_depth; + int default_class; + + mask = VisualScreenMask | VisualDepthMask | VisualClassMask; + temp.screen = scr; + temp.depth = depth; + temp.CLASS = xclass; + + default_depth = DefaultDepth(dpy,scr); + default_class = DefaultVisual(dpy,scr)->CLASS; + + if (depth==default_depth && xclass==default_class) { + /* try to get root window's visual */ + temp.visualid = DefaultVisual(dpy,scr)->visualid; + mask |= VisualIDMask; + } + + vis = XGetVisualInfo( dpy, mask, &temp, &n ); + + /* In case bits/pixel > 24, make sure color channels are still <=8 bits. + * An SGI Infinite Reality system, for example, can have 30bpp pixels: + * 10 bits per color channel. Mesa's limited to a max of 8 bits/channel. + */ + if (vis && depth > 24 && (xclass==TrueColor || xclass==DirectColor)) { + if (_mesa_bitcount((GLuint) vis->red_mask ) <= 8 && + _mesa_bitcount((GLuint) vis->green_mask) <= 8 && + _mesa_bitcount((GLuint) vis->blue_mask ) <= 8) { + return vis; + } + else { + XFree((void *) vis); + return NULL; + } + } + + return vis; +} + + +/* + * Retrieve the value of the given environment variable and find + * the X visual which matches it. + * Input: dpy - the display + * screen - the screen number + * varname - the name of the environment variable + * Return: an XVisualInfo pointer to NULL if error. + */ +static XVisualInfo * +get_env_visual(Display *dpy, int scr, const char *varname) +{ + char value[100], type[100]; + int depth, xclass = -1; + XVisualInfo *vis; + + if (!_mesa_getenv( varname )) { + return NULL; + } + + _mesa_strncpy( value, _mesa_getenv(varname), 100 ); + value[99] = 0; + + sscanf( value, "%s %d", type, &depth ); + + if (_mesa_strcmp(type,"TrueColor")==0) xclass = TrueColor; + else if (_mesa_strcmp(type,"DirectColor")==0) xclass = DirectColor; + else if (_mesa_strcmp(type,"PseudoColor")==0) xclass = PseudoColor; + else if (_mesa_strcmp(type,"StaticColor")==0) xclass = StaticColor; + else if (_mesa_strcmp(type,"GrayScale")==0) xclass = GrayScale; + else if (_mesa_strcmp(type,"StaticGray")==0) xclass = StaticGray; + + if (xclass>-1 && depth>0) { + vis = get_visual( dpy, scr, depth, xclass ); + if (vis) { + return vis; + } + } + + _mesa_warning(NULL, "GLX unable to find visual class=%s, depth=%d.", + type, depth); + + return NULL; +} + + + +/* + * Select an X visual which satisfies the RGBA flag and minimum depth. + * Input: dpy, + * screen - X display and screen number + * min_depth - minimum visual depth + * preferred_class - preferred GLX visual class or DONT_CARE + * Return: pointer to an XVisualInfo or NULL. + */ +static XVisualInfo * +choose_x_visual( Display *dpy, int screen, int min_depth, + int preferred_class ) +{ + XVisualInfo *vis; + int xclass, visclass = 0; + int depth; + + /* First see if the MESA_RGB_VISUAL env var is defined */ + vis = get_env_visual( dpy, screen, "MESA_RGB_VISUAL" ); + if (vis) { + return vis; + } + /* Otherwise, search for a suitable visual */ + if (preferred_class==DONT_CARE) { + for (xclass=0;xclass<6;xclass++) { + switch (xclass) { + case 0: visclass = TrueColor; break; + case 1: visclass = DirectColor; break; + case 2: visclass = PseudoColor; break; + case 3: visclass = StaticColor; break; + case 4: visclass = GrayScale; break; + case 5: visclass = StaticGray; break; + } + if (min_depth==0) { + /* start with shallowest */ + for (depth=0;depth<=32;depth++) { + if (visclass==TrueColor && depth==8) { + /* Special case: try to get 8-bit PseudoColor before */ + /* 8-bit TrueColor */ + vis = get_visual( dpy, screen, 8, PseudoColor ); + if (vis) { + return vis; + } + } + vis = get_visual( dpy, screen, depth, visclass ); + if (vis) { + return vis; + } + } + } + else { + /* start with deepest */ + for (depth=32;depth>=min_depth;depth--) { + if (visclass==TrueColor && depth==8) { + /* Special case: try to get 8-bit PseudoColor before */ + /* 8-bit TrueColor */ + vis = get_visual( dpy, screen, 8, PseudoColor ); + if (vis) { + return vis; + } + } + vis = get_visual( dpy, screen, depth, visclass ); + if (vis) { + return vis; + } + } + } + } + } + else { + /* search for a specific visual class */ + switch (preferred_class) { + case GLX_TRUE_COLOR_EXT: visclass = TrueColor; break; + case GLX_DIRECT_COLOR_EXT: visclass = DirectColor; break; + case GLX_PSEUDO_COLOR_EXT: visclass = PseudoColor; break; + case GLX_STATIC_COLOR_EXT: visclass = StaticColor; break; + case GLX_GRAY_SCALE_EXT: visclass = GrayScale; break; + case GLX_STATIC_GRAY_EXT: visclass = StaticGray; break; + default: return NULL; + } + if (min_depth==0) { + /* start with shallowest */ + for (depth=0;depth<=32;depth++) { + vis = get_visual( dpy, screen, depth, visclass ); + if (vis) { + return vis; + } + } + } + else { + /* start with deepest */ + for (depth=32;depth>=min_depth;depth--) { + vis = get_visual( dpy, screen, depth, visclass ); + if (vis) { + return vis; + } + } + } + } + + /* didn't find a visual */ + return NULL; +} + + + + +/**********************************************************************/ +/*** Display-related functions ***/ +/**********************************************************************/ + + +/** + * Free all XMesaVisuals which are associated with the given display. + */ +static void +destroy_visuals_on_display(Display *dpy) +{ + int i; + for (i = 0; i < NumVisuals; i++) { + if (VisualTable[i]->display == dpy) { + /* remove this visual */ + int j; + free(VisualTable[i]); + for (j = i; j < NumVisuals - 1; j++) + VisualTable[j] = VisualTable[j + 1]; + NumVisuals--; + } + } +} + + +/** + * Called from XCloseDisplay() to let us free our display-related data. + */ +static int +close_display_callback(Display *dpy, XExtCodes *codes) +{ + destroy_visuals_on_display(dpy); + xmesa_destroy_buffers_on_display(dpy); + return 0; +} + + +/** + * Look for the named extension on given display and return a pointer + * to the _XExtension data, or NULL if extension not found. + */ +static _XExtension * +lookup_extension(Display *dpy, const char *extName) +{ + _XExtension *ext; + for (ext = dpy->ext_procs; ext; ext = ext->next) { + if (ext->name && strcmp(ext->name, extName) == 0) { + return ext; + } + } + return NULL; +} + + +/** + * Whenever we're given a new Display pointer, call this function to + * register our close_display_callback function. + */ +static void +register_with_display(Display *dpy) +{ + const char *extName = "MesaGLX"; + _XExtension *ext; + + ext = lookup_extension(dpy, extName); + if (!ext) { + XExtCodes *c = XAddExtension(dpy); + ext = dpy->ext_procs; /* new extension is at head of list */ + assert(c->extension == ext->codes.extension); + ext->name = _mesa_strdup(extName); + ext->close_display = close_display_callback; + } +} + + +/**********************************************************************/ +/*** Begin Fake GLX API Functions ***/ +/**********************************************************************/ + + +/** + * Helper used by glXChooseVisual and glXChooseFBConfig. + * The fbConfig parameter must be GL_FALSE for the former and GL_TRUE for + * the later. + * In either case, the attribute list is terminated with the value 'None'. + */ +static XMesaVisual +choose_visual( Display *dpy, int screen, const int *list, GLboolean fbConfig ) +{ + const GLboolean rgbModeDefault = fbConfig; + const int *parselist; + XVisualInfo *vis; + int min_ci = 0; + int min_red=0, min_green=0, min_blue=0; + GLboolean rgb_flag = rgbModeDefault; + GLboolean alpha_flag = GL_FALSE; + GLboolean double_flag = GL_FALSE; + GLboolean stereo_flag = GL_FALSE; + GLint depth_size = 0; + GLint stencil_size = 0; + GLint accumRedSize = 0; + GLint accumGreenSize = 0; + GLint accumBlueSize = 0; + GLint accumAlphaSize = 0; + int level = 0; + int visual_type = DONT_CARE; + int trans_type = DONT_CARE; + int trans_value = DONT_CARE; + GLint caveat = DONT_CARE; + XMesaVisual xmvis = NULL; + int desiredVisualID = -1; + int numAux = 0; + + parselist = list; + + while (*parselist) { + + switch (*parselist) { + case GLX_USE_GL: + if (fbConfig) { + /* invalid token */ + return NULL; + } + else { + /* skip */ + parselist++; + } + break; + case GLX_BUFFER_SIZE: + parselist++; + min_ci = *parselist++; + break; + case GLX_LEVEL: + parselist++; + level = *parselist++; + break; + case GLX_RGBA: + if (fbConfig) { + /* invalid token */ + return NULL; + } + else { + rgb_flag = GL_TRUE; + parselist++; + } + break; + case GLX_DOUBLEBUFFER: + parselist++; + if (fbConfig) { + double_flag = *parselist++; + } + else { + double_flag = GL_TRUE; + } + break; + case GLX_STEREO: + parselist++; + if (fbConfig) { + stereo_flag = *parselist++; + } + else { + stereo_flag = GL_TRUE; + } + break; + case GLX_AUX_BUFFERS: + parselist++; + numAux = *parselist++; + if (numAux > MAX_AUX_BUFFERS) + return NULL; + break; + case GLX_RED_SIZE: + parselist++; + min_red = *parselist++; + break; + case GLX_GREEN_SIZE: + parselist++; + min_green = *parselist++; + break; + case GLX_BLUE_SIZE: + parselist++; + min_blue = *parselist++; + break; + case GLX_ALPHA_SIZE: + parselist++; + { + GLint size = *parselist++; + alpha_flag = size ? GL_TRUE : GL_FALSE; + } + break; + case GLX_DEPTH_SIZE: + parselist++; + depth_size = *parselist++; + break; + case GLX_STENCIL_SIZE: + parselist++; + stencil_size = *parselist++; + break; + case GLX_ACCUM_RED_SIZE: + parselist++; + { + GLint size = *parselist++; + accumRedSize = MAX2( accumRedSize, size ); + } + break; + case GLX_ACCUM_GREEN_SIZE: + parselist++; + { + GLint size = *parselist++; + accumGreenSize = MAX2( accumGreenSize, size ); + } + break; + case GLX_ACCUM_BLUE_SIZE: + parselist++; + { + GLint size = *parselist++; + accumBlueSize = MAX2( accumBlueSize, size ); + } + break; + case GLX_ACCUM_ALPHA_SIZE: + parselist++; + { + GLint size = *parselist++; + accumAlphaSize = MAX2( accumAlphaSize, size ); + } + break; + + /* + * GLX_EXT_visual_info extension + */ + case GLX_X_VISUAL_TYPE_EXT: + parselist++; + visual_type = *parselist++; + break; + case GLX_TRANSPARENT_TYPE_EXT: + parselist++; + trans_type = *parselist++; + break; + case GLX_TRANSPARENT_INDEX_VALUE_EXT: + parselist++; + trans_value = *parselist++; + break; + case GLX_TRANSPARENT_RED_VALUE_EXT: + case GLX_TRANSPARENT_GREEN_VALUE_EXT: + case GLX_TRANSPARENT_BLUE_VALUE_EXT: + case GLX_TRANSPARENT_ALPHA_VALUE_EXT: + /* ignore */ + parselist++; + parselist++; + break; + + /* + * GLX_EXT_visual_info extension + */ + case GLX_VISUAL_CAVEAT_EXT: + parselist++; + caveat = *parselist++; /* ignored for now */ + break; + + /* + * GLX_ARB_multisample + */ + case GLX_SAMPLE_BUFFERS_ARB: + /* ms not supported */ + return NULL; + case GLX_SAMPLES_ARB: + /* ms not supported */ + return NULL; + + /* + * FBConfig attribs. + */ + case GLX_RENDER_TYPE: + if (!fbConfig) + return NULL; + parselist++; + if (*parselist == GLX_RGBA_BIT) { + rgb_flag = GL_TRUE; + } + else if (*parselist == GLX_COLOR_INDEX_BIT) { + rgb_flag = GL_FALSE; + } + else if (*parselist == 0) { + rgb_flag = GL_TRUE; + } + parselist++; + break; + case GLX_DRAWABLE_TYPE: + if (!fbConfig) + return NULL; + parselist++; + if (*parselist & ~(GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT)) { + return NULL; /* bad bit */ + } + parselist++; + break; + case GLX_FBCONFIG_ID: + if (!fbConfig) + return NULL; + parselist++; + desiredVisualID = *parselist++; + break; + case GLX_X_RENDERABLE: + if (!fbConfig) + return NULL; + parselist += 2; + /* ignore */ + break; + +#ifdef GLX_EXT_texture_from_pixmap + case GLX_BIND_TO_TEXTURE_RGB_EXT: + parselist++; /*skip*/ + break; + case GLX_BIND_TO_TEXTURE_RGBA_EXT: + parselist++; /*skip*/ + break; + case GLX_BIND_TO_MIPMAP_TEXTURE_EXT: + parselist++; /*skip*/ + break; + case GLX_BIND_TO_TEXTURE_TARGETS_EXT: + parselist++; + if (*parselist & ~(GLX_TEXTURE_1D_BIT_EXT | + GLX_TEXTURE_2D_BIT_EXT | + GLX_TEXTURE_RECTANGLE_BIT_EXT)) { + /* invalid bit */ + return NULL; + } + break; + case GLX_Y_INVERTED_EXT: + parselist++; /*skip*/ + break; +#endif + + case None: + /* end of list */ + break; + + default: + /* undefined attribute */ + _mesa_warning(NULL, "unexpected attrib 0x%x in choose_visual()", + *parselist); + return NULL; + } + } + + (void) caveat; + + + /* + * Since we're only simulating the GLX extension this function will never + * find any real GL visuals. Instead, all we can do is try to find an RGB + * or CI visual of appropriate depth. Other requested attributes such as + * double buffering, depth buffer, etc. will be associated with the X + * visual and stored in the VisualTable[]. + */ + if (desiredVisualID != -1) { + /* try to get a specific visual, by visualID */ + XVisualInfo temp; + int n; + temp.visualid = desiredVisualID; + temp.screen = screen; + vis = XGetVisualInfo(dpy, VisualIDMask | VisualScreenMask, &temp, &n); + if (vis) { + /* give the visual some useful GLX attributes */ + double_flag = GL_TRUE; + rgb_flag = GL_TRUE; + depth_size = default_depth_bits(); + stencil_size = STENCIL_BITS; + /* XXX accum??? */ + } + } + else if (level==0) { + /* normal color planes */ + /* Get an RGB visual */ + int min_rgb = min_red + min_green + min_blue; + if (min_rgb>1 && min_rgb<8) { + /* a special case to be sure we can get a monochrome visual */ + min_rgb = 1; + } + vis = choose_x_visual( dpy, screen, min_rgb, visual_type ); + } + else { + _mesa_warning(NULL, "overlay not supported"); + return NULL; + } + + if (vis) { + /* Note: we're not exactly obeying the glXChooseVisual rules here. + * When GLX_DEPTH_SIZE = 1 is specified we're supposed to choose the + * largest depth buffer size, which is 32bits/value. Instead, we + * return 16 to maintain performance with earlier versions of Mesa. + */ + if (stencil_size > 0) + depth_size = 24; /* if Z and stencil, always use 24+8 format */ + else if (depth_size > 24) + depth_size = 32; + else if (depth_size > 16) + depth_size = 24; + else if (depth_size > 0) { + depth_size = default_depth_bits(); + } + + if (!alpha_flag) { + alpha_flag = default_alpha_bits() > 0; + } + + /* we only support one size of stencil and accum buffers. */ + if (stencil_size > 0) + stencil_size = STENCIL_BITS; + + if (accumRedSize > 0 || + accumGreenSize > 0 || + accumBlueSize > 0 || + accumAlphaSize > 0) { + + accumRedSize = + accumGreenSize = + accumBlueSize = default_accum_bits(); + + accumAlphaSize = alpha_flag ? accumRedSize : 0; + } + + xmvis = save_glx_visual( dpy, vis, rgb_flag, alpha_flag, double_flag, + stereo_flag, depth_size, stencil_size, + accumRedSize, accumGreenSize, + accumBlueSize, accumAlphaSize, level, numAux ); + } + + return xmvis; +} + + +XVisualInfo * +glXChooseVisual( Display *dpy, int screen, int *list ) +{ + XMesaVisual xmvis; + + /* register ourselves as an extension on this display */ + register_with_display(dpy); + + xmvis = choose_visual(dpy, screen, list, GL_FALSE); + if (xmvis) { + /* create a new vishandle - the cached one may be stale */ + xmvis->vishandle = (XVisualInfo *) _mesa_malloc(sizeof(XVisualInfo)); + if (xmvis->vishandle) { + _mesa_memcpy(xmvis->vishandle, xmvis->visinfo, sizeof(XVisualInfo)); + } + return xmvis->vishandle; + } + else + return NULL; +} + + +GLXContext +glXCreateContext( Display *dpy, XVisualInfo *visinfo, + GLXContext share_list, Bool direct ) +{ + XMesaVisual xmvis; + GLXContext glxCtx; + GLXContext shareCtx = share_list; + + if (!dpy || !visinfo) + return 0; + + glxCtx = CALLOC_STRUCT(__GLXcontextRec); + if (!glxCtx) + return 0; + + /* deallocate unused windows/buffers */ +#if 0 + XMesaGarbageCollect(); +#endif + + xmvis = find_glx_visual( dpy, visinfo ); + if (!xmvis) { + /* This visual wasn't found with glXChooseVisual() */ + xmvis = create_glx_visual( dpy, visinfo ); + if (!xmvis) { + /* unusable visual */ + _mesa_free(glxCtx); + return NULL; + } + } + + glxCtx->xmesaContext = XMesaCreateContext(xmvis, + shareCtx ? shareCtx->xmesaContext : NULL); + if (!glxCtx->xmesaContext) { + _mesa_free(glxCtx); + return NULL; + } + + glxCtx->isDirect = DEFAULT_DIRECT; + glxCtx->currentDpy = dpy; + glxCtx->xid = (XID) glxCtx; /* self pointer */ + + return glxCtx; +} + + +/* XXX these may have to be removed due to thread-safety issues. */ +static GLXContext MakeCurrent_PrevContext = 0; +static GLXDrawable MakeCurrent_PrevDrawable = 0; +static GLXDrawable MakeCurrent_PrevReadable = 0; +static XMesaBuffer MakeCurrent_PrevDrawBuffer = 0; +static XMesaBuffer MakeCurrent_PrevReadBuffer = 0; + + +/* GLX 1.3 and later */ +Bool +glXMakeContextCurrent( Display *dpy, GLXDrawable draw, + GLXDrawable read, GLXContext ctx ) +{ + GLXContext glxCtx = ctx; + static boolean firsttime = 1, no_rast = 0; + + if (firsttime) { + no_rast = getenv("SP_NO_RAST") != NULL; + firsttime = 0; + } + + if (ctx && draw && read) { + XMesaBuffer drawBuffer, readBuffer; + XMesaContext xmctx = glxCtx->xmesaContext; + + /* Find the XMesaBuffer which corresponds to the GLXDrawable 'draw' */ + if (ctx == MakeCurrent_PrevContext + && draw == MakeCurrent_PrevDrawable) { + drawBuffer = MakeCurrent_PrevDrawBuffer; + } + else { + drawBuffer = XMesaFindBuffer( dpy, draw ); + } + if (!drawBuffer) { + /* drawable must be a new window! */ + drawBuffer = XMesaCreateWindowBuffer( xmctx->xm_visual, draw ); + if (!drawBuffer) { + /* Out of memory, or context/drawable depth mismatch */ + return False; + } + } + + /* Find the XMesaBuffer which corresponds to the GLXDrawable 'read' */ + if (ctx == MakeCurrent_PrevContext + && read == MakeCurrent_PrevReadable) { + readBuffer = MakeCurrent_PrevReadBuffer; + } + else { + readBuffer = XMesaFindBuffer( dpy, read ); + } + if (!readBuffer) { + /* drawable must be a new window! */ + readBuffer = XMesaCreateWindowBuffer( xmctx->xm_visual, read ); + if (!readBuffer) { + /* Out of memory, or context/drawable depth mismatch */ + return False; + } + } + + if (no_rast && + MakeCurrent_PrevContext == ctx && + MakeCurrent_PrevDrawable == draw && + MakeCurrent_PrevReadable == read && + MakeCurrent_PrevDrawBuffer == drawBuffer && + MakeCurrent_PrevReadBuffer == readBuffer) + return True; + + MakeCurrent_PrevContext = ctx; + MakeCurrent_PrevDrawable = draw; + MakeCurrent_PrevReadable = read; + MakeCurrent_PrevDrawBuffer = drawBuffer; + MakeCurrent_PrevReadBuffer = readBuffer; + + /* Now make current! */ + if (XMesaMakeCurrent2(xmctx, drawBuffer, readBuffer)) { + ctx->currentDpy = dpy; + ctx->currentDrawable = draw; + ctx->currentReadable = read; + SetCurrentContext(ctx); + return True; + } + else { + return False; + } + } + else if (!ctx && !draw && !read) { + /* release current context w/out assigning new one. */ + XMesaMakeCurrent2( NULL, NULL, NULL ); + MakeCurrent_PrevContext = 0; + MakeCurrent_PrevDrawable = 0; + MakeCurrent_PrevReadable = 0; + MakeCurrent_PrevDrawBuffer = 0; + MakeCurrent_PrevReadBuffer = 0; + SetCurrentContext(NULL); + return True; + } + else { + /* The args must either all be non-zero or all zero. + * This is an error. + */ + return False; + } +} + + +Bool +glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx ) +{ + return glXMakeContextCurrent( dpy, drawable, drawable, ctx ); +} + + +GLXContext +glXGetCurrentContext(void) +{ + return GetCurrentContext(); +} + + +Display * +glXGetCurrentDisplay(void) +{ + GLXContext glxCtx = glXGetCurrentContext(); + + return glxCtx ? glxCtx->currentDpy : NULL; +} + + +Display * +glXGetCurrentDisplayEXT(void) +{ + return glXGetCurrentDisplay(); +} + + +GLXDrawable +glXGetCurrentDrawable(void) +{ + GLXContext gc = glXGetCurrentContext(); + return gc ? gc->currentDrawable : 0; +} + + +GLXDrawable +glXGetCurrentReadDrawable(void) +{ + GLXContext gc = glXGetCurrentContext(); + return gc ? gc->currentReadable : 0; +} + + +GLXDrawable +glXGetCurrentReadDrawableSGI(void) +{ + return glXGetCurrentReadDrawable(); +} + + +GLXPixmap +glXCreateGLXPixmap( Display *dpy, XVisualInfo *visinfo, Pixmap pixmap ) +{ + XMesaVisual v; + XMesaBuffer b; + + v = find_glx_visual( dpy, visinfo ); + if (!v) { + v = create_glx_visual( dpy, visinfo ); + if (!v) { + /* unusable visual */ + return 0; + } + } + + b = XMesaCreatePixmapBuffer( v, pixmap, 0 ); + if (!b) { + return 0; + } + return b->drawable; +} + + +/*** GLX_MESA_pixmap_colormap ***/ + +GLXPixmap +glXCreateGLXPixmapMESA( Display *dpy, XVisualInfo *visinfo, + Pixmap pixmap, Colormap cmap ) +{ + XMesaVisual v; + XMesaBuffer b; + + v = find_glx_visual( dpy, visinfo ); + if (!v) { + v = create_glx_visual( dpy, visinfo ); + if (!v) { + /* unusable visual */ + return 0; + } + } + + b = XMesaCreatePixmapBuffer( v, pixmap, cmap ); + if (!b) { + return 0; + } + return b->drawable; +} + + +void +glXDestroyGLXPixmap( Display *dpy, GLXPixmap pixmap ) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, pixmap); + if (b) { + XMesaDestroyBuffer(b); + } + else if (_mesa_getenv("MESA_DEBUG")) { + _mesa_warning(NULL, "Mesa: glXDestroyGLXPixmap: invalid pixmap\n"); + } +} + + +void +glXCopyContext( Display *dpy, GLXContext src, GLXContext dst, + unsigned long mask ) +{ + XMesaContext xm_src = src->xmesaContext; + XMesaContext xm_dst = dst->xmesaContext; + (void) dpy; + if (MakeCurrent_PrevContext == src) { + _mesa_Flush(); + } + st_copy_context_state( xm_src->st, xm_dst->st, (GLuint) mask ); +} + + +Bool +glXQueryExtension( Display *dpy, int *errorb, int *event ) +{ + /* Mesa's GLX isn't really an X extension but we try to act like one. */ + (void) dpy; + (void) errorb; + (void) event; + return True; +} + + +void +glXDestroyContext( Display *dpy, GLXContext ctx ) +{ + GLXContext glxCtx = ctx; + (void) dpy; + MakeCurrent_PrevContext = 0; + MakeCurrent_PrevDrawable = 0; + MakeCurrent_PrevReadable = 0; + MakeCurrent_PrevDrawBuffer = 0; + MakeCurrent_PrevReadBuffer = 0; + XMesaDestroyContext( glxCtx->xmesaContext ); + XMesaGarbageCollect(); + _mesa_free(glxCtx); +} + + +Bool +glXIsDirect( Display *dpy, GLXContext ctx ) +{ + GLXContext glxCtx = ctx; + (void) ctx; + return glxCtx->isDirect; +} + + + +void +glXSwapBuffers( Display *dpy, GLXDrawable drawable ) +{ + XMesaBuffer buffer = XMesaFindBuffer( dpy, drawable ); + static boolean firsttime = 1, no_rast = 0; + + if (firsttime) { + no_rast = getenv("SP_NO_RAST") != NULL; + firsttime = 0; + } + + if (no_rast) + return; + + if (buffer) { + XMesaSwapBuffers(buffer); + } + else if (_mesa_getenv("MESA_DEBUG")) { + _mesa_warning(NULL, "glXSwapBuffers: invalid drawable 0x%x\n", + (int) drawable); + } +} + + + +/*** GLX_MESA_copy_sub_buffer ***/ + +void +glXCopySubBufferMESA( Display *dpy, GLXDrawable drawable, + int x, int y, int width, int height ) +{ + XMesaBuffer buffer = XMesaFindBuffer( dpy, drawable ); + if (buffer) { + XMesaCopySubBuffer(buffer, x, y, width, height); + } + else if (_mesa_getenv("MESA_DEBUG")) { + _mesa_warning(NULL, "Mesa: glXCopySubBufferMESA: invalid drawable\n"); + } +} + + +Bool +glXQueryVersion( Display *dpy, int *maj, int *min ) +{ + (void) dpy; + /* Return GLX version, not Mesa version */ + assert(CLIENT_MAJOR_VERSION == SERVER_MAJOR_VERSION); + *maj = CLIENT_MAJOR_VERSION; + *min = MIN2( CLIENT_MINOR_VERSION, SERVER_MINOR_VERSION ); + return True; +} + + +/* + * Query the GLX attributes of the given XVisualInfo. + */ +static int +get_config( XMesaVisual xmvis, int attrib, int *value, GLboolean fbconfig ) +{ + ASSERT(xmvis); + switch(attrib) { + case GLX_USE_GL: + if (fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = (int) True; + return 0; + case GLX_BUFFER_SIZE: + *value = xmvis->visinfo->depth; + return 0; + case GLX_LEVEL: + *value = xmvis->mesa_visual.level; + return 0; + case GLX_RGBA: + if (fbconfig) + return GLX_BAD_ATTRIBUTE; + if (xmvis->mesa_visual.rgbMode) { + *value = True; + } + else { + *value = False; + } + return 0; + case GLX_DOUBLEBUFFER: + *value = (int) xmvis->mesa_visual.doubleBufferMode; + return 0; + case GLX_STEREO: + *value = (int) xmvis->mesa_visual.stereoMode; + return 0; + case GLX_AUX_BUFFERS: + *value = xmvis->mesa_visual.numAuxBuffers; + return 0; + case GLX_RED_SIZE: + *value = xmvis->mesa_visual.redBits; + return 0; + case GLX_GREEN_SIZE: + *value = xmvis->mesa_visual.greenBits; + return 0; + case GLX_BLUE_SIZE: + *value = xmvis->mesa_visual.blueBits; + return 0; + case GLX_ALPHA_SIZE: + *value = xmvis->mesa_visual.alphaBits; + return 0; + case GLX_DEPTH_SIZE: + *value = xmvis->mesa_visual.depthBits; + return 0; + case GLX_STENCIL_SIZE: + *value = xmvis->mesa_visual.stencilBits; + return 0; + case GLX_ACCUM_RED_SIZE: + *value = xmvis->mesa_visual.accumRedBits; + return 0; + case GLX_ACCUM_GREEN_SIZE: + *value = xmvis->mesa_visual.accumGreenBits; + return 0; + case GLX_ACCUM_BLUE_SIZE: + *value = xmvis->mesa_visual.accumBlueBits; + return 0; + case GLX_ACCUM_ALPHA_SIZE: + *value = xmvis->mesa_visual.accumAlphaBits; + return 0; + + /* + * GLX_EXT_visual_info extension + */ + case GLX_X_VISUAL_TYPE_EXT: + switch (xmvis->visinfo->CLASS) { + case StaticGray: *value = GLX_STATIC_GRAY_EXT; return 0; + case GrayScale: *value = GLX_GRAY_SCALE_EXT; return 0; + case StaticColor: *value = GLX_STATIC_GRAY_EXT; return 0; + case PseudoColor: *value = GLX_PSEUDO_COLOR_EXT; return 0; + case TrueColor: *value = GLX_TRUE_COLOR_EXT; return 0; + case DirectColor: *value = GLX_DIRECT_COLOR_EXT; return 0; + } + return 0; + case GLX_TRANSPARENT_TYPE_EXT: + /* normal planes */ + *value = GLX_NONE_EXT; + return 0; + case GLX_TRANSPARENT_INDEX_VALUE_EXT: + /* undefined */ + return 0; + case GLX_TRANSPARENT_RED_VALUE_EXT: + /* undefined */ + return 0; + case GLX_TRANSPARENT_GREEN_VALUE_EXT: + /* undefined */ + return 0; + case GLX_TRANSPARENT_BLUE_VALUE_EXT: + /* undefined */ + return 0; + case GLX_TRANSPARENT_ALPHA_VALUE_EXT: + /* undefined */ + return 0; + + /* + * GLX_EXT_visual_info extension + */ + case GLX_VISUAL_CAVEAT_EXT: + /* test for zero, just in case */ + if (xmvis->mesa_visual.visualRating > 0) + *value = xmvis->mesa_visual.visualRating; + else + *value = GLX_NONE_EXT; + return 0; + + /* + * GLX_ARB_multisample + */ + case GLX_SAMPLE_BUFFERS_ARB: + *value = 0; + return 0; + case GLX_SAMPLES_ARB: + *value = 0; + return 0; + + /* + * For FBConfigs: + */ + case GLX_SCREEN_EXT: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = xmvis->visinfo->screen; + break; + case GLX_DRAWABLE_TYPE: /*SGIX too */ + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; + break; + case GLX_RENDER_TYPE_SGIX: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + if (xmvis->mesa_visual.rgbMode) + *value = GLX_RGBA_BIT; + else + *value = GLX_COLOR_INDEX_BIT; + break; + case GLX_X_RENDERABLE_SGIX: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = True; /* XXX really? */ + break; + case GLX_FBCONFIG_ID_SGIX: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = xmvis->visinfo->visualid; + break; + case GLX_MAX_PBUFFER_WIDTH: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + /* XXX or MAX_WIDTH? */ + *value = DisplayWidth(xmvis->display, xmvis->visinfo->screen); + break; + case GLX_MAX_PBUFFER_HEIGHT: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = DisplayHeight(xmvis->display, xmvis->visinfo->screen); + break; + case GLX_MAX_PBUFFER_PIXELS: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = DisplayWidth(xmvis->display, xmvis->visinfo->screen) * + DisplayHeight(xmvis->display, xmvis->visinfo->screen); + break; + case GLX_VISUAL_ID: + if (!fbconfig) + return GLX_BAD_ATTRIBUTE; + *value = xmvis->visinfo->visualid; + break; + +#ifdef GLX_EXT_texture_from_pixmap + case GLX_BIND_TO_TEXTURE_RGB_EXT: + *value = True; /*XXX*/ + break; + case GLX_BIND_TO_TEXTURE_RGBA_EXT: + /* XXX review */ + *value = xmvis->mesa_visual.alphaBits > 0 ? True : False; + break; + case GLX_BIND_TO_MIPMAP_TEXTURE_EXT: + *value = True; /*XXX*/ + break; + case GLX_BIND_TO_TEXTURE_TARGETS_EXT: + *value = (GLX_TEXTURE_1D_BIT_EXT | + GLX_TEXTURE_2D_BIT_EXT | + GLX_TEXTURE_RECTANGLE_BIT_EXT); /*XXX*/ + break; + case GLX_Y_INVERTED_EXT: + *value = True; /*XXX*/ + break; +#endif + + default: + return GLX_BAD_ATTRIBUTE; + } + return Success; +} + + +int +glXGetConfig( Display *dpy, XVisualInfo *visinfo, + int attrib, int *value ) +{ + XMesaVisual xmvis; + int k; + if (!dpy || !visinfo) + return GLX_BAD_ATTRIBUTE; + + xmvis = find_glx_visual( dpy, visinfo ); + if (!xmvis) { + /* this visual wasn't obtained with glXChooseVisual */ + xmvis = create_glx_visual( dpy, visinfo ); + if (!xmvis) { + /* this visual can't be used for GL rendering */ + if (attrib==GLX_USE_GL) { + *value = (int) False; + return 0; + } + else { + return GLX_BAD_VISUAL; + } + } + } + + k = get_config(xmvis, attrib, value, GL_FALSE); + return k; +} + + +void +glXWaitGL( void ) +{ + XMesaContext xmesa = XMesaGetCurrentContext(); + XMesaFlush( xmesa ); +} + + + +void +glXWaitX( void ) +{ + XMesaContext xmesa = XMesaGetCurrentContext(); + XMesaFlush( xmesa ); +} + + +static const char * +get_extensions( void ) +{ + return EXTENSIONS; +} + + + +/* GLX 1.1 and later */ +const char * +glXQueryExtensionsString( Display *dpy, int screen ) +{ + (void) dpy; + (void) screen; + return get_extensions(); +} + + + +/* GLX 1.1 and later */ +const char * +glXQueryServerString( Display *dpy, int screen, int name ) +{ + static char version[1000]; + _mesa_sprintf(version, "%d.%d %s", + SERVER_MAJOR_VERSION, SERVER_MINOR_VERSION, MESA_GLX_VERSION); + + (void) dpy; + (void) screen; + + switch (name) { + case GLX_EXTENSIONS: + return get_extensions(); + case GLX_VENDOR: + return VENDOR; + case GLX_VERSION: + return version; + default: + return NULL; + } +} + + + +/* GLX 1.1 and later */ +const char * +glXGetClientString( Display *dpy, int name ) +{ + static char version[1000]; + _mesa_sprintf(version, "%d.%d %s", CLIENT_MAJOR_VERSION, + CLIENT_MINOR_VERSION, MESA_GLX_VERSION); + + (void) dpy; + + switch (name) { + case GLX_EXTENSIONS: + return get_extensions(); + case GLX_VENDOR: + return VENDOR; + case GLX_VERSION: + return version; + default: + return NULL; + } +} + + + +/* + * GLX 1.3 and later + */ + + +int +glXGetFBConfigAttrib( Display *dpy, GLXFBConfig config, + int attribute, int *value ) +{ + XMesaVisual v = (XMesaVisual) config; + (void) dpy; + (void) config; + + if (!dpy || !config || !value) + return -1; + + return get_config(v, attribute, value, GL_TRUE); +} + + +GLXFBConfig * +glXGetFBConfigs( Display *dpy, int screen, int *nelements ) +{ + XVisualInfo *visuals, visTemplate; + const long visMask = VisualScreenMask; + int i; + + /* Get list of all X visuals */ + visTemplate.screen = screen; + visuals = XGetVisualInfo(dpy, visMask, &visTemplate, nelements); + if (*nelements > 0) { + XMesaVisual *results; + results = (XMesaVisual *) _mesa_malloc(*nelements * sizeof(XMesaVisual)); + if (!results) { + *nelements = 0; + return NULL; + } + for (i = 0; i < *nelements; i++) { + results[i] = create_glx_visual(dpy, visuals + i); + } + return (GLXFBConfig *) results; + } + return NULL; +} + + +GLXFBConfig * +glXChooseFBConfig( Display *dpy, int screen, + const int *attribList, int *nitems ) +{ + XMesaVisual xmvis; + + if (!attribList || !attribList[0]) { + /* return list of all configs (per GLX_SGIX_fbconfig spec) */ + return glXGetFBConfigs(dpy, screen, nitems); + } + + xmvis = choose_visual(dpy, screen, attribList, GL_TRUE); + if (xmvis) { + GLXFBConfig *config = (GLXFBConfig *) _mesa_malloc(sizeof(XMesaVisual)); + if (!config) { + *nitems = 0; + return NULL; + } + *nitems = 1; + config[0] = (GLXFBConfig) xmvis; + return (GLXFBConfig *) config; + } + else { + *nitems = 0; + return NULL; + } +} + + +XVisualInfo * +glXGetVisualFromFBConfig( Display *dpy, GLXFBConfig config ) +{ + if (dpy && config) { + XMesaVisual xmvis = (XMesaVisual) config; +#if 0 + return xmvis->vishandle; +#else + /* create a new vishandle - the cached one may be stale */ + xmvis->vishandle = (XVisualInfo *) _mesa_malloc(sizeof(XVisualInfo)); + if (xmvis->vishandle) { + _mesa_memcpy(xmvis->vishandle, xmvis->visinfo, sizeof(XVisualInfo)); + } + return xmvis->vishandle; +#endif + } + else { + return NULL; + } +} + + +GLXWindow +glXCreateWindow( Display *dpy, GLXFBConfig config, Window win, + const int *attribList ) +{ + XMesaVisual xmvis = (XMesaVisual) config; + XMesaBuffer xmbuf; + if (!xmvis) + return 0; + + xmbuf = XMesaCreateWindowBuffer(xmvis, win); + if (!xmbuf) + return 0; + + (void) dpy; + (void) attribList; /* Ignored in GLX 1.3 */ + + return win; /* A hack for now */ +} + + +void +glXDestroyWindow( Display *dpy, GLXWindow window ) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, (Drawable) window); + if (b) + XMesaDestroyBuffer(b); + /* don't destroy X window */ +} + + +/* XXX untested */ +GLXPixmap +glXCreatePixmap( Display *dpy, GLXFBConfig config, Pixmap pixmap, + const int *attribList ) +{ + XMesaVisual v = (XMesaVisual) config; + XMesaBuffer b; + const int *attr; + int target = 0, format = 0, mipmap = 0; + int value; + + if (!dpy || !config || !pixmap) + return 0; + + for (attr = attribList; attr && *attr; attr++) { + switch (*attr) { + case GLX_TEXTURE_FORMAT_EXT: + attr++; + switch (*attr) { + case GLX_TEXTURE_FORMAT_NONE_EXT: + case GLX_TEXTURE_FORMAT_RGB_EXT: + case GLX_TEXTURE_FORMAT_RGBA_EXT: + format = *attr; + break; + default: + /* error */ + return 0; + } + break; + case GLX_TEXTURE_TARGET_EXT: + attr++; + switch (*attr) { + case GLX_TEXTURE_1D_EXT: + case GLX_TEXTURE_2D_EXT: + case GLX_TEXTURE_RECTANGLE_EXT: + target = *attr; + break; + default: + /* error */ + return 0; + } + break; + case GLX_MIPMAP_TEXTURE_EXT: + attr++; + if (*attr) + mipmap = 1; + break; + default: + /* error */ + return 0; + } + } + + if (format == GLX_TEXTURE_FORMAT_RGB_EXT) { + if (get_config(v, GLX_BIND_TO_TEXTURE_RGB_EXT, + &value, GL_TRUE) != Success + || !value) { + return 0; /* error! */ + } + } + else if (format == GLX_TEXTURE_FORMAT_RGBA_EXT) { + if (get_config(v, GLX_BIND_TO_TEXTURE_RGBA_EXT, + &value, GL_TRUE) != Success + || !value) { + return 0; /* error! */ + } + } + if (mipmap) { + if (get_config(v, GLX_BIND_TO_MIPMAP_TEXTURE_EXT, + &value, GL_TRUE) != Success + || !value) { + return 0; /* error! */ + } + } + if (target == GLX_TEXTURE_1D_EXT) { + if (get_config(v, GLX_BIND_TO_TEXTURE_TARGETS_EXT, + &value, GL_TRUE) != Success + || (value & GLX_TEXTURE_1D_BIT_EXT) == 0) { + return 0; /* error! */ + } + } + else if (target == GLX_TEXTURE_2D_EXT) { + if (get_config(v, GLX_BIND_TO_TEXTURE_TARGETS_EXT, + &value, GL_TRUE) != Success + || (value & GLX_TEXTURE_2D_BIT_EXT) == 0) { + return 0; /* error! */ + } + } + if (target == GLX_TEXTURE_RECTANGLE_EXT) { + if (get_config(v, GLX_BIND_TO_TEXTURE_TARGETS_EXT, + &value, GL_TRUE) != Success + || (value & GLX_TEXTURE_RECTANGLE_BIT_EXT) == 0) { + return 0; /* error! */ + } + } + + if (format || target || mipmap) { + /* texture from pixmap */ + b = XMesaCreatePixmapTextureBuffer(v, pixmap, 0, format, target, mipmap); + } + else { + b = XMesaCreatePixmapBuffer( v, pixmap, 0 ); + } + if (!b) { + return 0; + } + + return pixmap; +} + + +void +glXDestroyPixmap( Display *dpy, GLXPixmap pixmap ) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, (Drawable)pixmap); + if (b) + XMesaDestroyBuffer(b); + /* don't destroy X pixmap */ +} + + +GLXPbuffer +glXCreatePbuffer( Display *dpy, GLXFBConfig config, + const int *attribList ) +{ + XMesaVisual xmvis = (XMesaVisual) config; + XMesaBuffer xmbuf; + const int *attrib; + int width = 0, height = 0; + GLboolean useLargest = GL_FALSE, preserveContents = GL_FALSE; + + (void) dpy; + + for (attrib = attribList; *attrib; attrib++) { + switch (*attrib) { + case GLX_PBUFFER_WIDTH: + attrib++; + width = *attrib; + break; + case GLX_PBUFFER_HEIGHT: + attrib++; + height = *attrib; + break; + case GLX_PRESERVED_CONTENTS: + attrib++; + preserveContents = *attrib; /* ignored */ + break; + case GLX_LARGEST_PBUFFER: + attrib++; + useLargest = *attrib; /* ignored */ + break; + default: + return 0; + } + } + + /* not used at this time */ + (void) useLargest; + (void) preserveContents; + + if (width == 0 || height == 0) + return 0; + + xmbuf = XMesaCreatePBuffer( xmvis, 0, width, height); + /* A GLXPbuffer handle must be an X Drawable because that's what + * glXMakeCurrent takes. + */ + if (xmbuf) + return (GLXPbuffer) xmbuf->drawable; + else + return 0; +} + + +void +glXDestroyPbuffer( Display *dpy, GLXPbuffer pbuf ) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, pbuf); + if (b) { + XMesaDestroyBuffer(b); + } +} + + +void +glXQueryDrawable( Display *dpy, GLXDrawable draw, int attribute, + unsigned int *value ) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, draw); + if (!xmbuf) + return; + + switch (attribute) { + case GLX_WIDTH: + *value = xmesa_buffer_width(xmbuf); + break; + case GLX_HEIGHT: + *value = xmesa_buffer_width(xmbuf); + break; + case GLX_PRESERVED_CONTENTS: + *value = True; + break; + case GLX_LARGEST_PBUFFER: + *value = xmesa_buffer_width(xmbuf) * xmesa_buffer_height(xmbuf); + break; + case GLX_FBCONFIG_ID: + *value = xmbuf->xm_visual->visinfo->visualid; + return; +#ifdef GLX_EXT_texture_from_pixmap + case GLX_TEXTURE_FORMAT_EXT: + *value = xmbuf->TextureFormat; + break; + case GLX_TEXTURE_TARGET_EXT: + *value = xmbuf->TextureTarget; + break; + case GLX_MIPMAP_TEXTURE_EXT: + *value = xmbuf->TextureMipmap; + break; +#endif + + default: + return; /* raise BadValue error */ + } +} + + +GLXContext +glXCreateNewContext( Display *dpy, GLXFBConfig config, + int renderType, GLXContext shareList, Bool direct ) +{ + GLXContext glxCtx; + GLXContext shareCtx = shareList; + XMesaVisual xmvis = (XMesaVisual) config; + + if (!dpy || !config || + (renderType != GLX_RGBA_TYPE && renderType != GLX_COLOR_INDEX_TYPE)) + return 0; + + glxCtx = CALLOC_STRUCT(__GLXcontextRec); + if (!glxCtx) + return 0; + + /* deallocate unused windows/buffers */ + XMesaGarbageCollect(); + + glxCtx->xmesaContext = XMesaCreateContext(xmvis, + shareCtx ? shareCtx->xmesaContext : NULL); + if (!glxCtx->xmesaContext) { + _mesa_free(glxCtx); + return NULL; + } + + glxCtx->isDirect = DEFAULT_DIRECT; + glxCtx->currentDpy = dpy; + glxCtx->xid = (XID) glxCtx; /* self pointer */ + + return glxCtx; +} + + +int +glXQueryContext( Display *dpy, GLXContext ctx, int attribute, int *value ) +{ + GLXContext glxCtx = ctx; + XMesaContext xmctx = glxCtx->xmesaContext; + + (void) dpy; + (void) ctx; + + switch (attribute) { + case GLX_FBCONFIG_ID: + *value = xmctx->xm_visual->visinfo->visualid; + break; + case GLX_RENDER_TYPE: + if (xmctx->xm_visual->mesa_visual.rgbMode) + *value = GLX_RGBA_BIT; + else + *value = GLX_COLOR_INDEX_BIT; + break; + case GLX_SCREEN: + *value = 0; + return Success; + default: + return GLX_BAD_ATTRIBUTE; + } + return 0; +} + + +void +glXSelectEvent( Display *dpy, GLXDrawable drawable, unsigned long mask ) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable); + if (xmbuf) + xmbuf->selectedEvents = mask; +} + + +void +glXGetSelectedEvent( Display *dpy, GLXDrawable drawable, + unsigned long *mask ) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable); + if (xmbuf) + *mask = xmbuf->selectedEvents; + else + *mask = 0; +} + + + +/*** GLX_SGI_swap_control ***/ + +int +glXSwapIntervalSGI(int interval) +{ + (void) interval; + return 0; +} + + + +/*** GLX_SGI_video_sync ***/ + +static unsigned int FrameCounter = 0; + +int +glXGetVideoSyncSGI(unsigned int *count) +{ + /* this is a bogus implementation */ + *count = FrameCounter++; + return 0; +} + +int +glXWaitVideoSyncSGI(int divisor, int remainder, unsigned int *count) +{ + if (divisor <= 0 || remainder < 0) + return GLX_BAD_VALUE; + /* this is a bogus implementation */ + FrameCounter++; + while (FrameCounter % divisor != remainder) + FrameCounter++; + *count = FrameCounter; + return 0; +} + + + +/*** GLX_SGI_make_current_read ***/ + +Bool +glXMakeCurrentReadSGI(Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx) +{ + return glXMakeContextCurrent( dpy, draw, read, ctx ); +} + +/* not used +static GLXDrawable +glXGetCurrentReadDrawableSGI(void) +{ + return 0; +} +*/ + + +/*** GLX_SGIX_video_source ***/ +#if defined(_VL_H) + +GLXVideoSourceSGIX +glXCreateGLXVideoSourceSGIX(Display *dpy, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode) +{ + (void) dpy; + (void) screen; + (void) server; + (void) path; + (void) nodeClass; + (void) drainNode; + return 0; +} + +void +glXDestroyGLXVideoSourceSGIX(Display *dpy, GLXVideoSourceSGIX src) +{ + (void) dpy; + (void) src; +} + +#endif + + +/*** GLX_EXT_import_context ***/ + +void +glXFreeContextEXT(Display *dpy, GLXContext context) +{ + (void) dpy; + (void) context; +} + +GLXContextID +glXGetContextIDEXT(const GLXContext context) +{ + (void) context; + return 0; +} + +GLXContext +glXImportContextEXT(Display *dpy, GLXContextID contextID) +{ + (void) dpy; + (void) contextID; + return 0; +} + +int +glXQueryContextInfoEXT(Display *dpy, GLXContext context, int attribute, int *value) +{ + (void) dpy; + (void) context; + (void) attribute; + (void) value; + return 0; +} + + + +/*** GLX_SGIX_fbconfig ***/ + +int +glXGetFBConfigAttribSGIX(Display *dpy, GLXFBConfigSGIX config, int attribute, int *value) +{ + return glXGetFBConfigAttrib(dpy, config, attribute, value); +} + +GLXFBConfigSGIX * +glXChooseFBConfigSGIX(Display *dpy, int screen, int *attrib_list, int *nelements) +{ + return (GLXFBConfig *) glXChooseFBConfig(dpy, screen, attrib_list, nelements); +} + + +GLXPixmap +glXCreateGLXPixmapWithConfigSGIX(Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap) +{ + XMesaVisual xmvis = (XMesaVisual) config; + XMesaBuffer xmbuf = XMesaCreatePixmapBuffer(xmvis, pixmap, 0); + return xmbuf->drawable; /* need to return an X ID */ +} + + +GLXContext +glXCreateContextWithConfigSGIX(Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct) +{ + XMesaVisual xmvis = (XMesaVisual) config; + GLXContext glxCtx; + GLXContext shareCtx = share_list; + + glxCtx = CALLOC_STRUCT(__GLXcontextRec); + if (!glxCtx) + return 0; + + /* deallocate unused windows/buffers */ + XMesaGarbageCollect(); + + glxCtx->xmesaContext = XMesaCreateContext(xmvis, + shareCtx ? shareCtx->xmesaContext : NULL); + if (!glxCtx->xmesaContext) { + _mesa_free(glxCtx); + return NULL; + } + + glxCtx->isDirect = DEFAULT_DIRECT; + glxCtx->currentDpy = dpy; + glxCtx->xid = (XID) glxCtx; /* self pointer */ + + return glxCtx; +} + + +XVisualInfo * +glXGetVisualFromFBConfigSGIX(Display *dpy, GLXFBConfigSGIX config) +{ + return glXGetVisualFromFBConfig(dpy, config); +} + + +GLXFBConfigSGIX +glXGetFBConfigFromVisualSGIX(Display *dpy, XVisualInfo *vis) +{ + XMesaVisual xmvis = find_glx_visual(dpy, vis); + if (!xmvis) { + /* This visual wasn't found with glXChooseVisual() */ + xmvis = create_glx_visual(dpy, vis); + } + + return (GLXFBConfigSGIX) xmvis; +} + + + +/*** GLX_SGIX_pbuffer ***/ + +GLXPbufferSGIX +glXCreateGLXPbufferSGIX(Display *dpy, GLXFBConfigSGIX config, + unsigned int width, unsigned int height, + int *attribList) +{ + XMesaVisual xmvis = (XMesaVisual) config; + XMesaBuffer xmbuf; + const int *attrib; + GLboolean useLargest = GL_FALSE, preserveContents = GL_FALSE; + + (void) dpy; + + for (attrib = attribList; attrib && *attrib; attrib++) { + switch (*attrib) { + case GLX_PRESERVED_CONTENTS_SGIX: + attrib++; + preserveContents = *attrib; /* ignored */ + break; + case GLX_LARGEST_PBUFFER_SGIX: + attrib++; + useLargest = *attrib; /* ignored */ + break; + default: + return 0; + } + } + + /* not used at this time */ + (void) useLargest; + (void) preserveContents; + + xmbuf = XMesaCreatePBuffer( xmvis, 0, width, height); + /* A GLXPbuffer handle must be an X Drawable because that's what + * glXMakeCurrent takes. + */ + return (GLXPbuffer) xmbuf->drawable; +} + + +void +glXDestroyGLXPbufferSGIX(Display *dpy, GLXPbufferSGIX pbuf) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, pbuf); + if (xmbuf) { + XMesaDestroyBuffer(xmbuf); + } +} + + +int +glXQueryGLXPbufferSGIX(Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value) +{ + const XMesaBuffer xmbuf = XMesaFindBuffer(dpy, pbuf); + + if (!xmbuf) { + /* Generate GLXBadPbufferSGIX for bad pbuffer */ + return 0; + } + + switch (attribute) { + case GLX_PRESERVED_CONTENTS_SGIX: + *value = True; + break; + case GLX_LARGEST_PBUFFER_SGIX: + *value = xmesa_buffer_width(xmbuf) * xmesa_buffer_height(xmbuf); + break; + case GLX_WIDTH_SGIX: + *value = xmesa_buffer_width(xmbuf); + break; + case GLX_HEIGHT_SGIX: + *value = xmesa_buffer_height(xmbuf); + break; + case GLX_EVENT_MASK_SGIX: + *value = 0; /* XXX might be wrong */ + break; + default: + *value = 0; + } + return 0; +} + + +void +glXSelectEventSGIX(Display *dpy, GLXDrawable drawable, unsigned long mask) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable); + if (xmbuf) { + /* Note: we'll never generate clobber events */ + xmbuf->selectedEvents = mask; + } +} + + +void +glXGetSelectedEventSGIX(Display *dpy, GLXDrawable drawable, unsigned long *mask) +{ + XMesaBuffer xmbuf = XMesaFindBuffer(dpy, drawable); + if (xmbuf) { + *mask = xmbuf->selectedEvents; + } + else { + *mask = 0; + } +} + + + +/*** GLX_SGI_cushion ***/ + +void +glXCushionSGI(Display *dpy, Window win, float cushion) +{ + (void) dpy; + (void) win; + (void) cushion; +} + + + +/*** GLX_SGIX_video_resize ***/ + +int +glXBindChannelToWindowSGIX(Display *dpy, int screen, int channel , Window window) +{ + (void) dpy; + (void) screen; + (void) channel; + (void) window; + return 0; +} + +int +glXChannelRectSGIX(Display *dpy, int screen, int channel, int x, int y, int w, int h) +{ + (void) dpy; + (void) screen; + (void) channel; + (void) x; + (void) y; + (void) w; + (void) h; + return 0; +} + +int +glXQueryChannelRectSGIX(Display *dpy, int screen, int channel, int *x, int *y, int *w, int *h) +{ + (void) dpy; + (void) screen; + (void) channel; + (void) x; + (void) y; + (void) w; + (void) h; + return 0; +} + +int +glXQueryChannelDeltasSGIX(Display *dpy, int screen, int channel, int *dx, int *dy, int *dw, int *dh) +{ + (void) dpy; + (void) screen; + (void) channel; + (void) dx; + (void) dy; + (void) dw; + (void) dh; + return 0; +} + +int +glXChannelRectSyncSGIX(Display *dpy, int screen, int channel, GLenum synctype) +{ + (void) dpy; + (void) screen; + (void) channel; + (void) synctype; + return 0; +} + + + +/*** GLX_SGIX_dmbuffer **/ + +#if defined(_DM_BUFFER_H_) +Bool +glXAssociateDMPbufferSGIX(Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer) +{ + (void) dpy; + (void) pbuffer; + (void) params; + (void) dmbuffer; + return False; +} +#endif + + +/*** GLX_SGIX_swap_group ***/ + +void +glXJoinSwapGroupSGIX(Display *dpy, GLXDrawable drawable, GLXDrawable member) +{ + (void) dpy; + (void) drawable; + (void) member; +} + + + +/*** GLX_SGIX_swap_barrier ***/ + +void +glXBindSwapBarrierSGIX(Display *dpy, GLXDrawable drawable, int barrier) +{ + (void) dpy; + (void) drawable; + (void) barrier; +} + +Bool +glXQueryMaxSwapBarriersSGIX(Display *dpy, int screen, int *max) +{ + (void) dpy; + (void) screen; + (void) max; + return False; +} + + + +/*** GLX_SUN_get_transparent_index ***/ + +Status +glXGetTransparentIndexSUN(Display *dpy, Window overlay, Window underlay, long *pTransparent) +{ + (void) dpy; + (void) overlay; + (void) underlay; + (void) pTransparent; + return 0; +} + + + +/*** GLX_MESA_release_buffers ***/ + +/* + * Release the depth, stencil, accum buffers attached to a GLXDrawable + * (a window or pixmap) prior to destroying the GLXDrawable. + */ +Bool +glXReleaseBuffersMESA( Display *dpy, GLXDrawable d ) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, d); + if (b) { + XMesaDestroyBuffer(b); + return True; + } + return False; +} + +/*** GLX_EXT_texture_from_pixmap ***/ + +void +glXBindTexImageEXT(Display *dpy, GLXDrawable drawable, int buffer, + const int *attrib_list) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, drawable); + if (b) + XMesaBindTexImage(dpy, b, buffer, attrib_list); +} + +void +glXReleaseTexImageEXT(Display *dpy, GLXDrawable drawable, int buffer) +{ + XMesaBuffer b = XMesaFindBuffer(dpy, drawable); + if (b) + XMesaReleaseTexImage(dpy, b, buffer); +} diff --git a/src/gallium/state_trackers/glx/xlib/glx_getproc.c b/src/gallium/state_trackers/glx/xlib/glx_getproc.c new file mode 100644 index 0000000000..ca7d88c922 --- /dev/null +++ b/src/gallium/state_trackers/glx/xlib/glx_getproc.c @@ -0,0 +1,214 @@ +/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * glXGetProcAddress() + */ + + +#define GLX_GLXEXT_PROTOTYPES + +#include <string.h> +#include "GL/glx.h" +#include "glapi/glapi.h" + + +struct name_address_pair { + const char *Name; + __GLXextFuncPtr Address; +}; + + +static struct name_address_pair GLX_functions[] = { + /*** GLX_VERSION_1_0 ***/ + { "glXChooseVisual", (__GLXextFuncPtr) glXChooseVisual }, + { "glXCopyContext", (__GLXextFuncPtr) glXCopyContext }, + { "glXCreateContext", (__GLXextFuncPtr) glXCreateContext }, + { "glXCreateGLXPixmap", (__GLXextFuncPtr) glXCreateGLXPixmap }, + { "glXDestroyContext", (__GLXextFuncPtr) glXDestroyContext }, + { "glXDestroyGLXPixmap", (__GLXextFuncPtr) glXDestroyGLXPixmap }, + { "glXGetConfig", (__GLXextFuncPtr) glXGetConfig }, + { "glXGetCurrentContext", (__GLXextFuncPtr) glXGetCurrentContext }, + { "glXGetCurrentDrawable", (__GLXextFuncPtr) glXGetCurrentDrawable }, + { "glXIsDirect", (__GLXextFuncPtr) glXIsDirect }, + { "glXMakeCurrent", (__GLXextFuncPtr) glXMakeCurrent }, + { "glXQueryExtension", (__GLXextFuncPtr) glXQueryExtension }, + { "glXQueryVersion", (__GLXextFuncPtr) glXQueryVersion }, + { "glXSwapBuffers", (__GLXextFuncPtr) glXSwapBuffers }, + { "glXUseXFont", (__GLXextFuncPtr) glXUseXFont }, + { "glXWaitGL", (__GLXextFuncPtr) glXWaitGL }, + { "glXWaitX", (__GLXextFuncPtr) glXWaitX }, + + /*** GLX_VERSION_1_1 ***/ + { "glXGetClientString", (__GLXextFuncPtr) glXGetClientString }, + { "glXQueryExtensionsString", (__GLXextFuncPtr) glXQueryExtensionsString }, + { "glXQueryServerString", (__GLXextFuncPtr) glXQueryServerString }, + + /*** GLX_VERSION_1_2 ***/ + { "glXGetCurrentDisplay", (__GLXextFuncPtr) glXGetCurrentDisplay }, + + /*** GLX_VERSION_1_3 ***/ + { "glXChooseFBConfig", (__GLXextFuncPtr) glXChooseFBConfig }, + { "glXCreateNewContext", (__GLXextFuncPtr) glXCreateNewContext }, + { "glXCreatePbuffer", (__GLXextFuncPtr) glXCreatePbuffer }, + { "glXCreatePixmap", (__GLXextFuncPtr) glXCreatePixmap }, + { "glXCreateWindow", (__GLXextFuncPtr) glXCreateWindow }, + { "glXDestroyPbuffer", (__GLXextFuncPtr) glXDestroyPbuffer }, + { "glXDestroyPixmap", (__GLXextFuncPtr) glXDestroyPixmap }, + { "glXDestroyWindow", (__GLXextFuncPtr) glXDestroyWindow }, + { "glXGetCurrentReadDrawable", (__GLXextFuncPtr) glXGetCurrentReadDrawable }, + { "glXGetFBConfigAttrib", (__GLXextFuncPtr) glXGetFBConfigAttrib }, + { "glXGetFBConfigs", (__GLXextFuncPtr) glXGetFBConfigs }, + { "glXGetSelectedEvent", (__GLXextFuncPtr) glXGetSelectedEvent }, + { "glXGetVisualFromFBConfig", (__GLXextFuncPtr) glXGetVisualFromFBConfig }, + { "glXMakeContextCurrent", (__GLXextFuncPtr) glXMakeContextCurrent }, + { "glXQueryContext", (__GLXextFuncPtr) glXQueryContext }, + { "glXQueryDrawable", (__GLXextFuncPtr) glXQueryDrawable }, + { "glXSelectEvent", (__GLXextFuncPtr) glXSelectEvent }, + + /*** GLX_VERSION_1_4 ***/ + { "glXGetProcAddress", (__GLXextFuncPtr) glXGetProcAddress }, + + /*** GLX_SGI_swap_control ***/ + { "glXSwapIntervalSGI", (__GLXextFuncPtr) glXSwapIntervalSGI }, + + /*** GLX_SGI_video_sync ***/ + { "glXGetVideoSyncSGI", (__GLXextFuncPtr) glXGetVideoSyncSGI }, + { "glXWaitVideoSyncSGI", (__GLXextFuncPtr) glXWaitVideoSyncSGI }, + + /*** GLX_SGI_make_current_read ***/ + { "glXMakeCurrentReadSGI", (__GLXextFuncPtr) glXMakeCurrentReadSGI }, + { "glXGetCurrentReadDrawableSGI", (__GLXextFuncPtr) glXGetCurrentReadDrawableSGI }, + + /*** GLX_SGIX_video_source ***/ +#if defined(_VL_H) + { "glXCreateGLXVideoSourceSGIX", (__GLXextFuncPtr) glXCreateGLXVideoSourceSGIX }, + { "glXDestroyGLXVideoSourceSGIX", (__GLXextFuncPtr) glXDestroyGLXVideoSourceSGIX }, +#endif + + /*** GLX_EXT_import_context ***/ + { "glXFreeContextEXT", (__GLXextFuncPtr) glXFreeContextEXT }, + { "glXGetContextIDEXT", (__GLXextFuncPtr) glXGetContextIDEXT }, + { "glXGetCurrentDisplayEXT", (__GLXextFuncPtr) glXGetCurrentDisplayEXT }, + { "glXImportContextEXT", (__GLXextFuncPtr) glXImportContextEXT }, + { "glXQueryContextInfoEXT", (__GLXextFuncPtr) glXQueryContextInfoEXT }, + + /*** GLX_SGIX_fbconfig ***/ + { "glXGetFBConfigAttribSGIX", (__GLXextFuncPtr) glXGetFBConfigAttribSGIX }, + { "glXChooseFBConfigSGIX", (__GLXextFuncPtr) glXChooseFBConfigSGIX }, + { "glXCreateGLXPixmapWithConfigSGIX", (__GLXextFuncPtr) glXCreateGLXPixmapWithConfigSGIX }, + { "glXCreateContextWithConfigSGIX", (__GLXextFuncPtr) glXCreateContextWithConfigSGIX }, + { "glXGetVisualFromFBConfigSGIX", (__GLXextFuncPtr) glXGetVisualFromFBConfigSGIX }, + { "glXGetFBConfigFromVisualSGIX", (__GLXextFuncPtr) glXGetFBConfigFromVisualSGIX }, + + /*** GLX_SGIX_pbuffer ***/ + { "glXCreateGLXPbufferSGIX", (__GLXextFuncPtr) glXCreateGLXPbufferSGIX }, + { "glXDestroyGLXPbufferSGIX", (__GLXextFuncPtr) glXDestroyGLXPbufferSGIX }, + { "glXQueryGLXPbufferSGIX", (__GLXextFuncPtr) glXQueryGLXPbufferSGIX }, + { "glXSelectEventSGIX", (__GLXextFuncPtr) glXSelectEventSGIX }, + { "glXGetSelectedEventSGIX", (__GLXextFuncPtr) glXGetSelectedEventSGIX }, + + /*** GLX_SGI_cushion ***/ + { "glXCushionSGI", (__GLXextFuncPtr) glXCushionSGI }, + + /*** GLX_SGIX_video_resize ***/ + { "glXBindChannelToWindowSGIX", (__GLXextFuncPtr) glXBindChannelToWindowSGIX }, + { "glXChannelRectSGIX", (__GLXextFuncPtr) glXChannelRectSGIX }, + { "glXQueryChannelRectSGIX", (__GLXextFuncPtr) glXQueryChannelRectSGIX }, + { "glXQueryChannelDeltasSGIX", (__GLXextFuncPtr) glXQueryChannelDeltasSGIX }, + { "glXChannelRectSyncSGIX", (__GLXextFuncPtr) glXChannelRectSyncSGIX }, + + /*** GLX_SGIX_dmbuffer **/ +#if defined(_DM_BUFFER_H_) + { "glXAssociateDMPbufferSGIX", (__GLXextFuncPtr) glXAssociateDMPbufferSGIX }, +#endif + + /*** GLX_SGIX_swap_group ***/ + { "glXJoinSwapGroupSGIX", (__GLXextFuncPtr) glXJoinSwapGroupSGIX }, + + /*** GLX_SGIX_swap_barrier ***/ + { "glXBindSwapBarrierSGIX", (__GLXextFuncPtr) glXBindSwapBarrierSGIX }, + { "glXQueryMaxSwapBarriersSGIX", (__GLXextFuncPtr) glXQueryMaxSwapBarriersSGIX }, + + /*** GLX_SUN_get_transparent_index ***/ + { "glXGetTransparentIndexSUN", (__GLXextFuncPtr) glXGetTransparentIndexSUN }, + + /*** GLX_MESA_copy_sub_buffer ***/ + { "glXCopySubBufferMESA", (__GLXextFuncPtr) glXCopySubBufferMESA }, + + /*** GLX_MESA_pixmap_colormap ***/ + { "glXCreateGLXPixmapMESA", (__GLXextFuncPtr) glXCreateGLXPixmapMESA }, + + /*** GLX_MESA_release_buffers ***/ + { "glXReleaseBuffersMESA", (__GLXextFuncPtr) glXReleaseBuffersMESA }, + + /*** GLX_ARB_get_proc_address ***/ + { "glXGetProcAddressARB", (__GLXextFuncPtr) glXGetProcAddressARB }, + + /*** GLX_EXT_texture_from_pixmap ***/ + { "glXBindTexImageEXT", (__GLXextFuncPtr) glXBindTexImageEXT }, + { "glXReleaseTexImageEXT", (__GLXextFuncPtr) glXReleaseTexImageEXT }, + + { NULL, NULL } /* end of list */ +}; + + + +/** + * Return address of named glX function, or NULL if not found. + */ +static __GLXextFuncPtr +_glxapi_get_proc_address(const char *funcName) +{ + GLuint i; + for (i = 0; GLX_functions[i].Name; i++) { + if (strcmp(GLX_functions[i].Name, funcName) == 0) + return GLX_functions[i].Address; + } + return NULL; +} + + +__GLXextFuncPtr +glXGetProcAddressARB(const GLubyte *procName) +{ + __GLXextFuncPtr f; + + f = _glxapi_get_proc_address((const char *) procName); + if (f) { + return f; + } + + f = (__GLXextFuncPtr) _glapi_get_proc_address((const char *) procName); + return f; +} + + +/* GLX 1.4 */ +void (*glXGetProcAddress(const GLubyte *procName))() +{ + return glXGetProcAddressARB(procName); +} diff --git a/src/gallium/state_trackers/glx/xlib/glx_usefont.c b/src/gallium/state_trackers/glx/xlib/glx_usefont.c new file mode 100644 index 0000000000..acc64df62b --- /dev/null +++ b/src/gallium/state_trackers/glx/xlib/glx_usefont.c @@ -0,0 +1,375 @@ +/* + * Mesa 3-D graphics library + * Version: 7.6 + * + * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de + * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. + * Copyright (C) 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * Fake implementation of glXUseXFont(). + */ + + +#include "main/context.h" +#include "main/imports.h" +#include <GL/glx.h> + + +/* Some debugging info. */ + +#ifdef DEBUG +#undef _R +#undef _G +#undef _B +#include <ctype.h> + +int debug_xfonts = 0; + +static void +dump_char_struct(XCharStruct * ch, char *prefix) +{ + printf("%slbearing = %d, rbearing = %d, width = %d\n", + prefix, ch->lbearing, ch->rbearing, ch->width); + printf("%sascent = %d, descent = %d, attributes = %u\n", + prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes); +} + +static void +dump_font_struct(XFontStruct * font) +{ + printf("ascent = %d, descent = %d\n", font->ascent, font->descent); + printf("char_or_byte2 = (%u,%u)\n", + font->min_char_or_byte2, font->max_char_or_byte2); + printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1); + printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False"); + printf("default_char = %c (\\%03o)\n", + (char) (isprint(font->default_char) ? font->default_char : ' '), + font->default_char); + dump_char_struct(&font->min_bounds, "min> "); + dump_char_struct(&font->max_bounds, "max> "); +#if 0 + for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) { + char prefix[8]; + sprintf(prefix, "%d> ", c); + dump_char_struct(&font->per_char[c], prefix); + } +#endif +} + +static void +dump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap) +{ + unsigned int x, y; + + printf(" "); + for (x = 0; x < 8 * width; x++) + printf("%o", 7 - (x % 8)); + putchar('\n'); + for (y = 0; y < height; y++) { + printf("%3o:", y); + for (x = 0; x < 8 * width; x++) + putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x % + 8)))) + ? '*' : '.'); + printf(" "); + for (x = 0; x < width; x++) + printf("0x%02x, ", bitmap[width * (height - y - 1) + x]); + putchar('\n'); + } +} +#endif /* DEBUG */ + + +/* Implementation. */ + +/* Fill a BITMAP with a character C from thew current font + in the graphics context GC. WIDTH is the width in bytes + and HEIGHT is the height in bits. + + Note that the generated bitmaps must be used with + + glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE); + glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + + Possible optimizations: + + * use only one reusable pixmap with the maximum dimensions. + * draw the entire font into a single pixmap (careful with + proportional fonts!). +*/ + + +/* + * Generate OpenGL-compatible bitmap. + */ +static void +fill_bitmap(Display * dpy, Window win, GC gc, + unsigned int width, unsigned int height, + int x0, int y0, unsigned int c, GLubyte * bitmap) +{ + XImage *image; + unsigned int x, y; + Pixmap pixmap; + XChar2b char2b; + + pixmap = XCreatePixmap(dpy, win, 8 * width, height, 1); + XSetForeground(dpy, gc, 0); + XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height); + XSetForeground(dpy, gc, 1); + + char2b.byte1 = (c >> 8) & 0xff; + char2b.byte2 = (c & 0xff); + + XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1); + + image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap); + if (image) { + /* Fill the bitmap (X11 and OpenGL are upside down wrt each other). */ + for (y = 0; y < height; y++) + for (x = 0; x < 8 * width; x++) + if (XGetPixel(image, x, y)) + bitmap[width * (height - y - 1) + x / 8] |= + (1 << (7 - (x % 8))); + XDestroyImage(image); + } + + XFreePixmap(dpy, pixmap); +} + +/* + * determine if a given glyph is valid and return the + * corresponding XCharStruct. + */ +static XCharStruct * +isvalid(XFontStruct * fs, unsigned int which) +{ + unsigned int rows, pages; + unsigned int byte1 = 0, byte2 = 0; + int i, valid = 1; + + rows = fs->max_byte1 - fs->min_byte1 + 1; + pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; + + if (rows == 1) { + /* "linear" fonts */ + if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which)) + valid = 0; + } + else { + /* "matrix" fonts */ + byte2 = which & 0xff; + byte1 = which >> 8; + if ((fs->min_char_or_byte2 > byte2) || + (fs->max_char_or_byte2 < byte2) || + (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1)) + valid = 0; + } + + if (valid) { + if (fs->per_char) { + if (rows == 1) { + /* "linear" fonts */ + return (fs->per_char + (which - fs->min_char_or_byte2)); + } + else { + /* "matrix" fonts */ + i = ((byte1 - fs->min_byte1) * pages) + + (byte2 - fs->min_char_or_byte2); + return (fs->per_char + i); + } + } + else { + return (&fs->min_bounds); + } + } + return (NULL); +} + + +void +glXUseXFont(Font font, int first, int count, int listbase) +{ + Display *dpy; + Window win; + Pixmap pixmap; + GC gc; + XGCValues values; + unsigned long valuemask; + XFontStruct *fs; + GLint swapbytes, lsbfirst, rowlength; + GLint skiprows, skippixels, alignment; + unsigned int max_width, max_height, max_bm_width, max_bm_height; + GLubyte *bm; + int i; + + dpy = glXGetCurrentDisplay(); + if (!dpy) + return; /* I guess glXMakeCurrent wasn't called */ + i = DefaultScreen(dpy); + win = RootWindow(dpy, i); + + fs = XQueryFont(dpy, font); + if (!fs) { + _mesa_error(NULL, GL_INVALID_VALUE, + "Couldn't get font structure information"); + return; + } + + /* Allocate a bitmap that can fit all characters. */ + max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing; + max_height = fs->max_bounds.ascent + fs->max_bounds.descent; + max_bm_width = (max_width + 7) / 8; + max_bm_height = max_height; + + bm = (GLubyte *) MALLOC((max_bm_width * max_bm_height) * sizeof(GLubyte)); + if (!bm) { + XFreeFontInfo(NULL, fs, 1); + _mesa_error(NULL, GL_OUT_OF_MEMORY, + "Couldn't allocate bitmap in glXUseXFont()"); + return; + } + +#if 0 + /* get the page info */ + pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; + firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2; + lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2; + rows = fs->max_byte1 - fs->min_byte1 + 1; + unsigned int first_char, last_char, pages, rows; +#endif + + /* Save the current packing mode for bitmaps. */ + glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes); + glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst); + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength); + glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows); + glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels); + glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); + + /* Enforce a standard packing mode which is compatible with + fill_bitmap() from above. This is actually the default mode, + except for the (non)alignment. */ + glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + pixmap = XCreatePixmap(dpy, win, 10, 10, 1); + values.foreground = BlackPixel(dpy, DefaultScreen(dpy)); + values.background = WhitePixel(dpy, DefaultScreen(dpy)); + values.font = fs->fid; + valuemask = GCForeground | GCBackground | GCFont; + gc = XCreateGC(dpy, pixmap, valuemask, &values); + XFreePixmap(dpy, pixmap); + +#ifdef DEBUG + if (debug_xfonts) + dump_font_struct(fs); +#endif + + for (i = 0; i < count; i++) { + unsigned int width, height, bm_width, bm_height; + GLfloat x0, y0, dx, dy; + XCharStruct *ch; + int x, y; + unsigned int c = first + i; + int list = listbase + i; + int valid; + + /* check on index validity and get the bounds */ + ch = isvalid(fs, c); + if (!ch) { + ch = &fs->max_bounds; + valid = 0; + } + else { + valid = 1; + } + +#ifdef DEBUG + if (debug_xfonts) { + char s[7]; + sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c); + dump_char_struct(ch, s); + } +#endif + + /* glBitmap()' parameters: + straight from the glXUseXFont(3) manpage. */ + width = ch->rbearing - ch->lbearing; + height = ch->ascent + ch->descent; + x0 = -ch->lbearing; + y0 = ch->descent - 0; /* XXX used to subtract 1 here */ + /* but that caused a conformace failure */ + dx = ch->width; + dy = 0; + + /* X11's starting point. */ + x = -ch->lbearing; + y = ch->ascent; + + /* Round the width to a multiple of eight. We will use this also + for the pixmap for capturing the X11 font. This is slightly + inefficient, but it makes the OpenGL part real easy. */ + bm_width = (width + 7) / 8; + bm_height = height; + + glNewList(list, GL_COMPILE); + if (valid && (bm_width > 0) && (bm_height > 0)) { + + MEMSET(bm, '\0', bm_width * bm_height); + fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm); + + glBitmap(width, height, x0, y0, dx, dy, bm); +#ifdef DEBUG + if (debug_xfonts) { + printf("width/height = %u/%u\n", width, height); + printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height); + dump_bitmap(bm_width, bm_height, bm); + } +#endif + } + else { + glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL); + } + glEndList(); + } + + FREE(bm); + XFreeFontInfo(NULL, fs, 1); + XFreeGC(dpy, gc); + + /* Restore saved packing modes. */ + glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes); + glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst); + glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength); + glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels); + glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); +} diff --git a/src/gallium/state_trackers/glx/xlib/xm_api.c b/src/gallium/state_trackers/glx/xlib/xm_api.c new file mode 100644 index 0000000000..957002ddd5 --- /dev/null +++ b/src/gallium/state_trackers/glx/xlib/xm_api.c @@ -0,0 +1,1220 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \file xm_api.c + * + * All the XMesa* API functions. + * + * + * NOTES: + * + * The window coordinate system origin (0,0) is in the lower-left corner + * of the window. X11's window coordinate origin is in the upper-left + * corner of the window. Therefore, most drawing functions in this + * file have to flip Y coordinates. + * + * Define USE_XSHM in the Makefile with -DUSE_XSHM if you want to compile + * in support for the MIT Shared Memory extension. If enabled, when you + * use an Ximage for the back buffer in double buffered mode, the "swap" + * operation will be faster. You must also link with -lXext. + * + * Byte swapping: If the Mesa host and the X display use a different + * byte order then there's some trickiness to be aware of when using + * XImages. The byte ordering used for the XImage is that of the X + * display, not the Mesa host. + * The color-to-pixel encoding for True/DirectColor must be done + * according to the display's visual red_mask, green_mask, and blue_mask. + * If XPutPixel is used to put a pixel into an XImage then XPutPixel will + * do byte swapping if needed. If one wants to directly "poke" the pixel + * into the XImage's buffer then the pixel must be byte swapped first. + * + */ + +#ifdef __CYGWIN__ +#undef WIN32 +#undef __WIN32__ +#endif + +#include "xm_api.h" +#include "main/context.h" +#include "main/framebuffer.h" + +#include "state_tracker/st_public.h" +#include "state_tracker/st_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_screen.h" +#include "pipe/p_context.h" + +#include "xm_winsys.h" +#include <GL/glx.h> + + +/* Driver interface routines, set up by xlib backend on library + * _init(). These are global in the same way that function names are + * global. + */ +static struct xm_driver driver; + +void xmesa_set_driver( const struct xm_driver *templ ) +{ + driver = *templ; +} + +/** + * Global X driver lock + */ +pipe_mutex _xmesa_lock; + + + +/**********************************************************************/ +/***** X Utility Functions *****/ +/**********************************************************************/ + + +/** + * Return the host's byte order as LSBFirst or MSBFirst ala X. + */ +static int host_byte_order( void ) +{ + int i = 1; + char *cptr = (char *) &i; + return (*cptr==1) ? LSBFirst : MSBFirst; +} + + +/** + * Check if the X Shared Memory extension is available. + * Return: 0 = not available + * 1 = shared XImage support available + * 2 = shared Pixmap support available also + */ +int xmesa_check_for_xshm( Display *display ) +{ +#if defined(USE_XSHM) + int major, minor, ignore; + Bool pixmaps; + + if (getenv("SP_NO_RAST")) + return 0; + + if (getenv("MESA_NOSHM")) { + return 0; + } + + if (XQueryExtension( display, "MIT-SHM", &ignore, &ignore, &ignore )) { + if (XShmQueryVersion( display, &major, &minor, &pixmaps )==True) { + return (pixmaps==True) ? 2 : 1; + } + else { + return 0; + } + } + else { + return 0; + } +#else + /* No XSHM support */ + return 0; +#endif +} + + +/** + * Return the true number of bits per pixel for XImages. + * For example, if we request a 24-bit deep visual we may actually need/get + * 32bpp XImages. This function returns the appropriate bpp. + * Input: dpy - the X display + * visinfo - desribes the visual to be used for XImages + * Return: true number of bits per pixel for XImages + */ +static int +bits_per_pixel( XMesaVisual xmv ) +{ + Display *dpy = xmv->display; + XVisualInfo * visinfo = xmv->visinfo; + XImage *img; + int bitsPerPixel; + /* Create a temporary XImage */ + img = XCreateImage( dpy, visinfo->visual, visinfo->depth, + ZPixmap, 0, /*format, offset*/ + (char*) MALLOC(8), /*data*/ + 1, 1, /*width, height*/ + 32, /*bitmap_pad*/ + 0 /*bytes_per_line*/ + ); + assert(img); + /* grab the bits/pixel value */ + bitsPerPixel = img->bits_per_pixel; + /* free the XImage */ + _mesa_free( img->data ); + img->data = NULL; + XDestroyImage( img ); + return bitsPerPixel; +} + + + +/* + * Determine if a given X window ID is valid (window exists). + * Do this by calling XGetWindowAttributes() for the window and + * checking if we catch an X error. + * Input: dpy - the display + * win - the window to check for existance + * Return: GL_TRUE - window exists + * GL_FALSE - window doesn't exist + */ +static GLboolean WindowExistsFlag; + +static int window_exists_err_handler( Display* dpy, XErrorEvent* xerr ) +{ + (void) dpy; + if (xerr->error_code == BadWindow) { + WindowExistsFlag = GL_FALSE; + } + return 0; +} + +static GLboolean window_exists( Display *dpy, Window win ) +{ + XWindowAttributes wa; + int (*old_handler)( Display*, XErrorEvent* ); + WindowExistsFlag = GL_TRUE; + old_handler = XSetErrorHandler(window_exists_err_handler); + XGetWindowAttributes( dpy, win, &wa ); /* dummy request */ + XSetErrorHandler(old_handler); + return WindowExistsFlag; +} + +static Status +get_drawable_size( Display *dpy, Drawable d, uint *width, uint *height ) +{ + Window root; + Status stat; + int xpos, ypos; + unsigned int w, h, bw, depth; + stat = XGetGeometry(dpy, d, &root, &xpos, &ypos, &w, &h, &bw, &depth); + *width = w; + *height = h; + return stat; +} + + +/** + * Return the size of the window (or pixmap) that corresponds to the + * given XMesaBuffer. + * \param width returns width in pixels + * \param height returns height in pixels + */ +static void +xmesa_get_window_size(Display *dpy, XMesaBuffer b, + GLuint *width, GLuint *height) +{ + Status stat; + + pipe_mutex_lock(_xmesa_lock); + XSync(b->xm_visual->display, 0); /* added for Chromium */ + stat = get_drawable_size(dpy, b->drawable, width, height); + pipe_mutex_unlock(_xmesa_lock); + + if (!stat) { + /* probably querying a window that's recently been destroyed */ + _mesa_warning(NULL, "XGetGeometry failed!\n"); + *width = *height = 1; + } +} + +#define GET_REDMASK(__v) __v->mesa_visual.redMask +#define GET_GREENMASK(__v) __v->mesa_visual.greenMask +#define GET_BLUEMASK(__v) __v->mesa_visual.blueMask + + +/** + * Choose the pixel format for the given visual. + * This will tell the gallium driver how to pack pixel data into + * drawing surfaces. + */ +static GLuint +choose_pixel_format(XMesaVisual v) +{ + boolean native_byte_order = (host_byte_order() == + ImageByteOrder(v->display)); + + if ( GET_REDMASK(v) == 0x0000ff + && GET_GREENMASK(v) == 0x00ff00 + && GET_BLUEMASK(v) == 0xff0000 + && v->BitsPerPixel == 32) { + if (native_byte_order) { + /* no byteswapping needed */ + return 0 /* PIXEL_FORMAT_U_A8_B8_G8_R8 */; + } + else { + return PIPE_FORMAT_R8G8B8A8_UNORM; + } + } + else if ( GET_REDMASK(v) == 0xff0000 + && GET_GREENMASK(v) == 0x00ff00 + && GET_BLUEMASK(v) == 0x0000ff + && v->BitsPerPixel == 32) { + if (native_byte_order) { + /* no byteswapping needed */ + return PIPE_FORMAT_A8R8G8B8_UNORM; + } + else { + return PIPE_FORMAT_B8G8R8A8_UNORM; + } + } + else if ( GET_REDMASK(v) == 0x0000ff00 + && GET_GREENMASK(v) == 0x00ff0000 + && GET_BLUEMASK(v) == 0xff000000 + && v->BitsPerPixel == 32) { + if (native_byte_order) { + /* no byteswapping needed */ + return PIPE_FORMAT_B8G8R8A8_UNORM; + } + else { + return PIPE_FORMAT_A8R8G8B8_UNORM; + } + } + else if ( GET_REDMASK(v) == 0xf800 + && GET_GREENMASK(v) == 0x07e0 + && GET_BLUEMASK(v) == 0x001f + && native_byte_order + && v->BitsPerPixel == 16) { + /* 5-6-5 RGB */ + return PIPE_FORMAT_R5G6B5_UNORM; + } + + assert(0); + return 0; +} + + + +/**********************************************************************/ +/***** Linked list of XMesaBuffers *****/ +/**********************************************************************/ + +XMesaBuffer XMesaBufferList = NULL; + + +/** + * Allocate a new XMesaBuffer object which corresponds to the given drawable. + * Note that XMesaBuffer is derived from GLframebuffer. + * The new XMesaBuffer will not have any size (Width=Height=0). + * + * \param d the corresponding X drawable (window or pixmap) + * \param type either WINDOW, PIXMAP or PBUFFER, describing d + * \param vis the buffer's visual + * \param cmap the window's colormap, if known. + * \return new XMesaBuffer or NULL if any problem + */ +static XMesaBuffer +create_xmesa_buffer(Drawable d, BufferType type, + XMesaVisual vis, Colormap cmap) +{ + XMesaBuffer b; + GLframebuffer *fb; + enum pipe_format colorFormat, depthFormat, stencilFormat; + uint width, height; + + ASSERT(type == WINDOW || type == PIXMAP || type == PBUFFER); + + b = (XMesaBuffer) CALLOC_STRUCT(xmesa_buffer); + if (!b) + return NULL; + + b->drawable = d; + + b->xm_visual = vis; + b->type = type; + b->cmap = cmap; + + /* determine PIPE_FORMATs for buffers */ + colorFormat = choose_pixel_format(vis); + + if (vis->mesa_visual.depthBits == 0) + depthFormat = PIPE_FORMAT_NONE; +#ifdef GALLIUM_CELL /* XXX temporary for Cell! */ + else + depthFormat = PIPE_FORMAT_S8Z24_UNORM; +#else + else if (vis->mesa_visual.depthBits <= 16) + depthFormat = PIPE_FORMAT_Z16_UNORM; + else if (vis->mesa_visual.depthBits <= 24) + depthFormat = PIPE_FORMAT_S8Z24_UNORM; + else + depthFormat = PIPE_FORMAT_Z32_UNORM; +#endif + + if (vis->mesa_visual.stencilBits == 8) { + if (depthFormat == PIPE_FORMAT_S8Z24_UNORM) + stencilFormat = depthFormat; + else + stencilFormat = PIPE_FORMAT_S8_UNORM; + } + else { + /* no stencil */ + stencilFormat = PIPE_FORMAT_NONE; + if (depthFormat == PIPE_FORMAT_S8Z24_UNORM) { + /* use 24-bit Z, undefined stencil channel */ + depthFormat = PIPE_FORMAT_X8Z24_UNORM; + } + } + + + get_drawable_size(vis->display, d, &width, &height); + + /* + * Create framebuffer, but we'll plug in our own renderbuffers below. + */ + b->stfb = st_create_framebuffer(&vis->mesa_visual, + colorFormat, depthFormat, stencilFormat, + width, height, + (void *) b); + fb = &b->stfb->Base; + + /* + * Create scratch XImage for xmesa_display_surface() + */ + b->tempImage = XCreateImage(vis->display, + vis->visinfo->visual, + vis->visinfo->depth, + ZPixmap, 0, /* format, offset */ + NULL, /* data */ + 0, 0, /* size */ + 32, /* bitmap_pad */ + 0); /* bytes_per_line */ + + /* GLX_EXT_texture_from_pixmap */ + b->TextureTarget = 0; + b->TextureFormat = GLX_TEXTURE_FORMAT_NONE_EXT; + b->TextureMipmap = 0; + + /* insert buffer into linked list */ + b->Next = XMesaBufferList; + XMesaBufferList = b; + + return b; +} + + +/** + * Find an XMesaBuffer by matching X display and colormap but NOT matching + * the notThis buffer. + */ +XMesaBuffer +xmesa_find_buffer(Display *dpy, Colormap cmap, XMesaBuffer notThis) +{ + XMesaBuffer b; + for (b = XMesaBufferList; b; b = b->Next) { + if (b->xm_visual->display == dpy && + b->cmap == cmap && + b != notThis) { + return b; + } + } + return NULL; +} + + +/** + * Remove buffer from linked list, delete if no longer referenced. + */ +static void +xmesa_free_buffer(XMesaBuffer buffer) +{ + XMesaBuffer prev = NULL, b; + + for (b = XMesaBufferList; b; b = b->Next) { + if (b == buffer) { + struct gl_framebuffer *fb = &buffer->stfb->Base; + + /* unlink buffer from list */ + if (prev) + prev->Next = buffer->Next; + else + XMesaBufferList = buffer->Next; + + /* mark as delete pending */ + fb->DeletePending = GL_TRUE; + + /* Since the X window for the XMesaBuffer is going away, we don't + * want to dereference this pointer in the future. + */ + b->drawable = 0; + + buffer->tempImage->data = NULL; + XDestroyImage(buffer->tempImage); + + /* Unreference. If count = zero we'll really delete the buffer */ + _mesa_reference_framebuffer(&fb, NULL); + + XFreeGC(b->xm_visual->display, b->gc); + + free(buffer); + + return; + } + /* continue search */ + prev = b; + } + /* buffer not found in XMesaBufferList */ + _mesa_problem(NULL,"xmesa_free_buffer() - buffer not found\n"); +} + + + +/**********************************************************************/ +/***** Misc Private Functions *****/ +/**********************************************************************/ + + +/** + * When a context is bound for the first time, we can finally finish + * initializing the context's visual and buffer information. + * \param v the XMesaVisual to initialize + * \param b the XMesaBuffer to initialize (may be NULL) + * \param rgb_flag TRUE = RGBA mode, FALSE = color index mode + * \param window the window/pixmap we're rendering into + * \param cmap the colormap associated with the window/pixmap + * \return GL_TRUE=success, GL_FALSE=failure + */ +static GLboolean +initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b, + GLboolean rgb_flag, Drawable window, + Colormap cmap) +{ + ASSERT(!b || b->xm_visual == v); + + /* Save true bits/pixel */ + v->BitsPerPixel = bits_per_pixel(v); + assert(v->BitsPerPixel > 0); + + if (rgb_flag == GL_FALSE) { + /* COLOR-INDEXED WINDOW: not supported*/ + return GL_FALSE; + } + else { + /* RGB WINDOW: + * We support RGB rendering into almost any kind of visual. + */ + const int xclass = v->mesa_visual.visualType; + if (xclass != GLX_TRUE_COLOR && xclass == !GLX_DIRECT_COLOR) { + _mesa_warning(NULL, + "XMesa: RGB mode rendering not supported in given visual.\n"); + return GL_FALSE; + } + v->mesa_visual.indexBits = 0; + + if (v->BitsPerPixel == 32) { + /* We use XImages for all front/back buffers. If an X Window or + * X Pixmap is 32bpp, there's no guarantee that the alpha channel + * will be preserved. For XImages we're in luck. + */ + v->mesa_visual.alphaBits = 8; + } + } + + /* + * If MESA_INFO env var is set print out some debugging info + * which can help Brian figure out what's going on when a user + * reports bugs. + */ + if (_mesa_getenv("MESA_INFO")) { + _mesa_printf("X/Mesa visual = %p\n", (void *) v); + _mesa_printf("X/Mesa level = %d\n", v->mesa_visual.level); + _mesa_printf("X/Mesa depth = %d\n", v->visinfo->depth); + _mesa_printf("X/Mesa bits per pixel = %d\n", v->BitsPerPixel); + } + + if (b && window) { + /* these should have been set in create_xmesa_buffer */ + ASSERT(b->drawable == window); + + /* Setup for single/double buffering */ + if (v->mesa_visual.doubleBufferMode) { + /* Double buffered */ + b->shm = xmesa_check_for_xshm( v->display ); + } + + /* X11 graphics context */ + b->gc = XCreateGC( v->display, window, 0, NULL ); + XSetFunction( v->display, b->gc, GXcopy ); + } + + return GL_TRUE; +} + + + +#define NUM_VISUAL_TYPES 6 + +/** + * Convert an X visual type to a GLX visual type. + * + * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.) + * to be converted. + * \return If \c visualType is a valid X visual type, a GLX visual type will + * be returned. Otherwise \c GLX_NONE will be returned. + * + * \note + * This code was lifted directly from lib/GL/glx/glcontextmodes.c in the + * DRI CVS tree. + */ +static GLint +xmesa_convert_from_x_visual_type( int visualType ) +{ + static const int glx_visual_types[ NUM_VISUAL_TYPES ] = { + GLX_STATIC_GRAY, GLX_GRAY_SCALE, + GLX_STATIC_COLOR, GLX_PSEUDO_COLOR, + GLX_TRUE_COLOR, GLX_DIRECT_COLOR + }; + + return ( (unsigned) visualType < NUM_VISUAL_TYPES ) + ? glx_visual_types[ visualType ] : GLX_NONE; +} + + +/**********************************************************************/ +/***** Public Functions *****/ +/**********************************************************************/ + + +/* + * Create a new X/Mesa visual. + * Input: display - X11 display + * visinfo - an XVisualInfo pointer + * rgb_flag - GL_TRUE = RGB mode, + * GL_FALSE = color index mode + * alpha_flag - alpha buffer requested? + * db_flag - GL_TRUE = double-buffered, + * GL_FALSE = single buffered + * stereo_flag - stereo visual? + * ximage_flag - GL_TRUE = use an XImage for back buffer, + * GL_FALSE = use an off-screen pixmap for back buffer + * depth_size - requested bits/depth values, or zero + * stencil_size - requested bits/stencil values, or zero + * accum_red_size - requested bits/red accum values, or zero + * accum_green_size - requested bits/green accum values, or zero + * accum_blue_size - requested bits/blue accum values, or zero + * accum_alpha_size - requested bits/alpha accum values, or zero + * num_samples - number of samples/pixel if multisampling, or zero + * level - visual level, usually 0 + * visualCaveat - ala the GLX extension, usually GLX_NONE + * Return; a new XMesaVisual or 0 if error. + */ +PUBLIC +XMesaVisual XMesaCreateVisual( Display *display, + XVisualInfo * visinfo, + GLboolean rgb_flag, + GLboolean alpha_flag, + GLboolean db_flag, + GLboolean stereo_flag, + GLboolean ximage_flag, + GLint depth_size, + GLint stencil_size, + GLint accum_red_size, + GLint accum_green_size, + GLint accum_blue_size, + GLint accum_alpha_size, + GLint num_samples, + GLint level, + GLint visualCaveat ) +{ + XMesaVisual v; + GLint red_bits, green_bits, blue_bits, alpha_bits; + + /* For debugging only */ + if (_mesa_getenv("MESA_XSYNC")) { + /* This makes debugging X easier. + * In your debugger, set a breakpoint on _XError to stop when an + * X protocol error is generated. + */ + XSynchronize( display, 1 ); + } + + v = (XMesaVisual) CALLOC_STRUCT(xmesa_visual); + if (!v) { + return NULL; + } + + v->display = display; + + /* Save a copy of the XVisualInfo struct because the user may X_mesa_free() + * the struct but we may need some of the information contained in it + * at a later time. + */ + v->visinfo = (XVisualInfo *) MALLOC(sizeof(*visinfo)); + if (!v->visinfo) { + _mesa_free(v); + return NULL; + } + MEMCPY(v->visinfo, visinfo, sizeof(*visinfo)); + + v->ximage_flag = ximage_flag; + + v->mesa_visual.redMask = visinfo->red_mask; + v->mesa_visual.greenMask = visinfo->green_mask; + v->mesa_visual.blueMask = visinfo->blue_mask; + v->mesa_visual.visualID = visinfo->visualid; + v->mesa_visual.screen = visinfo->screen; + +#if !(defined(__cplusplus) || defined(c_plusplus)) + v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->class); +#else + v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->c_class); +#endif + + v->mesa_visual.visualRating = visualCaveat; + + if (alpha_flag) + v->mesa_visual.alphaBits = 8; + + (void) initialize_visual_and_buffer( v, NULL, rgb_flag, 0, 0 ); + + { + const int xclass = v->mesa_visual.visualType; + if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) { + red_bits = _mesa_bitcount(GET_REDMASK(v)); + green_bits = _mesa_bitcount(GET_GREENMASK(v)); + blue_bits = _mesa_bitcount(GET_BLUEMASK(v)); + } + else { + /* this is an approximation */ + int depth; + depth = v->visinfo->depth; + red_bits = depth / 3; + depth -= red_bits; + green_bits = depth / 2; + depth -= green_bits; + blue_bits = depth; + alpha_bits = 0; + assert( red_bits + green_bits + blue_bits == v->visinfo->depth ); + } + alpha_bits = v->mesa_visual.alphaBits; + } + + _mesa_initialize_visual( &v->mesa_visual, + rgb_flag, db_flag, stereo_flag, + red_bits, green_bits, + blue_bits, alpha_bits, + v->mesa_visual.indexBits, + depth_size, + stencil_size, + accum_red_size, accum_green_size, + accum_blue_size, accum_alpha_size, + 0 ); + + /* XXX minor hack */ + v->mesa_visual.level = level; + return v; +} + + +PUBLIC +void XMesaDestroyVisual( XMesaVisual v ) +{ + _mesa_free(v->visinfo); + _mesa_free(v); +} + + + +/** + * Create a new XMesaContext. + * \param v the XMesaVisual + * \param share_list another XMesaContext with which to share display + * lists or NULL if no sharing is wanted. + * \return an XMesaContext or NULL if error. + */ +PUBLIC +XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list ) +{ + static GLboolean firstTime = GL_TRUE; + static struct pipe_screen *screen = NULL; + struct pipe_context *pipe = NULL; + XMesaContext c; + GLcontext *mesaCtx; + uint pf; + + if (firstTime) { + pipe_mutex_init(_xmesa_lock); + screen = driver.create_pipe_screen(); + firstTime = GL_FALSE; + } + + /* Note: the XMesaContext contains a Mesa GLcontext struct (inheritance) */ + c = (XMesaContext) CALLOC_STRUCT(xmesa_context); + if (!c) + return NULL; + + pf = choose_pixel_format(v); + assert(pf); + + c->xm_visual = v; + c->xm_buffer = NULL; /* set later by XMesaMakeCurrent */ + c->xm_read_buffer = NULL; + + if (screen == NULL) + goto fail; + + pipe = driver.create_pipe_context(screen, (void *) c); + if (pipe == NULL) + goto fail; + + c->st = st_create_context(pipe, + &v->mesa_visual, + share_list ? share_list->st : NULL); + if (c->st == NULL) + goto fail; + + mesaCtx = c->st->ctx; + c->st->ctx->DriverCtx = c; + + return c; + +fail: + if (c->st) + st_destroy_context(c->st); + else if (pipe) + pipe->destroy(pipe); + + _mesa_free(c); + return NULL; +} + + + +PUBLIC +void XMesaDestroyContext( XMesaContext c ) +{ + st_destroy_context(c->st); + + /* FIXME: We should destroy the screen here, but if we do so, surfaces may + * outlive it, causing segfaults + struct pipe_screen *screen = c->st->pipe->screen; + screen->destroy(screen); + */ + + _mesa_free(c); +} + + + +/** + * Private function for creating an XMesaBuffer which corresponds to an + * X window or pixmap. + * \param v the window's XMesaVisual + * \param w the window we're wrapping + * \return new XMesaBuffer or NULL if error + */ +PUBLIC XMesaBuffer +XMesaCreateWindowBuffer(XMesaVisual v, Window w) +{ + XWindowAttributes attr; + XMesaBuffer b; + Colormap cmap; + int depth; + + assert(v); + assert(w); + + /* Check that window depth matches visual depth */ + XGetWindowAttributes( v->display, w, &attr ); + depth = attr.depth; + if (v->visinfo->depth != depth) { + _mesa_warning(NULL, "XMesaCreateWindowBuffer: depth mismatch between visual (%d) and window (%d)!\n", + v->visinfo->depth, depth); + return NULL; + } + + /* Find colormap */ + if (attr.colormap) { + cmap = attr.colormap; + } + else { + _mesa_warning(NULL, "Window %u has no colormap!\n", (unsigned int) w); + /* this is weird, a window w/out a colormap!? */ + /* OK, let's just allocate a new one and hope for the best */ + cmap = XCreateColormap(v->display, w, attr.visual, AllocNone); + } + + b = create_xmesa_buffer((Drawable) w, WINDOW, v, cmap); + if (!b) + return NULL; + + if (!initialize_visual_and_buffer( v, b, v->mesa_visual.rgbMode, + (Drawable) w, cmap )) { + xmesa_free_buffer(b); + return NULL; + } + + return b; +} + + + +/** + * Create a new XMesaBuffer from an X pixmap. + * + * \param v the XMesaVisual + * \param p the pixmap + * \param cmap the colormap, may be 0 if using a \c GLX_TRUE_COLOR or + * \c GLX_DIRECT_COLOR visual for the pixmap + * \returns new XMesaBuffer or NULL if error + */ +PUBLIC XMesaBuffer +XMesaCreatePixmapBuffer(XMesaVisual v, Pixmap p, Colormap cmap) +{ + XMesaBuffer b; + + assert(v); + + b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap); + if (!b) + return NULL; + + if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode, + (Drawable) p, cmap)) { + xmesa_free_buffer(b); + return NULL; + } + + return b; +} + + +/** + * For GLX_EXT_texture_from_pixmap + */ +XMesaBuffer +XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p, + Colormap cmap, + int format, int target, int mipmap) +{ + GET_CURRENT_CONTEXT(ctx); + XMesaBuffer b; + GLuint width, height; + + assert(v); + + b = create_xmesa_buffer((Drawable) p, PIXMAP, v, cmap); + if (!b) + return NULL; + + /* get pixmap size, update framebuffer/renderbuffer dims */ + xmesa_get_window_size(v->display, b, &width, &height); + _mesa_resize_framebuffer(NULL, &(b->stfb->Base), width, height); + + if (target == 0) { + /* examine dims */ + if (ctx->Extensions.ARB_texture_non_power_of_two) { + target = GLX_TEXTURE_2D_EXT; + } + else if ( _mesa_bitcount(width) == 1 + && _mesa_bitcount(height) == 1) { + /* power of two size */ + if (height == 1) { + target = GLX_TEXTURE_1D_EXT; + } + else { + target = GLX_TEXTURE_2D_EXT; + } + } + else if (ctx->Extensions.NV_texture_rectangle) { + target = GLX_TEXTURE_RECTANGLE_EXT; + } + else { + /* non power of two textures not supported */ + XMesaDestroyBuffer(b); + return 0; + } + } + + b->TextureTarget = target; + b->TextureFormat = format; + b->TextureMipmap = mipmap; + + if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode, + (Drawable) p, cmap)) { + xmesa_free_buffer(b); + return NULL; + } + + return b; +} + + + +XMesaBuffer +XMesaCreatePBuffer(XMesaVisual v, Colormap cmap, + unsigned int width, unsigned int height) +{ + Window root; + Drawable drawable; /* X Pixmap Drawable */ + XMesaBuffer b; + + /* allocate pixmap for front buffer */ + root = RootWindow( v->display, v->visinfo->screen ); + drawable = XCreatePixmap(v->display, root, width, height, + v->visinfo->depth); + if (!drawable) + return NULL; + + b = create_xmesa_buffer(drawable, PBUFFER, v, cmap); + if (!b) + return NULL; + + if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode, + drawable, cmap)) { + xmesa_free_buffer(b); + return NULL; + } + + return b; +} + + + +/* + * Deallocate an XMesaBuffer structure and all related info. + */ +PUBLIC void +XMesaDestroyBuffer(XMesaBuffer b) +{ + xmesa_free_buffer(b); +} + + +/** + * Query the current window size and update the corresponding GLframebuffer + * and all attached renderbuffers. + * Called when: + * 1. the first time a buffer is bound to a context. + * 2. SwapBuffers. XXX probabaly from xm_flush_frontbuffer() too... + * Note: it's possible (and legal) for xmctx to be NULL. That can happen + * when resizing a buffer when no rendering context is bound. + */ +void +xmesa_check_and_update_buffer_size(XMesaContext xmctx, XMesaBuffer drawBuffer) +{ + GLuint width, height; + xmesa_get_window_size(drawBuffer->xm_visual->display, drawBuffer, &width, &height); + st_resize_framebuffer(drawBuffer->stfb, width, height); +} + + + + +/* + * Bind buffer b to context c and make c the current rendering context. + */ +PUBLIC +GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer, + XMesaBuffer readBuffer ) +{ + XMesaContext old_ctx = XMesaGetCurrentContext(); + + if (old_ctx && old_ctx != c) { + XMesaFlush(old_ctx); + old_ctx->xm_buffer = NULL; + old_ctx->xm_read_buffer = NULL; + } + + if (c) { + if (!drawBuffer || !readBuffer) + return GL_FALSE; /* must specify buffers! */ + + if (c == old_ctx && + c->xm_buffer == drawBuffer && + c->xm_read_buffer == readBuffer) + return GL_TRUE; + + c->xm_buffer = drawBuffer; + c->xm_read_buffer = readBuffer; + + st_make_current(c->st, drawBuffer->stfb, readBuffer->stfb); + + xmesa_check_and_update_buffer_size(c, drawBuffer); + if (readBuffer != drawBuffer) + xmesa_check_and_update_buffer_size(c, readBuffer); + + /* Solution to Stephane Rehel's problem with glXReleaseBuffersMESA(): */ + drawBuffer->wasCurrent = GL_TRUE; + } + else { + /* Detach */ + st_make_current( NULL, NULL, NULL ); + + } + return GL_TRUE; +} + + +/* + * Unbind the context c from its buffer. + */ +GLboolean XMesaUnbindContext( XMesaContext c ) +{ + /* A no-op for XFree86 integration purposes */ + return GL_TRUE; +} + + +XMesaContext XMesaGetCurrentContext( void ) +{ + GET_CURRENT_CONTEXT(ctx); + if (ctx) { + XMesaContext xmesa = xmesa_context(ctx); + return xmesa; + } + else { + return 0; + } +} + + + +/** + * Swap front and back color buffers and have winsys display front buffer. + * If there's no front color buffer no swap actually occurs. + */ +PUBLIC +void XMesaSwapBuffers( XMesaBuffer b ) +{ + struct pipe_surface *frontLeftSurf; + + st_swapbuffers(b->stfb, &frontLeftSurf, NULL); + + if (frontLeftSurf) { + driver.display_surface(b, frontLeftSurf); + } + + xmesa_check_and_update_buffer_size(NULL, b); +} + + + +/* + * Copy sub-region of back buffer to front buffer + */ +void XMesaCopySubBuffer( XMesaBuffer b, int x, int y, int width, int height ) +{ + struct pipe_surface *surf_front; + struct pipe_surface *surf_back; + struct pipe_context *pipe = NULL; /* XXX fix */ + + st_get_framebuffer_surface(b->stfb, ST_SURFACE_FRONT_LEFT, &surf_front); + st_get_framebuffer_surface(b->stfb, ST_SURFACE_BACK_LEFT, &surf_back); + + if (!surf_front || !surf_back) + return; + + pipe->surface_copy(pipe, + surf_front, x, y, /* dest */ + surf_back, x, y, /* src */ + width, height); +} + + + +void XMesaFlush( XMesaContext c ) +{ + if (c && c->xm_visual->display) { + st_finish(c->st); + XSync( c->xm_visual->display, False ); + } +} + + + + + +XMesaBuffer XMesaFindBuffer( Display *dpy, Drawable d ) +{ + XMesaBuffer b; + for (b = XMesaBufferList; b; b = b->Next) { + if (b->drawable == d && b->xm_visual->display == dpy) { + return b; + } + } + return NULL; +} + + +/** + * Free/destroy all XMesaBuffers associated with given display. + */ +void xmesa_destroy_buffers_on_display(Display *dpy) +{ + XMesaBuffer b, next; + for (b = XMesaBufferList; b; b = next) { + next = b->Next; + if (b->xm_visual->display == dpy) { + xmesa_free_buffer(b); + } + } +} + + +/* + * Look for XMesaBuffers whose X window has been destroyed. + * Deallocate any such XMesaBuffers. + */ +void XMesaGarbageCollect( void ) +{ + XMesaBuffer b, next; + for (b=XMesaBufferList; b; b=next) { + next = b->Next; + if (b->xm_visual && + b->xm_visual->display && + b->drawable && + b->type == WINDOW) { + XSync(b->xm_visual->display, False); + if (!window_exists( b->xm_visual->display, b->drawable )) { + /* found a dead window, free the ancillary info */ + XMesaDestroyBuffer( b ); + } + } + } +} + + + + +PUBLIC void +XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer, + const int *attrib_list) +{ +} + + + +PUBLIC void +XMesaReleaseTexImage(Display *dpy, XMesaBuffer drawable, int buffer) +{ +} + diff --git a/src/gallium/state_trackers/glx/xlib/xm_api.h b/src/gallium/state_trackers/glx/xlib/xm_api.h new file mode 100644 index 0000000000..ce97a3ec76 --- /dev/null +++ b/src/gallium/state_trackers/glx/xlib/xm_api.h @@ -0,0 +1,394 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + + +/* Sample Usage: + +In addition to the usual X calls to select a visual, create a colormap +and create a window, you must do the following to use the X/Mesa interface: + +1. Call XMesaCreateVisual() to make an XMesaVisual from an XVisualInfo. + +2. Call XMesaCreateContext() to create an X/Mesa rendering context, given + the XMesaVisual. + +3. Call XMesaCreateWindowBuffer() to create an XMesaBuffer from an X window + and XMesaVisual. + +4. Call XMesaMakeCurrent() to bind the XMesaBuffer to an XMesaContext and + to make the context the current one. + +5. Make gl* calls to render your graphics. + +6. Use XMesaSwapBuffers() when double buffering to swap front/back buffers. + +7. Before the X window is destroyed, call XMesaDestroyBuffer(). + +8. Before exiting, call XMesaDestroyVisual and XMesaDestroyContext. + +*/ + + + + +#ifndef XMESA_H +#define XMESA_H + + +#include "main/mtypes.h" +#include "state_tracker/st_context.h" +#include "state_tracker/st_public.h" +#include "pipe/p_thread.h" + + +# include <X11/Xlib.h> +# include <X11/Xlibint.h> +# include <X11/Xutil.h> +# ifdef USE_XSHM /* was SHM */ +# include <sys/ipc.h> +# include <sys/shm.h> +# include <X11/extensions/XShm.h> +# endif + +typedef struct xmesa_buffer *XMesaBuffer; +typedef struct xmesa_context *XMesaContext; +typedef struct xmesa_visual *XMesaVisual; + + + +/* + * Create a new X/Mesa visual. + * Input: display - X11 display + * visinfo - an XVisualInfo pointer + * rgb_flag - GL_TRUE = RGB mode, + * GL_FALSE = color index mode + * alpha_flag - alpha buffer requested? + * db_flag - GL_TRUE = double-buffered, + * GL_FALSE = single buffered + * stereo_flag - stereo visual? + * ximage_flag - GL_TRUE = use an XImage for back buffer, + * GL_FALSE = use an off-screen pixmap for back buffer + * depth_size - requested bits/depth values, or zero + * stencil_size - requested bits/stencil values, or zero + * accum_red_size - requested bits/red accum values, or zero + * accum_green_size - requested bits/green accum values, or zero + * accum_blue_size - requested bits/blue accum values, or zero + * accum_alpha_size - requested bits/alpha accum values, or zero + * num_samples - number of samples/pixel if multisampling, or zero + * level - visual level, usually 0 + * visualCaveat - ala the GLX extension, usually GLX_NONE_EXT + * Return; a new XMesaVisual or 0 if error. + */ +extern XMesaVisual XMesaCreateVisual( Display *display, + XVisualInfo * visinfo, + GLboolean rgb_flag, + GLboolean alpha_flag, + GLboolean db_flag, + GLboolean stereo_flag, + GLboolean ximage_flag, + GLint depth_size, + GLint stencil_size, + GLint accum_red_size, + GLint accum_green_size, + GLint accum_blue_size, + GLint accum_alpha_size, + GLint num_samples, + GLint level, + GLint visualCaveat ); + +/* + * Destroy an XMesaVisual, but not the associated XVisualInfo. + */ +extern void XMesaDestroyVisual( XMesaVisual v ); + + + +/* + * Create a new XMesaContext for rendering into an X11 window. + * + * Input: visual - an XMesaVisual + * share_list - another XMesaContext with which to share display + * lists or NULL if no sharing is wanted. + * Return: an XMesaContext or NULL if error. + */ +extern XMesaContext XMesaCreateContext( XMesaVisual v, + XMesaContext share_list ); + + +/* + * Destroy a rendering context as returned by XMesaCreateContext() + */ +extern void XMesaDestroyContext( XMesaContext c ); + + + +/* + * Create an XMesaBuffer from an X window. + */ +extern XMesaBuffer XMesaCreateWindowBuffer( XMesaVisual v, Window w ); + + +/* + * Create an XMesaBuffer from an X pixmap. + */ +extern XMesaBuffer XMesaCreatePixmapBuffer( XMesaVisual v, + Pixmap p, + Colormap cmap ); + + +/* + * Destroy an XMesaBuffer, but not the corresponding window or pixmap. + */ +extern void XMesaDestroyBuffer( XMesaBuffer b ); + + +/* + * Return the XMesaBuffer handle which corresponds to an X drawable, if any. + * + * New in Mesa 2.3. + */ +extern XMesaBuffer XMesaFindBuffer( Display *dpy, + Drawable d ); + + + +/* + * Bind two buffers (read and draw) to a context and make the + * context the current one. + * New in Mesa 3.3 + */ +extern GLboolean XMesaMakeCurrent2( XMesaContext c, + XMesaBuffer drawBuffer, + XMesaBuffer readBuffer ); + + +/* + * Unbind the current context from its buffer. + */ +extern GLboolean XMesaUnbindContext( XMesaContext c ); + + +/* + * Return a handle to the current context. + */ +extern XMesaContext XMesaGetCurrentContext( void ); + + +/* + * Swap the front and back buffers for the given buffer. No action is + * taken if the buffer is not double buffered. + */ +extern void XMesaSwapBuffers( XMesaBuffer b ); + + +/* + * Copy a sub-region of the back buffer to the front buffer. + * + * New in Mesa 2.6 + */ +extern void XMesaCopySubBuffer( XMesaBuffer b, + int x, + int y, + int width, + int height ); + + + + + +/* + * Flush/sync a context + */ +extern void XMesaFlush( XMesaContext c ); + + + +/* + * Scan for XMesaBuffers whose window/pixmap has been destroyed, then free + * any memory used by that buffer. + * + * New in Mesa 2.3. + */ +extern void XMesaGarbageCollect( void ); + + + +/* + * Create a pbuffer. + * New in Mesa 4.1 + */ +extern XMesaBuffer XMesaCreatePBuffer(XMesaVisual v, Colormap cmap, + unsigned int width, unsigned int height); + + + +/* + * Texture from Pixmap + * New in Mesa 7.1 + */ +extern void +XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer, + const int *attrib_list); + +extern void +XMesaReleaseTexImage(Display *dpy, XMesaBuffer drawable, int buffer); + + +extern XMesaBuffer +XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p, + Colormap cmap, + int format, int target, int mipmap); + + + + +/*********************************************************************** + */ + +extern pipe_mutex _xmesa_lock; + +extern struct xmesa_buffer *XMesaBufferList; + + +/** + * Visual inforation, derived from GLvisual. + * Basically corresponds to an XVisualInfo. + */ +struct xmesa_visual { + GLvisual mesa_visual; /* Device independent visual parameters */ + Display *display; /* The X11 display */ + XVisualInfo * visinfo; /* X's visual info (pointer to private copy) */ + XVisualInfo *vishandle; /* Only used in fakeglx.c */ + GLint BitsPerPixel; /* True bits per pixel for XImages */ + + GLboolean ximage_flag; /* Use XImage for back buffer (not pixmap)? */ +}; + + +/** + * Context info, derived from st_context. + * Basically corresponds to a GLXContext. + */ +struct xmesa_context { + struct st_context *st; + XMesaVisual xm_visual; /** pixel format info */ + XMesaBuffer xm_buffer; /** current drawbuffer */ + XMesaBuffer xm_read_buffer; /** current readbuffer */ +}; + + +/** + * Types of X/GLX drawables we might render into. + */ +typedef enum { + WINDOW, /* An X window */ + GLXWINDOW, /* GLX window */ + PIXMAP, /* GLX pixmap */ + PBUFFER /* GLX Pbuffer */ +} BufferType; + + +/** + * Framebuffer information, derived from. + * Basically corresponds to a GLXDrawable. + */ +struct xmesa_buffer { + struct st_framebuffer *stfb; + + GLboolean wasCurrent; /* was ever the current buffer? */ + XMesaVisual xm_visual; /* the X/Mesa visual */ + Drawable drawable; /* Usually the X window ID */ + Colormap cmap; /* the X colormap */ + BufferType type; /* window, pixmap, pbuffer or glxwindow */ + + XImage *tempImage; + unsigned long selectedEvents;/* for pbuffers only */ + + GLuint shm; /* X Shared Memory extension status: */ + /* 0 = not available */ + /* 1 = XImage support available */ + /* 2 = Pixmap support available too */ +#if defined(USE_XSHM) + XShmSegmentInfo shminfo; +#endif + + GC gc; /* scratch GC for span, line, tri drawing */ + + /* GLX_EXT_texture_from_pixmap */ + GLint TextureTarget; /** GLX_TEXTURE_1D_EXT, for example */ + GLint TextureFormat; /** GLX_TEXTURE_FORMAT_RGB_EXT, for example */ + GLint TextureMipmap; /** 0 or 1 */ + + struct xmesa_buffer *Next; /* Linked list pointer: */ +}; + + + +/** cast wrapper */ +static INLINE XMesaContext +xmesa_context(GLcontext *ctx) +{ + return (XMesaContext) ctx->DriverCtx; +} + + +/** cast wrapper */ +static INLINE XMesaBuffer +xmesa_buffer(GLframebuffer *fb) +{ + struct st_framebuffer *stfb = (struct st_framebuffer *) fb; + return (XMesaBuffer) st_framebuffer_private(stfb); +} + + +extern void +xmesa_delete_framebuffer(struct gl_framebuffer *fb); + +extern XMesaBuffer +xmesa_find_buffer(Display *dpy, Colormap cmap, XMesaBuffer notThis); + +extern void +xmesa_check_and_update_buffer_size(XMesaContext xmctx, XMesaBuffer drawBuffer); + +extern void +xmesa_destroy_buffers_on_display(Display *dpy); + +static INLINE GLuint +xmesa_buffer_width(XMesaBuffer b) +{ + return b->stfb->Base.Width; +} + +static INLINE GLuint +xmesa_buffer_height(XMesaBuffer b) +{ + return b->stfb->Base.Height; +} + +extern int +xmesa_check_for_xshm(Display *display); + + +#endif diff --git a/src/gallium/state_trackers/glx/xlib/xm_winsys.h b/src/gallium/state_trackers/glx/xlib/xm_winsys.h new file mode 100644 index 0000000000..0e57605c34 --- /dev/null +++ b/src/gallium/state_trackers/glx/xlib/xm_winsys.h @@ -0,0 +1,59 @@ + +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef XM_WINSYS_H +#define XM_WINSYS_H + +struct pipe_context; +struct pipe_screen; +struct pipe_surface; +struct xmesa_buffer; + + +struct xm_driver { + + struct pipe_screen *(*create_pipe_screen)( void ); + + /* The context_private argument needs to go away. Is currently used + * in a round-about way to associate a display-target surface with its + * Xlib window. + */ + struct pipe_context *(*create_pipe_context)( struct pipe_screen *, + void *context_private ); + + void (*display_surface)( struct xmesa_buffer *, + struct pipe_surface * ); + +}; + + +extern void +xmesa_set_driver( const struct xm_driver *driver ); + + +#endif diff --git a/src/gallium/state_trackers/python/README b/src/gallium/state_trackers/python/README new file mode 100644 index 0000000000..e03d546830 --- /dev/null +++ b/src/gallium/state_trackers/python/README @@ -0,0 +1,43 @@ +This directory contains Python bindings to Gallium3D. It looks like a state +tracker from the pipe driver perspective, and it looks like a pipe driver from +the python script perspective. + + +To build you'll need: +* Python (with development packages) +* SCons +* SWIG, http://www.swig.org/download.html +* Python Imaging Library with TK support, http://www.pythonware.com/products/pil/, + for the samples + +On a debian-based distro you can simply do: + + aptitude install python-dev scons swig python-imaging python-imaging-tk + +On a Windows machine ensure the swig command is in your PATH. + +Invoke scons on the top dir as + + scons debug=yes statetrackers=python drivers=softpipe,trace winsys=none + +To use it set PYTHONPATH appropriately, e.g, in Linux do: + + export PYTHONPATH=$PWD/build/linux-x86-debug/gallium/state_trackers/python + +or (in Windows) + + set PYTHONPATH=%CD%\build\windows-x86-debug\gallium\state_trackers\python + +and then try running + + python src/gallium/state_trackers/python/samples/tri.py + +which should show a triangle. + + +This is still work in progress: +- errors are not handled properly and almost always result in crash +- state atoms with array members are awkward to set + +-- +Jose Fonseca <jfonseca@vmware.com> diff --git a/src/gallium/state_trackers/python/SConscript b/src/gallium/state_trackers/python/SConscript new file mode 100644 index 0000000000..ec385e7c44 --- /dev/null +++ b/src/gallium/state_trackers/python/SConscript @@ -0,0 +1,47 @@ +import sys +import os.path + +Import('*') + +if 'python' in env['statetrackers']: + + env = env.Clone() + + env.Tool('python') + + env.Tool('swig') + env.Append(SWIGPATH = ['#src/gallium/include', '#src/gallium/include/pipe']) + env.Append(SWIGFLAGS = ['-python', '-keyword']) + + env.Append(CPPPATH = '.') + + if env['platform'] == 'windows': + env.Append(LIBS = [ + 'opengl32', + 'gdi32', + 'user32', + 'kernel32', + ]) + else: + env.Append(LIBS = [ + 'GL', + 'X11', + ]) + + pyst = env.ConvenienceLibrary( + target = 'pyst', + source = [ + 'gallium.i', + 'st_device.c', + 'st_sample.c', + 'st_softpipe_winsys.c', + ], + ) + + env.SharedLibrary( + target = '_gallium', + source = [ + 'st_hardpipe_winsys.c', + ], + LIBS = [pyst, softpipe, trace] + auxiliaries + env['LIBS'], + ) diff --git a/src/gallium/state_trackers/python/gallium.i b/src/gallium/state_trackers/python/gallium.i new file mode 100644 index 0000000000..3f79cc1a3d --- /dev/null +++ b/src/gallium/state_trackers/python/gallium.i @@ -0,0 +1,103 @@ + /************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * @file + * SWIG interface definion for Gallium types. + * + * @author Jose Fonseca <jrfonseca@tungstengraphics.com> + */ + +%module gallium; + +%{ + +#include <stdio.h> + +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "pipe/p_shader_tokens.h" +#include "cso_cache/cso_context.h" +#include "util/u_draw_quad.h" +#include "util/u_tile.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "tgsi/tgsi_text.h" +#include "tgsi/tgsi_dump.h" + +#include "st_device.h" +#include "st_sample.h" + +%} + +%include "typemaps.i" +%include "exception.i" +%include "cstring.i" + +%include "carrays.i" +%array_class(unsigned char, ByteArray); +%array_class(int, IntArray); +%array_class(unsigned, UnsignedArray); +%array_class(float, FloatArray); + + +%rename(Device) st_device; +%rename(Context) st_context; +%rename(Texture) pipe_texture; +%rename(Surface) st_surface; +%rename(Buffer) pipe_buffer; + +%rename(BlendColor) pipe_blend_color; +%rename(Blend) pipe_blend_state; +%rename(Clip) pipe_clip_state; +%rename(ConstantBuffer) pipe_constant_buffer; +%rename(Depth) pipe_depth_state; +%rename(Stencil) pipe_stencil_state; +%rename(Alpha) pipe_alpha_state; +%rename(DepthStencilAlpha) pipe_depth_stencil_alpha_state; +%rename(FormatBlock) pipe_format_block; +%rename(Framebuffer) pipe_framebuffer_state; +%rename(PolyStipple) pipe_poly_stipple; +%rename(Rasterizer) pipe_rasterizer_state; +%rename(Sampler) pipe_sampler_state; +%rename(Scissor) pipe_scissor_state; +%rename(Shader) pipe_shader_state; +%rename(VertexBuffer) pipe_vertex_buffer; +%rename(VertexElement) pipe_vertex_element; +%rename(Viewport) pipe_viewport_state; + + +%include "p_compiler.i" +%include "p_defines.h"; +%include "p_format.i" + +%include "p_device.i" +%include "p_context.i" +%include "p_texture.i" +%include "p_state.i" + diff --git a/src/gallium/state_trackers/python/p_compiler.i b/src/gallium/state_trackers/python/p_compiler.i new file mode 100644 index 0000000000..15f6ba5b9d --- /dev/null +++ b/src/gallium/state_trackers/python/p_compiler.i @@ -0,0 +1,29 @@ + /************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +typedef unsigned char ubyte; diff --git a/src/gallium/state_trackers/python/p_context.i b/src/gallium/state_trackers/python/p_context.i new file mode 100644 index 0000000000..a40aa1e518 --- /dev/null +++ b/src/gallium/state_trackers/python/p_context.i @@ -0,0 +1,319 @@ + /************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * @file + * SWIG interface definion for Gallium types. + * + * @author Jose Fonseca <jrfonseca@tungstengraphics.com> + */ + +%nodefaultctor st_context; +%nodefaultdtor st_context; + +struct st_context { +}; + +%extend st_context { + + ~st_context() { + st_context_destroy($self); + } + + /* + * State functions (create/bind/destroy state objects) + */ + + void set_blend( const struct pipe_blend_state *state ) { + cso_set_blend($self->cso, state); + } + + void set_sampler( unsigned index, const struct pipe_sampler_state *state ) { + cso_single_sampler($self->cso, index, state); + cso_single_sampler_done($self->cso); + } + + void set_rasterizer( const struct pipe_rasterizer_state *state ) { + cso_set_rasterizer($self->cso, state); + } + + void set_depth_stencil_alpha(const struct pipe_depth_stencil_alpha_state *state) { + cso_set_depth_stencil_alpha($self->cso, state); + } + + void set_fragment_shader( const struct pipe_shader_state *state ) { + void *fs; + + if(!state) { + cso_set_fragment_shader_handle($self->cso, NULL); + return; + } + + fs = $self->pipe->create_fs_state($self->pipe, state); + if(!fs) + return; + + if(cso_set_fragment_shader_handle($self->cso, fs) != PIPE_OK) + return; + + cso_delete_fragment_shader($self->cso, $self->fs); + $self->fs = fs; + } + + void set_vertex_shader( const struct pipe_shader_state *state ) { + void *vs; + + if(!state) { + cso_set_vertex_shader_handle($self->cso, NULL); + return; + } + + vs = $self->pipe->create_vs_state($self->pipe, state); + if(!vs) + return; + + if(cso_set_vertex_shader_handle($self->cso, vs) != PIPE_OK) + return; + + cso_delete_vertex_shader($self->cso, $self->vs); + $self->vs = vs; + } + + /* + * Parameter-like state (or properties) + */ + + void set_blend_color(const struct pipe_blend_color *state ) { + cso_set_blend_color($self->cso, state); + } + + void set_clip(const struct pipe_clip_state *state ) { + $self->pipe->set_clip_state($self->pipe, state); + } + + void set_constant_buffer(unsigned shader, unsigned index, + struct pipe_buffer *buffer ) + { + struct pipe_constant_buffer state; + memset(&state, 0, sizeof(state)); + state.buffer = buffer; + $self->pipe->set_constant_buffer($self->pipe, shader, index, &state); + } + + void set_framebuffer(const struct pipe_framebuffer_state *state ) + { + memcpy(&$self->framebuffer, state, sizeof *state); + cso_set_framebuffer($self->cso, state); + } + + void set_polygon_stipple(const struct pipe_poly_stipple *state ) { + $self->pipe->set_polygon_stipple($self->pipe, state); + } + + void set_scissor(const struct pipe_scissor_state *state ) { + $self->pipe->set_scissor_state($self->pipe, state); + } + + void set_viewport(const struct pipe_viewport_state *state) { + cso_set_viewport($self->cso, state); + } + + void set_sampler_texture(unsigned index, + struct pipe_texture *texture) { + if(!texture) + texture = $self->default_texture; + pipe_texture_reference(&$self->sampler_textures[index], texture); + $self->pipe->set_sampler_textures($self->pipe, + PIPE_MAX_SAMPLERS, + $self->sampler_textures); + } + + void set_vertex_buffer(unsigned index, + unsigned stride, + unsigned max_index, + unsigned buffer_offset, + struct pipe_buffer *buffer) + { + unsigned i; + struct pipe_vertex_buffer state; + + memset(&state, 0, sizeof(state)); + state.stride = stride; + state.max_index = max_index; + state.buffer_offset = buffer_offset; + state.buffer = buffer; + + memcpy(&$self->vertex_buffers[index], &state, sizeof(state)); + + for(i = 0; i < PIPE_MAX_ATTRIBS; ++i) + if(self->vertex_buffers[i].buffer) + $self->num_vertex_buffers = i + 1; + + $self->pipe->set_vertex_buffers($self->pipe, + $self->num_vertex_buffers, + $self->vertex_buffers); + } + + void set_vertex_element(unsigned index, + const struct pipe_vertex_element *element) + { + memcpy(&$self->vertex_elements[index], element, sizeof(*element)); + } + + void set_vertex_elements(unsigned num) + { + $self->num_vertex_elements = num; + $self->pipe->set_vertex_elements($self->pipe, + $self->num_vertex_elements, + $self->vertex_elements); + } + + /* + * Draw functions + */ + + void draw_arrays(unsigned mode, unsigned start, unsigned count) { + $self->pipe->draw_arrays($self->pipe, mode, start, count); + } + + void draw_elements( struct pipe_buffer *indexBuffer, + unsigned indexSize, + unsigned mode, unsigned start, unsigned count) + { + $self->pipe->draw_elements($self->pipe, + indexBuffer, + indexSize, + mode, start, count); + } + + void draw_range_elements( struct pipe_buffer *indexBuffer, + unsigned indexSize, unsigned minIndex, unsigned maxIndex, + unsigned mode, unsigned start, unsigned count) + { + $self->pipe->draw_range_elements($self->pipe, + indexBuffer, + indexSize, minIndex, maxIndex, + mode, start, count); + } + + void draw_vertices(unsigned prim, + unsigned num_verts, + unsigned num_attribs, + const float *vertices) + { + struct pipe_context *pipe = $self->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_buffer *vbuf; + float *map; + unsigned size; + + size = num_verts * num_attribs * 4 * sizeof(float); + + vbuf = pipe_buffer_create(screen, + 32, + PIPE_BUFFER_USAGE_VERTEX, + size); + if(!vbuf) + goto error1; + + map = pipe_buffer_map(screen, vbuf, PIPE_BUFFER_USAGE_CPU_WRITE); + if (!map) + goto error2; + memcpy(map, vertices, size); + pipe_buffer_unmap(screen, vbuf); + + util_draw_vertex_buffer(pipe, vbuf, 0, prim, num_verts, num_attribs); + +error2: + pipe_buffer_reference(&vbuf, NULL); +error1: + ; + } + + void + flush(unsigned flags = 0) { + struct pipe_fence_handle *fence = NULL; + $self->pipe->flush($self->pipe, flags | PIPE_FLUSH_RENDER_CACHE, &fence); + if(fence) { + /* TODO: allow asynchronous operation */ + $self->pipe->screen->fence_finish( $self->pipe->screen, fence, 0 ); + $self->pipe->screen->fence_reference( $self->pipe->screen, &fence, NULL ); + } + } + + /* + * Surface functions + */ + + void surface_copy(struct st_surface *dst, + unsigned destx, unsigned desty, + struct st_surface *src, + unsigned srcx, unsigned srcy, + unsigned width, unsigned height) + { + struct pipe_surface *_dst = NULL; + struct pipe_surface *_src = NULL; + + _dst = st_pipe_surface(dst, PIPE_BUFFER_USAGE_GPU_WRITE); + if(!_dst) + SWIG_exception(SWIG_ValueError, "couldn't acquire destination surface for writing"); + + _src = st_pipe_surface(src, PIPE_BUFFER_USAGE_GPU_READ); + if(!_src) + SWIG_exception(SWIG_ValueError, "couldn't acquire source surface for reading"); + + $self->pipe->surface_copy($self->pipe, _dst, destx, desty, _src, srcx, srcy, width, height); + + fail: + pipe_surface_reference(&_src, NULL); + pipe_surface_reference(&_dst, NULL); + } + + void surface_fill(struct st_surface *dst, + unsigned x, unsigned y, + unsigned width, unsigned height, + unsigned value) + { + struct pipe_surface *_dst = NULL; + + _dst = st_pipe_surface(dst, PIPE_BUFFER_USAGE_GPU_WRITE); + if(!_dst) + SWIG_exception(SWIG_ValueError, "couldn't acquire destination surface for writing"); + + $self->pipe->surface_fill($self->pipe, _dst, x, y, width, height, value); + + fail: + pipe_surface_reference(&_dst, NULL); + } + + void clear(unsigned buffers, const float *rgba, double depth = 0.0f, + unsigned stencil = 0) + { + $self->pipe->clear($self->pipe, buffers, rgba, depth, stencil); + } + +}; diff --git a/src/gallium/state_trackers/python/p_device.i b/src/gallium/state_trackers/python/p_device.i new file mode 100644 index 0000000000..f16fe5b0ff --- /dev/null +++ b/src/gallium/state_trackers/python/p_device.i @@ -0,0 +1,130 @@ + /************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * @file + * SWIG interface definion for Gallium types. + * + * @author Jose Fonseca <jrfonseca@tungstengraphics.com> + */ + + +%nodefaultctor st_device; +%nodefaultdtor st_device; + + +struct st_device { +}; + +%newobject st_device::texture_create; +%newobject st_device::context_create; +%newobject st_device::buffer_create; + +%extend st_device { + + st_device(int hardware = 1) { + return st_device_create(hardware ? TRUE : FALSE); + } + + ~st_device() { + st_device_destroy($self); + } + + const char * get_name( void ) { + return $self->screen->get_name($self->screen); + } + + const char * get_vendor( void ) { + return $self->screen->get_vendor($self->screen); + } + + /** + * Query an integer-valued capability/parameter/limit + * \param param one of PIPE_CAP_x + */ + int get_param( int param ) { + return $self->screen->get_param($self->screen, param); + } + + /** + * Query a float-valued capability/parameter/limit + * \param param one of PIPE_CAP_x + */ + float get_paramf( int param ) { + return $self->screen->get_paramf($self->screen, param); + } + + /** + * Check if the given pipe_format is supported as a texture or + * drawing surface. + * \param type one of PIPE_TEXTURE, PIPE_SURFACE + */ + int is_format_supported( enum pipe_format format, + enum pipe_texture_target target, + unsigned tex_usage, + unsigned geom_flags ) { + return $self->screen->is_format_supported( $self->screen, + format, + target, + tex_usage, + geom_flags ); + } + + struct st_context * + context_create(void) { + return st_context_create($self); + } + + struct pipe_texture * + texture_create( + enum pipe_format format, + unsigned width, + unsigned height, + unsigned depth = 1, + unsigned last_level = 0, + enum pipe_texture_target target = PIPE_TEXTURE_2D, + unsigned tex_usage = 0 + ) { + struct pipe_texture templat; + memset(&templat, 0, sizeof(templat)); + templat.format = format; + pf_get_block(templat.format, &templat.block); + templat.width[0] = width; + templat.height[0] = height; + templat.depth[0] = depth; + templat.last_level = last_level; + templat.target = target; + templat.tex_usage = tex_usage; + return $self->screen->texture_create($self->screen, &templat); + } + + struct pipe_buffer * + buffer_create(unsigned size, unsigned alignment = 0, unsigned usage = 0) { + return pipe_buffer_create($self->screen, alignment, usage, size); + } + +}; diff --git a/src/gallium/state_trackers/python/p_format.i b/src/gallium/state_trackers/python/p_format.i new file mode 100644 index 0000000000..26fb12b387 --- /dev/null +++ b/src/gallium/state_trackers/python/p_format.i @@ -0,0 +1,162 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (c) 2008 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * XXX: SWIG can't parse p_format.h, so we need to duplicate the relevant + * declarations here + */ + +%{ +#include "pipe/p_format.h" +%} + +enum pipe_format { + PIPE_FORMAT_NONE, + PIPE_FORMAT_A8R8G8B8_UNORM, + PIPE_FORMAT_X8R8G8B8_UNORM, + PIPE_FORMAT_B8G8R8A8_UNORM, + PIPE_FORMAT_B8G8R8X8_UNORM, + PIPE_FORMAT_A1R5G5B5_UNORM, + PIPE_FORMAT_A4R4G4B4_UNORM, + PIPE_FORMAT_R5G6B5_UNORM, + PIPE_FORMAT_A2B10G10R10_UNORM, + PIPE_FORMAT_L8_UNORM, + PIPE_FORMAT_A8_UNORM, + PIPE_FORMAT_I8_UNORM, + PIPE_FORMAT_A8L8_UNORM, + PIPE_FORMAT_L16_UNORM, + PIPE_FORMAT_YCBCR, + PIPE_FORMAT_YCBCR_REV, + PIPE_FORMAT_Z16_UNORM, + PIPE_FORMAT_Z32_UNORM, + PIPE_FORMAT_Z32_FLOAT, + PIPE_FORMAT_S8Z24_UNORM, + PIPE_FORMAT_Z24S8_UNORM, + PIPE_FORMAT_X8Z24_UNORM, + PIPE_FORMAT_Z24X8_UNORM, + PIPE_FORMAT_S8_UNORM, + PIPE_FORMAT_R64_FLOAT, + PIPE_FORMAT_R64G64_FLOAT, + PIPE_FORMAT_R64G64B64_FLOAT, + PIPE_FORMAT_R64G64B64A64_FLOAT, + PIPE_FORMAT_R32_FLOAT, + PIPE_FORMAT_R32G32_FLOAT, + PIPE_FORMAT_R32G32B32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_FORMAT_R32_UNORM, + PIPE_FORMAT_R32G32_UNORM, + PIPE_FORMAT_R32G32B32_UNORM, + PIPE_FORMAT_R32G32B32A32_UNORM, + PIPE_FORMAT_R32_USCALED, + PIPE_FORMAT_R32G32_USCALED, + PIPE_FORMAT_R32G32B32_USCALED, + PIPE_FORMAT_R32G32B32A32_USCALED, + PIPE_FORMAT_R32_SNORM, + PIPE_FORMAT_R32G32_SNORM, + PIPE_FORMAT_R32G32B32_SNORM, + PIPE_FORMAT_R32G32B32A32_SNORM, + PIPE_FORMAT_R32_SSCALED, + PIPE_FORMAT_R32G32_SSCALED, + PIPE_FORMAT_R32G32B32_SSCALED, + PIPE_FORMAT_R32G32B32A32_SSCALED, + PIPE_FORMAT_R16_UNORM, + PIPE_FORMAT_R16G16_UNORM, + PIPE_FORMAT_R16G16B16_UNORM, + PIPE_FORMAT_R16G16B16A16_UNORM, + PIPE_FORMAT_R16_USCALED, + PIPE_FORMAT_R16G16_USCALED, + PIPE_FORMAT_R16G16B16_USCALED, + PIPE_FORMAT_R16G16B16A16_USCALED, + PIPE_FORMAT_R16_SNORM, + PIPE_FORMAT_R16G16_SNORM, + PIPE_FORMAT_R16G16B16_SNORM, + PIPE_FORMAT_R16G16B16A16_SNORM, + PIPE_FORMAT_R16_SSCALED, + PIPE_FORMAT_R16G16_SSCALED, + PIPE_FORMAT_R16G16B16_SSCALED, + PIPE_FORMAT_R16G16B16A16_SSCALED, + PIPE_FORMAT_R8_UNORM, + PIPE_FORMAT_R8G8_UNORM, + PIPE_FORMAT_R8G8B8_UNORM, + PIPE_FORMAT_R8G8B8A8_UNORM, + PIPE_FORMAT_R8G8B8X8_UNORM, + PIPE_FORMAT_R8_USCALED, + PIPE_FORMAT_R8G8_USCALED, + PIPE_FORMAT_R8G8B8_USCALED, + PIPE_FORMAT_R8G8B8A8_USCALED, + PIPE_FORMAT_R8G8B8X8_USCALED, + PIPE_FORMAT_R8_SNORM, + PIPE_FORMAT_R8G8_SNORM, + PIPE_FORMAT_R8G8B8_SNORM, + PIPE_FORMAT_R8G8B8A8_SNORM, + PIPE_FORMAT_R8G8B8X8_SNORM, + PIPE_FORMAT_B6G5R5_SNORM, + PIPE_FORMAT_A8B8G8R8_SNORM, + PIPE_FORMAT_X8B8G8R8_SNORM, + PIPE_FORMAT_R8_SSCALED, + PIPE_FORMAT_R8G8_SSCALED, + PIPE_FORMAT_R8G8B8_SSCALED, + PIPE_FORMAT_R8G8B8A8_SSCALED, + PIPE_FORMAT_R8G8B8X8_SSCALED, + PIPE_FORMAT_R32_FIXED, + PIPE_FORMAT_R32G32_FIXED, + PIPE_FORMAT_R32G32B32_FIXED, + PIPE_FORMAT_R32G32B32A32_FIXED, + + PIPE_FORMAT_L8_SRGB, + PIPE_FORMAT_A8L8_SRGB, + PIPE_FORMAT_R8G8B8_SRGB, + PIPE_FORMAT_R8G8B8A8_SRGB, + PIPE_FORMAT_R8G8B8X8_SRGB, + PIPE_FORMAT_A8R8G8B8_SRGB, + PIPE_FORMAT_X8R8G8B8_SRGB, + PIPE_FORMAT_B8G8R8A8_SRGB, + PIPE_FORMAT_B8G8R8X8_SRGB, + + PIPE_FORMAT_X8UB8UG8SR8S_NORM, + PIPE_FORMAT_B6UG5SR5S_NORM, + + PIPE_FORMAT_DXT1_RGB, + PIPE_FORMAT_DXT1_RGBA, + PIPE_FORMAT_DXT3_RGBA, + PIPE_FORMAT_DXT5_RGBA, + + PIPE_FORMAT_DXT1_SRGB, + PIPE_FORMAT_DXT1_SRGBA, + PIPE_FORMAT_DXT3_SRGBA, + PIPE_FORMAT_DXT5_SRGBA, +}; + + +struct pipe_format_block +{ + unsigned size; + unsigned width; + unsigned height; +}; + diff --git a/src/gallium/state_trackers/python/p_state.i b/src/gallium/state_trackers/python/p_state.i new file mode 100644 index 0000000000..90f157e0ab --- /dev/null +++ b/src/gallium/state_trackers/python/p_state.i @@ -0,0 +1,137 @@ + /************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * @file + * SWIG interface definion for Gallium types. + * + * @author Jose Fonseca <jrfonseca@tungstengraphics.com> + */ + +%module gallium; + +%ignore winsys; +%ignore pipe_vertex_buffer::buffer; + +%include "pipe/p_compiler.h"; +%include "pipe/p_state.h"; + + +%array_class(struct pipe_stencil_state, StencilArray); + + +%extend pipe_framebuffer_state { + + pipe_framebuffer_state(void) { + return CALLOC_STRUCT(pipe_framebuffer_state); + } + + ~pipe_framebuffer_state() { + unsigned index; + for(index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) + pipe_surface_reference(&$self->cbufs[index], NULL); + pipe_surface_reference(&$self->zsbuf, NULL); + FREE($self); + } + + void + set_cbuf(unsigned index, struct st_surface *surface) + { + struct pipe_surface *_surface = NULL; + + if(index >= PIPE_MAX_COLOR_BUFS) + SWIG_exception(SWIG_ValueError, "index out of bounds"); + + if(surface) { + _surface = st_pipe_surface(surface, PIPE_BUFFER_USAGE_GPU_WRITE); + if(!_surface) + SWIG_exception(SWIG_ValueError, "couldn't acquire surface for writing"); + } + + pipe_surface_reference(&$self->cbufs[index], _surface); + + fail: + return; + } + + void + set_zsbuf(struct st_surface *surface) + { + struct pipe_surface *_surface = NULL; + + if(surface) { + _surface = st_pipe_surface(surface, PIPE_BUFFER_USAGE_GPU_WRITE); + if(!_surface) + SWIG_exception(SWIG_ValueError, "couldn't acquire surface for writing"); + } + + pipe_surface_reference(&$self->zsbuf, _surface); + + fail: + return; + } + +}; + + +%extend pipe_shader_state { + + pipe_shader_state(const char *text, unsigned num_tokens = 1024) { + struct tgsi_token *tokens; + struct pipe_shader_state *shader; + + tokens = MALLOC(num_tokens * sizeof(struct tgsi_token)); + if(!tokens) + goto error1; + + if(tgsi_text_translate(text, tokens, num_tokens ) != TRUE) + goto error2; + + shader = CALLOC_STRUCT(pipe_shader_state); + if(!shader) + goto error3; + + shader->tokens = tokens; + + return shader; + +error3: +error2: + FREE(tokens); +error1: + return NULL; + } + + ~pipe_shader_state() { + FREE((void*)$self->tokens); + FREE($self); + } + + void dump(unsigned flags = 0) { + tgsi_dump($self->tokens, flags); + } +} diff --git a/src/gallium/state_trackers/python/p_texture.i b/src/gallium/state_trackers/python/p_texture.i new file mode 100644 index 0000000000..1d513abf3c --- /dev/null +++ b/src/gallium/state_trackers/python/p_texture.i @@ -0,0 +1,450 @@ + /************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * @file + * SWIG interface definion for Gallium types. + * + * @author Jose Fonseca <jrfonseca@tungstengraphics.com> + */ + + +%nodefaultctor pipe_texture; +%nodefaultctor st_surface; +%nodefaultctor pipe_buffer; + +%nodefaultdtor pipe_texture; +%nodefaultdtor st_surface; +%nodefaultdtor pipe_buffer; + +%ignore pipe_texture::screen; + +%immutable st_surface::texture; +%immutable st_surface::face; +%immutable st_surface::level; +%immutable st_surface::zslice; + +%newobject pipe_texture::get_surface; + + +%extend pipe_texture { + + ~pipe_texture() { + struct pipe_texture *ptr = $self; + pipe_texture_reference(&ptr, NULL); + } + + unsigned get_width(unsigned level=0) { + return $self->width[level]; + } + + unsigned get_height(unsigned level=0) { + return $self->height[level]; + } + + unsigned get_depth(unsigned level=0) { + return $self->depth[level]; + } + + unsigned get_nblocksx(unsigned level=0) { + return $self->nblocksx[level]; + } + + unsigned get_nblocksy(unsigned level=0) { + return $self->nblocksy[level]; + } + + /** Get a surface which is a "view" into a texture */ + struct st_surface * + get_surface(unsigned face=0, unsigned level=0, unsigned zslice=0) + { + struct st_surface *surface; + + if(face >= ($self->target == PIPE_TEXTURE_CUBE ? 6U : 1U)) + SWIG_exception(SWIG_ValueError, "face out of bounds"); + if(level > $self->last_level) + SWIG_exception(SWIG_ValueError, "level out of bounds"); + if(zslice >= $self->depth[level]) + SWIG_exception(SWIG_ValueError, "zslice out of bounds"); + + surface = CALLOC_STRUCT(st_surface); + if(!surface) + return NULL; + + pipe_texture_reference(&surface->texture, $self); + surface->face = face; + surface->level = level; + surface->zslice = zslice; + + return surface; + + fail: + return NULL; + } + +}; + +struct st_surface +{ + %immutable; + + struct pipe_texture *texture; + unsigned face; + unsigned level; + unsigned zslice; + +}; + +%extend st_surface { + + %immutable; + + unsigned format; + unsigned width; + unsigned height; + unsigned nblocksx; + unsigned nblocksy; + + ~st_surface() { + pipe_texture_reference(&$self->texture, NULL); + FREE($self); + } + + %cstring_output_allocate_size(char **STRING, int *LENGTH, free(*$1)); + void get_tile_raw(unsigned x, unsigned y, unsigned w, unsigned h, char **STRING, int *LENGTH) + { + struct pipe_texture *texture = $self->texture; + struct pipe_screen *screen = texture->screen; + struct pipe_transfer *transfer; + unsigned stride; + + stride = pf_get_nblocksx(&texture->block, w) * texture->block.size; + *LENGTH = pf_get_nblocksy(&texture->block, h) * stride; + *STRING = (char *) malloc(*LENGTH); + if(!*STRING) + return; + + transfer = screen->get_tex_transfer(screen, + $self->texture, + $self->face, + $self->level, + $self->zslice, + PIPE_TRANSFER_READ, + x, y, w, h); + if(transfer) { + pipe_get_tile_raw(transfer, 0, 0, w, h, *STRING, stride); + screen->tex_transfer_destroy(transfer); + } + } + + %cstring_input_binary(const char *STRING, unsigned LENGTH); + void put_tile_raw(unsigned x, unsigned y, unsigned w, unsigned h, const char *STRING, unsigned LENGTH, unsigned stride = 0) + { + struct pipe_texture *texture = $self->texture; + struct pipe_screen *screen = texture->screen; + struct pipe_transfer *transfer; + + if(stride == 0) + stride = pf_get_nblocksx(&texture->block, w) * texture->block.size; + + if(LENGTH < pf_get_nblocksy(&texture->block, h) * stride) + SWIG_exception(SWIG_ValueError, "offset must be smaller than buffer size"); + + transfer = screen->get_tex_transfer(screen, + $self->texture, + $self->face, + $self->level, + $self->zslice, + PIPE_TRANSFER_WRITE, + x, y, w, h); + if(!transfer) + SWIG_exception(SWIG_MemoryError, "couldn't initiate transfer"); + + pipe_put_tile_raw(transfer, 0, 0, w, h, STRING, stride); + screen->tex_transfer_destroy(transfer); + + fail: + return; + } + + void + get_tile_rgba(unsigned x, unsigned y, unsigned w, unsigned h, float *rgba) + { + struct pipe_screen *screen = $self->texture->screen; + struct pipe_transfer *transfer; + transfer = screen->get_tex_transfer(screen, + $self->texture, + $self->face, + $self->level, + $self->zslice, + PIPE_TRANSFER_READ, + x, y, w, h); + if(transfer) { + pipe_get_tile_rgba(transfer, 0, 0, w, h, rgba); + screen->tex_transfer_destroy(transfer); + } + } + + void + put_tile_rgba(unsigned x, unsigned y, unsigned w, unsigned h, const float *rgba) + { + struct pipe_screen *screen = $self->texture->screen; + struct pipe_transfer *transfer; + transfer = screen->get_tex_transfer(screen, + $self->texture, + $self->face, + $self->level, + $self->zslice, + PIPE_TRANSFER_WRITE, + x, y, w, h); + if(transfer) { + pipe_put_tile_rgba(transfer, 0, 0, w, h, rgba); + screen->tex_transfer_destroy(transfer); + } + } + + %cstring_output_allocate_size(char **STRING, int *LENGTH, free(*$1)); + void + get_tile_rgba8(unsigned x, unsigned y, unsigned w, unsigned h, char **STRING, int *LENGTH) + { + struct pipe_screen *screen = $self->texture->screen; + struct pipe_transfer *transfer; + float *rgba; + unsigned char *rgba8; + unsigned i, j, k; + + *LENGTH = 0; + *STRING = NULL; + + if (!$self) + return; + + *LENGTH = h*w*4; + *STRING = (char *) malloc(*LENGTH); + if(!*STRING) + return; + + rgba = malloc(h*w*4*sizeof(float)); + if(!rgba) + return; + + rgba8 = (unsigned char *) *STRING; + + transfer = screen->get_tex_transfer(screen, + $self->texture, + $self->face, + $self->level, + $self->zslice, + PIPE_TRANSFER_READ, + x, y, + w, h); + if(transfer) { + pipe_get_tile_rgba(transfer, 0, 0, w, h, rgba); + for(j = 0; j < h; ++j) { + for(i = 0; i < w; ++i) + for(k = 0; k <4; ++k) + rgba8[j*w*4 + i*4 + k] = float_to_ubyte(rgba[j*w*4 + i*4 + k]); + } + screen->tex_transfer_destroy(transfer); + } + + free(rgba); + } + + void + get_tile_z(unsigned x, unsigned y, unsigned w, unsigned h, unsigned *z) + { + struct pipe_screen *screen = $self->texture->screen; + struct pipe_transfer *transfer; + transfer = screen->get_tex_transfer(screen, + $self->texture, + $self->face, + $self->level, + $self->zslice, + PIPE_TRANSFER_READ, + x, y, w, h); + if(transfer) { + pipe_get_tile_z(transfer, 0, 0, w, h, z); + screen->tex_transfer_destroy(transfer); + } + } + + void + put_tile_z(unsigned x, unsigned y, unsigned w, unsigned h, const unsigned *z) + { + struct pipe_screen *screen = $self->texture->screen; + struct pipe_transfer *transfer; + transfer = screen->get_tex_transfer(screen, + $self->texture, + $self->face, + $self->level, + $self->zslice, + PIPE_TRANSFER_WRITE, + x, y, w, h); + if(transfer) { + pipe_put_tile_z(transfer, 0, 0, w, h, z); + screen->tex_transfer_destroy(transfer); + } + } + + void + sample_rgba(float *rgba) { + st_sample_surface($self, rgba); + } + + unsigned + compare_tile_rgba(unsigned x, unsigned y, unsigned w, unsigned h, const float *rgba, float tol = 0.0) + { + struct pipe_screen *screen = $self->texture->screen; + struct pipe_transfer *transfer; + float *rgba2; + const float *p1; + const float *p2; + unsigned i, j, n; + + rgba2 = MALLOC(h*w*4*sizeof(float)); + if(!rgba2) + return ~0; + + transfer = screen->get_tex_transfer(screen, + $self->texture, + $self->face, + $self->level, + $self->zslice, + PIPE_TRANSFER_READ, + x, y, w, h); + if(!transfer) { + FREE(rgba2); + return ~0; + } + + pipe_get_tile_rgba(transfer, 0, 0, w, h, rgba2); + screen->tex_transfer_destroy(transfer); + + p1 = rgba; + p2 = rgba2; + n = 0; + for(i = h*w; i; --i) { + unsigned differs = 0; + for(j = 4; j; --j) { + float delta = *p2++ - *p1++; + if (delta < -tol || delta > tol) + differs = 1; + } + n += differs; + } + + FREE(rgba2); + + return n; + } + +}; + +%{ + static enum pipe_format + st_surface_format_get(struct st_surface *surface) + { + return surface->texture->format; + } + + static unsigned + st_surface_width_get(struct st_surface *surface) + { + return surface->texture->width[surface->level]; + } + + static unsigned + st_surface_height_get(struct st_surface *surface) + { + return surface->texture->height[surface->level]; + } + + static unsigned + st_surface_nblocksx_get(struct st_surface *surface) + { + return surface->texture->nblocksx[surface->level]; + } + + static unsigned + st_surface_nblocksy_get(struct st_surface *surface) + { + return surface->texture->nblocksy[surface->level]; + } +%} + +/* Avoid naming conflict with p_inlines.h's pipe_buffer_read/write */ +%rename(read) read_; +%rename(write) write_; + +%extend pipe_buffer { + + ~pipe_buffer() { + struct pipe_buffer *ptr = $self; + pipe_buffer_reference(&ptr, NULL); + } + + unsigned __len__(void) + { + assert(p_atomic_read(&$self->reference.count) > 0); + return $self->size; + } + + %cstring_output_allocate_size(char **STRING, int *LENGTH, free(*$1)); + void read_(char **STRING, int *LENGTH) + { + struct pipe_screen *screen = $self->screen; + + assert(p_atomic_read(&$self->reference.count) > 0); + + *LENGTH = $self->size; + *STRING = (char *) malloc($self->size); + if(!*STRING) + return; + + pipe_buffer_read(screen, $self, 0, $self->size, *STRING); + } + + %cstring_input_binary(const char *STRING, unsigned LENGTH); + void write_(const char *STRING, unsigned LENGTH, unsigned offset = 0) + { + struct pipe_screen *screen = $self->screen; + + assert(p_atomic_read(&$self->reference.count) > 0); + + if(offset > $self->size) + SWIG_exception(SWIG_ValueError, "offset must be smaller than buffer size"); + + if(offset + LENGTH > $self->size) + SWIG_exception(SWIG_ValueError, "data length must fit inside the buffer"); + + pipe_buffer_write(screen, $self, offset, LENGTH, STRING); + +fail: + return; + } +}; diff --git a/src/gallium/state_trackers/python/retrace/README b/src/gallium/state_trackers/python/retrace/README new file mode 100644 index 0000000000..822cd11404 --- /dev/null +++ b/src/gallium/state_trackers/python/retrace/README @@ -0,0 +1,17 @@ +This is an application written in python to replay the traces captured by the + trace pipe driver. + + +To use it follow the instructions in src/gallium/drivers/trace/README and +src/gallium/state_trackers/python/README, and then do + + python src/gallium/state_trackers/python/samples/retrace/interpreter.py filename.trace + + +This is still work in progress: +- not everything is captured/replayed + - surface/textures contents +- any tiny error will result in a crash + +-- +Jose Fonseca <jrfonseca@tungstengraphics.com> diff --git a/src/gallium/state_trackers/python/retrace/format.py b/src/gallium/state_trackers/python/retrace/format.py new file mode 100755 index 0000000000..a4285bfe07 --- /dev/null +++ b/src/gallium/state_trackers/python/retrace/format.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +import sys + + +class Formatter: + '''Plain formatter''' + + def __init__(self, stream): + self.stream = stream + + def text(self, text): + self.stream.write(text) + + def newline(self): + self.text('\n') + + def function(self, name): + self.text(name) + + def variable(self, name): + self.text(name) + + def literal(self, value): + self.text(str(value)) + + def address(self, addr): + self.text(str(addr)) + + +class AnsiFormatter(Formatter): + '''Formatter for plain-text files which outputs ANSI escape codes. See + http://en.wikipedia.org/wiki/ANSI_escape_code for more information + concerning ANSI escape codes. + ''' + + _csi = '\33[' + + _normal = '0m' + _bold = '1m' + _italic = '3m' + _red = '31m' + _green = '32m' + _blue = '34m' + + def _escape(self, code): + self.text(self._csi + code) + + def function(self, name): + self._escape(self._bold) + Formatter.function(self, name) + self._escape(self._normal) + + def variable(self, name): + self._escape(self._italic) + Formatter.variable(self, name) + self._escape(self._normal) + + def literal(self, value): + self._escape(self._blue) + Formatter.literal(self, value) + self._escape(self._normal) + + def address(self, value): + self._escape(self._green) + Formatter.address(self, value) + self._escape(self._normal) + + +class WindowsConsoleFormatter(Formatter): + '''Formatter for the Windows Console. See + http://code.activestate.com/recipes/496901/ for more information. + ''' + + STD_INPUT_HANDLE = -10 + STD_OUTPUT_HANDLE = -11 + STD_ERROR_HANDLE = -12 + + FOREGROUND_BLUE = 0x01 + FOREGROUND_GREEN = 0x02 + FOREGROUND_RED = 0x04 + FOREGROUND_INTENSITY = 0x08 + BACKGROUND_BLUE = 0x10 + BACKGROUND_GREEN = 0x20 + BACKGROUND_RED = 0x40 + BACKGROUND_INTENSITY = 0x80 + + _normal = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED + _bold = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY + _italic = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED + _red = FOREGROUND_RED | FOREGROUND_INTENSITY + _green = FOREGROUND_GREEN | FOREGROUND_INTENSITY + _blue = FOREGROUND_BLUE | FOREGROUND_INTENSITY + + def __init__(self, stream): + Formatter.__init__(self, stream) + + if stream is sys.stdin: + nStdHandle = self.STD_INPUT_HANDLE + elif stream is sys.stdout: + nStdHandle = self.STD_OUTPUT_HANDLE + elif stream is sys.stderr: + nStdHandle = self.STD_ERROR_HANDLE + else: + nStdHandle = None + + if nStdHandle: + import ctypes + self.handle = ctypes.windll.kernel32.GetStdHandle(nStdHandle) + else: + self.handle = None + + def _attribute(self, attr): + if self.handle: + import ctypes + ctypes.windll.kernel32.SetConsoleTextAttribute(self.handle, attr) + + def function(self, name): + self._attribute(self._bold) + Formatter.function(self, name) + self._attribute(self._normal) + + def variable(self, name): + self._attribute(self._italic) + Formatter.variable(self, name) + self._attribute(self._normal) + + def literal(self, value): + self._attribute(self._blue) + Formatter.literal(self, value) + self._attribute(self._normal) + + def address(self, value): + self._attribute(self._green) + Formatter.address(self, value) + self._attribute(self._normal) + + +def DefaultFormatter(stream): + if sys.platform in ('linux2', 'cygwin'): + return AnsiFormatter(stream) + elif sys.platform in ('win32',): + return WindowsConsoleFormatter(stream) + else: + return Formatter(stream) + diff --git a/src/gallium/state_trackers/python/retrace/interpreter.py b/src/gallium/state_trackers/python/retrace/interpreter.py new file mode 100755 index 0000000000..6f0bd6ae52 --- /dev/null +++ b/src/gallium/state_trackers/python/retrace/interpreter.py @@ -0,0 +1,748 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +import sys +import struct + +import gallium +import model +import parse as parser + + +try: + from struct import unpack_from +except ImportError: + def unpack_from(fmt, buf, offset=0): + size = struct.calcsize(fmt) + return struct.unpack(fmt, buf[offset:offset + size]) + + +def make_image(surface, x=None, y=None, w=None, h=None): + if x is None: + x = 0 + if y is None: + y = 0 + if w is None: + w = surface.width - x + if h is None: + h = surface.height - y + data = surface.get_tile_rgba8(0, 0, surface.width, surface.height) + + import Image + outimage = Image.fromstring('RGBA', (surface.width, surface.height), data, "raw", 'RGBA', 0, 1) + return outimage + +def save_image(filename, surface, x=None, y=None, w=None, h=None): + outimage = make_image(surface, x, y, w, h) + outimage.save(filename, "PNG") + +def show_image(surface, title, x=None, y=None, w=None, h=None): + outimage = make_image(surface, x, y, w, h) + + import Tkinter as tk + from PIL import Image, ImageTk + root = tk.Tk() + + root.title(title) + + image1 = ImageTk.PhotoImage(outimage) + w = image1.width() + h = image1.height() + x = 100 + y = 100 + root.geometry("%dx%d+%d+%d" % (w, h, x, y)) + panel1 = tk.Label(root, image=image1) + panel1.pack(side='top', fill='both', expand='yes') + panel1.image = image1 + root.mainloop() + + +class Struct: + """C-like struct""" + + # A basic Python class can pass as a C-like structure + pass + + +struct_factories = { + "pipe_blend_color": gallium.BlendColor, + "pipe_blend_state": gallium.Blend, + #"pipe_clip_state": gallium.Clip, + #"pipe_constant_buffer": gallium.ConstantBuffer, + "pipe_depth_state": gallium.Depth, + "pipe_stencil_state": gallium.Stencil, + "pipe_alpha_state": gallium.Alpha, + "pipe_depth_stencil_alpha_state": gallium.DepthStencilAlpha, + "pipe_format_block": gallium.FormatBlock, + #"pipe_framebuffer_state": gallium.Framebuffer, + "pipe_poly_stipple": gallium.PolyStipple, + "pipe_rasterizer_state": gallium.Rasterizer, + "pipe_sampler_state": gallium.Sampler, + "pipe_scissor_state": gallium.Scissor, + #"pipe_shader_state": gallium.Shader, + #"pipe_vertex_buffer": gallium.VertexBuffer, + "pipe_vertex_element": gallium.VertexElement, + "pipe_viewport_state": gallium.Viewport, + #"pipe_texture": gallium.Texture, +} + + +member_array_factories = { + "pipe_rasterizer_state": {"sprite_coord_mode": gallium.ByteArray}, + "pipe_poly_stipple": {"stipple": gallium.UnsignedArray}, + "pipe_viewport_state": {"scale": gallium.FloatArray, "translate": gallium.FloatArray}, + #"pipe_clip_state": {"ucp": gallium.FloatArray}, + "pipe_depth_stencil_alpha_state": {"stencil": gallium.StencilArray}, + "pipe_blend_color": {"color": gallium.FloatArray}, + "pipe_sampler_state": {"border_color": gallium.FloatArray}, +} + + +class Translator(model.Visitor): + """Translate model arguments into regular Python objects""" + + def __init__(self, interpreter): + self.interpreter = interpreter + self.result = None + + def visit(self, node): + self.result = None + node.visit(self) + return self.result + + def visit_literal(self, node): + self.result = node.value + + def visit_named_constant(self, node): + # lookup the named constant in the gallium module + self.result = getattr(gallium, node.name) + + def visit_array(self, node): + array = [] + for element in node.elements: + array.append(self.visit(element)) + self.result = array + + def visit_struct(self, node): + struct_factory = struct_factories.get(node.name, Struct) + struct = struct_factory() + for member_name, member_node in node.members: + member_value = self.visit(member_node) + try: + array_factory = member_array_factories[node.name][member_name] + except KeyError: + pass + else: + assert isinstance(member_value, list) + array = array_factory(len(member_value)) + for i in range(len(member_value)): + array[i] = member_value[i] + member_value = array + #print node.name, member_name, member_value + assert isinstance(struct, Struct) or hasattr(struct, member_name) + setattr(struct, member_name, member_value) + self.result = struct + + def visit_pointer(self, node): + self.result = self.interpreter.lookup_object(node.address) + + +class Object: + + def __init__(self, interpreter, real): + self.interpreter = interpreter + self.real = real + + +class Global(Object): + + def __init__(self, interpreter, real): + self.interpreter = interpreter + self.real = real + + def pipe_winsys_create(self): + return Winsys(self.interpreter, gallium.Device()) + + def pipe_screen_create(self, winsys=None): + if winsys is None: + real = gallium.Device() + else: + real = winsys.real + return Screen(self.interpreter, real) + + def pipe_context_create(self, screen): + context = screen.real.context_create() + return Context(self.interpreter, context) + + +class Winsys(Object): + + def __init__(self, interpreter, real): + self.interpreter = interpreter + self.real = real + + def get_name(self): + pass + + def user_buffer_create(self, data, size): + # We don't really care to distinguish between user and regular buffers + buffer = self.real.buffer_create(size, + 4, + gallium.PIPE_BUFFER_USAGE_CPU_READ | + gallium.PIPE_BUFFER_USAGE_CPU_WRITE ) + assert size == len(data) + buffer.write(data) + return buffer + + def buffer_create(self, alignment, usage, size): + return self.real.buffer_create(size, alignment, usage) + + def buffer_destroy(self, buffer): + pass + + def buffer_write(self, buffer, data, size): + assert size == len(data) + buffer.write(data) + + def fence_finish(self, fence, flags): + pass + + def fence_reference(self, dst, src): + pass + + def flush_frontbuffer(self, surface): + pass + + def surface_alloc(self): + return None + + def surface_release(self, surface): + pass + + +class Transfer: + + def __init__(self, surface, x, y, w, h): + self.surface = surface + self.x = x + self.y = y + self.w = w + self.h = h + + +class Screen(Object): + + def destroy(self): + pass + + def get_name(self): + pass + + def get_vendor(self): + pass + + def get_param(self, param): + pass + + def get_paramf(self, param): + pass + + def is_format_supported(self, format, target, tex_usage, geom_flags): + return self.real.is_format_supported(format, target, tex_usage, geom_flags) + + def texture_create(self, templat): + return self.real.texture_create( + format = templat.format, + width = templat.width[0], + height = templat.height[0], + depth = templat.depth[0], + last_level = templat.last_level, + target = templat.target, + tex_usage = templat.tex_usage, + ) + + def texture_destroy(self, texture): + self.interpreter.unregister_object(texture) + + def texture_release(self, surface): + pass + + def get_tex_surface(self, texture, face, level, zslice, usage): + if texture is None: + return None + return texture.get_surface(face, level, zslice) + + def tex_surface_destroy(self, surface): + self.interpreter.unregister_object(surface) + + def tex_surface_release(self, surface): + pass + + def surface_write(self, surface, data, stride, size): + if surface is None: + return + assert surface.nblocksy * stride == size + surface.put_tile_raw(0, 0, surface.width, surface.height, data, stride) + + def get_tex_transfer(self, texture, face, level, zslice, usage, x, y, w, h): + if texture is None: + return None + transfer = Transfer(texture.get_surface(face, level, zslice), x, y, w, h) + if transfer and usage != gallium.PIPE_TRANSFER_WRITE: + if self.interpreter.options.all: + self.interpreter.present(transfer.surface, 'transf_read', x, y, w, h) + return transfer + + def tex_transfer_destroy(self, transfer): + self.interpreter.unregister_object(transfer) + + def transfer_write(self, transfer, stride, data, size): + if transfer is None: + return + transfer.surface.put_tile_raw(transfer.x, transfer.y, transfer.w, transfer.h, data, stride) + if self.interpreter.options.all: + self.interpreter.present(transfer.surface, 'transf_write', transfer.x, transfer.y, transfer.w, transfer.h) + + def user_buffer_create(self, data, size): + # We don't really care to distinguish between user and regular buffers + buffer = self.real.buffer_create(size, + 4, + gallium.PIPE_BUFFER_USAGE_CPU_READ | + gallium.PIPE_BUFFER_USAGE_CPU_WRITE ) + assert size == len(data) + buffer.write(data) + return buffer + + def buffer_create(self, alignment, usage, size): + return self.real.buffer_create(size, alignment, usage) + + def buffer_destroy(self, buffer): + pass + + def buffer_write(self, buffer, data, size, offset=0): + assert size == len(data) + buffer.write(data) + + def fence_finish(self, fence, flags): + pass + + def fence_reference(self, dst, src): + pass + + def flush_frontbuffer(self, surface): + pass + + +class Context(Object): + + def __init__(self, interpreter, real): + Object.__init__(self, interpreter, real) + self.cbufs = [] + self.zsbuf = None + self.vbufs = [] + self.velems = [] + self.dirty = False + + def destroy(self): + pass + + def create_blend_state(self, state): + return state + + def bind_blend_state(self, state): + if state is not None: + self.real.set_blend(state) + + def delete_blend_state(self, state): + pass + + def create_sampler_state(self, state): + return state + + def delete_sampler_state(self, state): + pass + + def bind_sampler_states(self, num_states, states): + for i in range(num_states): + self.real.set_sampler(i, states[i]) + + def create_rasterizer_state(self, state): + return state + + def bind_rasterizer_state(self, state): + if state is not None: + self.real.set_rasterizer(state) + + def delete_rasterizer_state(self, state): + pass + + def create_depth_stencil_alpha_state(self, state): + return state + + def bind_depth_stencil_alpha_state(self, state): + if state is not None: + self.real.set_depth_stencil_alpha(state) + + def delete_depth_stencil_alpha_state(self, state): + pass + + def create_fs_state(self, state): + tokens = str(state.tokens) + shader = gallium.Shader(tokens) + return shader + + create_vs_state = create_fs_state + + def bind_fs_state(self, state): + self.real.set_fragment_shader(state) + + def bind_vs_state(self, state): + self.real.set_vertex_shader(state) + + def delete_fs_state(self, state): + pass + + delete_vs_state = delete_fs_state + + def set_blend_color(self, state): + self.real.set_blend_color(state) + + def set_clip_state(self, state): + _state = gallium.Clip() + _state.nr = state.nr + if state.nr: + # FIXME + ucp = gallium.FloatArray(gallium.PIPE_MAX_CLIP_PLANES*4) + for i in range(len(state.ucp)): + for j in range(len(state.ucp[i])): + ucp[i*4 + j] = state.ucp[i][j] + _state.ucp = ucp + self.real.set_clip(_state) + + def dump_constant_buffer(self, buffer): + if not self.interpreter.verbosity(2): + return + + data = buffer.read() + format = '4f' + index = 0 + for offset in range(0, len(data), struct.calcsize(format)): + x, y, z, w = unpack_from(format, data, offset) + sys.stdout.write('\tCONST[%2u] = {%10.4f, %10.4f, %10.4f, %10.4f}\n' % (index, x, y, z, w)) + index += 1 + sys.stdout.flush() + + def set_constant_buffer(self, shader, index, buffer): + if buffer is not None: + self.real.set_constant_buffer(shader, index, buffer.buffer) + + self.dump_constant_buffer(buffer.buffer) + + def set_framebuffer_state(self, state): + _state = gallium.Framebuffer() + _state.width = state.width + _state.height = state.height + _state.nr_cbufs = state.nr_cbufs + for i in range(len(state.cbufs)): + _state.set_cbuf(i, state.cbufs[i]) + _state.set_zsbuf(state.zsbuf) + self.real.set_framebuffer(_state) + + self.cbufs = state.cbufs + self.zsbuf = state.zsbuf + + def set_polygon_stipple(self, state): + self.real.set_polygon_stipple(state) + + def set_scissor_state(self, state): + self.real.set_scissor(state) + + def set_viewport_state(self, state): + self.real.set_viewport(state) + + def set_sampler_textures(self, num_textures, textures): + for i in range(num_textures): + self.real.set_sampler_texture(i, textures[i]) + + def set_vertex_buffers(self, num_buffers, buffers): + self.vbufs = buffers[0:num_buffers] + for i in range(num_buffers): + vbuf = buffers[i] + self.real.set_vertex_buffer( + i, + stride = vbuf.stride, + max_index = vbuf.max_index, + buffer_offset = vbuf.buffer_offset, + buffer = vbuf.buffer, + ) + + def set_vertex_elements(self, num_elements, elements): + self.velems = elements[0:num_elements] + for i in range(num_elements): + self.real.set_vertex_element(i, elements[i]) + self.real.set_vertex_elements(num_elements) + + def set_edgeflags(self, bitfield): + # FIXME + pass + + def dump_vertices(self, start, count): + if not self.interpreter.verbosity(2): + return + + for index in range(start, start + count): + if index >= start + 16: + sys.stdout.write('\t...\n') + break + sys.stdout.write('\t{\n') + for velem in self.velems: + vbuf = self.vbufs[velem.vertex_buffer_index] + + offset = vbuf.buffer_offset + velem.src_offset + vbuf.stride*index + format = { + gallium.PIPE_FORMAT_R32_FLOAT: 'f', + gallium.PIPE_FORMAT_R32G32_FLOAT: '2f', + gallium.PIPE_FORMAT_R32G32B32_FLOAT: '3f', + gallium.PIPE_FORMAT_R32G32B32A32_FLOAT: '4f', + gallium.PIPE_FORMAT_B8G8R8A8_UNORM: '4B', + }[velem.src_format] + + data = vbuf.buffer.read() + values = unpack_from(format, data, offset) + sys.stdout.write('\t\t{' + ', '.join(map(str, values)) + '},\n') + assert len(values) == velem.nr_components + sys.stdout.write('\t},\n') + sys.stdout.flush() + + def dump_indices(self, ibuf, isize, start, count): + if not self.interpreter.verbosity(2): + return + + format = { + 1: 'B', + 2: 'H', + 4: 'I', + }[isize] + + assert struct.calcsize(format) == isize + + data = ibuf.read() + maxindex, minindex = 0, 0xffffffff + + sys.stdout.write('\t{\n') + for i in range(start, start + count): + if i >= start + 16: + sys.stdout.write('\t...\n') + break + offset = i*isize + index, = unpack_from(format, data, offset) + sys.stdout.write('\t\t%u,\n' % index) + minindex = min(minindex, index) + maxindex = max(maxindex, index) + sys.stdout.write('\t},\n') + sys.stdout.flush() + + return minindex, maxindex + + def draw_arrays(self, mode, start, count): + self.dump_vertices(start, count) + + self.real.draw_arrays(mode, start, count) + self._set_dirty() + + def draw_elements(self, indexBuffer, indexSize, mode, start, count): + if self.interpreter.verbosity(2): + minindex, maxindex = self.dump_indices(indexBuffer, indexSize, start, count) + self.dump_vertices(minindex, maxindex - minindex) + + self.real.draw_elements(indexBuffer, indexSize, mode, start, count) + self._set_dirty() + + def draw_range_elements(self, indexBuffer, indexSize, minIndex, maxIndex, mode, start, count): + if self.interpreter.verbosity(2): + minindex, maxindex = self.dump_indices(indexBuffer, indexSize, start, count) + minindex = min(minindex, minIndex) + maxindex = min(maxindex, maxIndex) + self.dump_vertices(minindex, maxindex - minindex) + + self.real.draw_range_elements(indexBuffer, indexSize, minIndex, maxIndex, mode, start, count) + self._set_dirty() + + def surface_copy(self, dest, destx, desty, src, srcx, srcy, width, height): + if dest is not None and src is not None: + if self.interpreter.options.all: + self.interpreter.present(src, 'surface_copy_src', srcx, srcy, width, height) + self.real.surface_copy(dest, destx, desty, src, srcx, srcy, width, height) + if dest in self.cbufs: + self._set_dirty() + flags = gallium.PIPE_FLUSH_FRAME + else: + flags = 0 + self.flush(flags) + if self.interpreter.options.all: + self.interpreter.present(dest, 'surface_copy_dest', destx, desty, width, height) + + def is_texture_referenced(self, texture, face, level): + #return self.real.is_texture_referenced(format, texture, face, level) + pass + + def is_buffer_referenced(self, buf): + #return self.real.is_buffer_referenced(format, buf) + pass + + def _set_dirty(self): + if self.interpreter.options.step: + self._present() + else: + self.dirty = True + + def flush(self, flags): + self.real.flush(flags) + if self.dirty: + if flags & gallium.PIPE_FLUSH_FRAME: + self._present() + self.dirty = False + return None + + def clear(self, buffers, rgba, depth, stencil): + _rgba = gallium.FloatArray(4) + for i in range(4): + _rgba[i] = rgba[i] + self.real.clear(buffers, _rgba, depth, stencil) + + def _present(self): + self.real.flush() + + if self.cbufs and self.cbufs[0]: + self.interpreter.present(self.cbufs[0], "cbuf") + if self.zsbuf: + if self.interpreter.options.all: + self.interpreter.present(self.zsbuf, "zsbuf") + + +class Interpreter(parser.TraceDumper): + + ignore_calls = set(( + ('pipe_screen', 'is_format_supported'), + ('pipe_screen', 'get_param'), + ('pipe_screen', 'get_paramf'), + )) + + def __init__(self, stream, options): + parser.TraceDumper.__init__(self, stream) + self.options = options + self.objects = {} + self.result = None + self.globl = Global(self, None) + self.call_no = None + + def register_object(self, address, object): + self.objects[address] = object + + def unregister_object(self, object): + # FIXME: + pass + + def lookup_object(self, address): + return self.objects[address] + + def interpret(self, trace): + for call in trace.calls: + self.interpret_call(call) + + def handle_call(self, call): + if self.options.stop and call.no > self.options.stop: + sys.exit(0) + + if (call.klass, call.method) in self.ignore_calls: + return + + self.call_no = call.no + + if self.verbosity(1): + parser.TraceDumper.handle_call(self, call) + sys.stdout.flush() + + args = [(str(name), self.interpret_arg(arg)) for name, arg in call.args] + + if call.klass: + name, obj = args[0] + args = args[1:] + else: + obj = self.globl + + method = getattr(obj, call.method) + ret = method(**dict(args)) + + if call.ret and isinstance(call.ret, model.Pointer): + if ret is None: + sys.stderr.write('warning: NULL returned\n') + self.register_object(call.ret.address, ret) + + self.call_no = None + + def interpret_arg(self, node): + translator = Translator(self) + return translator.visit(node) + + def verbosity(self, level): + return self.options.verbosity >= level + + def present(self, surface, description, x=None, y=None, w=None, h=None): + if self.call_no < self.options.start: + return + + if self.options.images: + filename = '%04u_%s.png' % (self.call_no, description) + save_image(filename, surface, x, y, w, h) + else: + title = '%u. %s' % (self.call_no, description) + show_image(surface, title, x, y, w, h) + + +class Main(parser.Main): + + def get_optparser(self): + optparser = parser.Main.get_optparser(self) + optparser.add_option("-q", "--quiet", action="store_const", const=0, dest="verbosity", help="no messages") + optparser.add_option("-v", "--verbose", action="count", dest="verbosity", default=1, help="increase verbosity level") + optparser.add_option("-i", "--images", action="store_true", dest="images", default=False, help="save images instead of showing them") + optparser.add_option("-a", "--all", action="store_true", dest="all", default=False, help="show depth, stencil, and transfers") + optparser.add_option("-s", "--step", action="store_true", dest="step", default=False, help="step trhough every draw") + optparser.add_option("-f", "--from", action="store", type="int", dest="start", default=0, help="from call no") + optparser.add_option("-t", "--to", action="store", type="int", dest="stop", default=0, help="until call no") + return optparser + + def process_arg(self, stream, options): + parser = Interpreter(stream, options) + parser.parse() + + +if __name__ == '__main__': + Main().main() diff --git a/src/gallium/state_trackers/python/retrace/model.py b/src/gallium/state_trackers/python/retrace/model.py new file mode 100755 index 0000000000..d4a079fb1e --- /dev/null +++ b/src/gallium/state_trackers/python/retrace/model.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +'''Trace data model.''' + + +import sys +import string +import format + +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + + +class Node: + + def visit(self, visitor): + raise NotImplementedError + + def __str__(self): + stream = StringIO() + formatter = format.DefaultFormatter(stream) + pretty_printer = PrettyPrinter(formatter) + self.visit(pretty_printer) + return stream.getvalue() + + +class Literal(Node): + + def __init__(self, value): + self.value = value + + def visit(self, visitor): + visitor.visit_literal(self) + + +class NamedConstant(Node): + + def __init__(self, name): + self.name = name + + def visit(self, visitor): + visitor.visit_named_constant(self) + + +class Array(Node): + + def __init__(self, elements): + self.elements = elements + + def visit(self, visitor): + visitor.visit_array(self) + + +class Struct(Node): + + def __init__(self, name, members): + self.name = name + self.members = members + + def visit(self, visitor): + visitor.visit_struct(self) + + +class Pointer(Node): + + def __init__(self, address): + self.address = address + + def visit(self, visitor): + visitor.visit_pointer(self) + + +class Call: + + def __init__(self, no, klass, method, args, ret): + self.no = no + self.klass = klass + self.method = method + self.args = args + self.ret = ret + + def visit(self, visitor): + visitor.visit_call(self) + + +class Trace: + + def __init__(self, calls): + self.calls = calls + + def visit(self, visitor): + visitor.visit_trace(self) + + +class Visitor: + + def visit_literal(self, node): + raise NotImplementedError + + def visit_named_constant(self, node): + raise NotImplementedError + + def visit_array(self, node): + raise NotImplementedError + + def visit_struct(self, node): + raise NotImplementedError + + def visit_pointer(self, node): + raise NotImplementedError + + def visit_call(self, node): + raise NotImplementedError + + def visit_trace(self, node): + raise NotImplementedError + + +class PrettyPrinter: + + def __init__(self, formatter): + self.formatter = formatter + + def visit_literal(self, node): + if isinstance(node.value, basestring): + if len(node.value) >= 4096 or node.value.strip(string.printable): + self.formatter.text('...') + return + + self.formatter.literal('"' + node.value + '"') + return + + self.formatter.literal(repr(node.value)) + + def visit_named_constant(self, node): + self.formatter.literal(node.name) + + def visit_array(self, node): + self.formatter.text('{') + sep = '' + for value in node.elements: + self.formatter.text(sep) + value.visit(self) + sep = ', ' + self.formatter.text('}') + + def visit_struct(self, node): + self.formatter.text('{') + sep = '' + for name, value in node.members: + self.formatter.text(sep) + self.formatter.variable(name) + self.formatter.text(' = ') + value.visit(self) + sep = ', ' + self.formatter.text('}') + + def visit_pointer(self, node): + self.formatter.address(node.address) + + def visit_call(self, node): + self.formatter.text('%s ' % node.no) + if node.klass is not None: + self.formatter.function(node.klass + '::' + node.method) + else: + self.formatter.function(node.method) + self.formatter.text('(') + sep = '' + for name, value in node.args: + self.formatter.text(sep) + self.formatter.variable(name) + self.formatter.text(' = ') + value.visit(self) + sep = ', ' + self.formatter.text(')') + if node.ret is not None: + self.formatter.text(' = ') + node.ret.visit(self) + + def visit_trace(self, node): + for call in node.calls: + call.visit(self) + self.formatter.newline() + diff --git a/src/gallium/state_trackers/python/retrace/parse.py b/src/gallium/state_trackers/python/retrace/parse.py new file mode 100755 index 0000000000..b08d368671 --- /dev/null +++ b/src/gallium/state_trackers/python/retrace/parse.py @@ -0,0 +1,392 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +import sys +import xml.parsers.expat +import binascii +import optparse + +from model import * + + +ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4) + + +class XmlToken: + + def __init__(self, type, name_or_data, attrs = None, line = None, column = None): + assert type in (ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF) + self.type = type + self.name_or_data = name_or_data + self.attrs = attrs + self.line = line + self.column = column + + def __str__(self): + if self.type == ELEMENT_START: + return '<' + self.name_or_data + ' ...>' + if self.type == ELEMENT_END: + return '</' + self.name_or_data + '>' + if self.type == CHARACTER_DATA: + return self.name_or_data + if self.type == EOF: + return 'end of file' + assert 0 + + +class XmlTokenizer: + """Expat based XML tokenizer.""" + + def __init__(self, fp, skip_ws = True): + self.fp = fp + self.tokens = [] + self.index = 0 + self.final = False + self.skip_ws = skip_ws + + self.character_pos = 0, 0 + self.character_data = '' + + self.parser = xml.parsers.expat.ParserCreate() + self.parser.StartElementHandler = self.handle_element_start + self.parser.EndElementHandler = self.handle_element_end + self.parser.CharacterDataHandler = self.handle_character_data + + def handle_element_start(self, name, attributes): + self.finish_character_data() + line, column = self.pos() + token = XmlToken(ELEMENT_START, name, attributes, line, column) + self.tokens.append(token) + + def handle_element_end(self, name): + self.finish_character_data() + line, column = self.pos() + token = XmlToken(ELEMENT_END, name, None, line, column) + self.tokens.append(token) + + def handle_character_data(self, data): + if not self.character_data: + self.character_pos = self.pos() + self.character_data += data + + def finish_character_data(self): + if self.character_data: + if not self.skip_ws or not self.character_data.isspace(): + line, column = self.character_pos + token = XmlToken(CHARACTER_DATA, self.character_data, None, line, column) + self.tokens.append(token) + self.character_data = '' + + def next(self): + size = 16*1024 + while self.index >= len(self.tokens) and not self.final: + self.tokens = [] + self.index = 0 + data = self.fp.read(size) + self.final = len(data) < size + data = data.rstrip('\0') + try: + self.parser.Parse(data, self.final) + except xml.parsers.expat.ExpatError, e: + #if e.code == xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS: + if e.code == 3: + pass + else: + raise e + if self.index >= len(self.tokens): + line, column = self.pos() + token = XmlToken(EOF, None, None, line, column) + else: + token = self.tokens[self.index] + self.index += 1 + return token + + def pos(self): + return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber + + +class TokenMismatch(Exception): + + def __init__(self, expected, found): + self.expected = expected + self.found = found + + def __str__(self): + return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found)) + + + +class XmlParser: + """Base XML document parser.""" + + def __init__(self, fp): + self.tokenizer = XmlTokenizer(fp) + self.consume() + + def consume(self): + self.token = self.tokenizer.next() + + def match_element_start(self, name): + return self.token.type == ELEMENT_START and self.token.name_or_data == name + + def match_element_end(self, name): + return self.token.type == ELEMENT_END and self.token.name_or_data == name + + def element_start(self, name): + while self.token.type == CHARACTER_DATA: + self.consume() + if self.token.type != ELEMENT_START: + raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token) + if self.token.name_or_data != name: + raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token) + attrs = self.token.attrs + self.consume() + return attrs + + def element_end(self, name): + while self.token.type == CHARACTER_DATA: + self.consume() + if self.token.type != ELEMENT_END: + raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token) + if self.token.name_or_data != name: + raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token) + self.consume() + + def character_data(self, strip = True): + data = '' + while self.token.type == CHARACTER_DATA: + data += self.token.name_or_data + self.consume() + if strip: + data = data.strip() + return data + + +class TraceParser(XmlParser): + + def __init__(self, fp): + XmlParser.__init__(self, fp) + self.last_call_no = 0 + + def parse(self): + self.element_start('trace') + while self.token.type not in (ELEMENT_END, EOF): + call = self.parse_call() + self.handle_call(call) + if self.token.type != EOF: + self.element_end('trace') + + def parse_call(self): + attrs = self.element_start('call') + try: + no = int(attrs['no']) + except KeyError: + self.last_call_no += 1 + no = self.last_call_no + else: + self.last_call_no = no + klass = attrs['class'] + method = attrs['method'] + args = [] + ret = None + while self.token.type == ELEMENT_START: + if self.token.name_or_data == 'arg': + arg = self.parse_arg() + args.append(arg) + elif self.token.name_or_data == 'ret': + ret = self.parse_ret() + elif self.token.name_or_data == 'call': + # ignore nested function calls + self.parse_call() + else: + raise TokenMismatch("<arg ...> or <ret ...>", self.token) + self.element_end('call') + + return Call(no, klass, method, args, ret) + + def parse_arg(self): + attrs = self.element_start('arg') + name = attrs['name'] + value = self.parse_value() + self.element_end('arg') + + return name, value + + def parse_ret(self): + attrs = self.element_start('ret') + value = self.parse_value() + self.element_end('ret') + + return value + + def parse_value(self): + expected_tokens = ('null', 'bool', 'int', 'uint', 'float', 'string', 'enum', 'array', 'struct', 'ptr', 'bytes') + if self.token.type == ELEMENT_START: + if self.token.name_or_data in expected_tokens: + method = getattr(self, 'parse_' + self.token.name_or_data) + return method() + raise TokenMismatch(" or " .join(expected_tokens), self.token) + + def parse_null(self): + self.element_start('null') + self.element_end('null') + return Literal(None) + + def parse_bool(self): + self.element_start('bool') + value = int(self.character_data()) + self.element_end('bool') + return Literal(value) + + def parse_int(self): + self.element_start('int') + value = int(self.character_data()) + self.element_end('int') + return Literal(value) + + def parse_uint(self): + self.element_start('uint') + value = int(self.character_data()) + self.element_end('uint') + return Literal(value) + + def parse_float(self): + self.element_start('float') + value = float(self.character_data()) + self.element_end('float') + return Literal(value) + + def parse_enum(self): + self.element_start('enum') + name = self.character_data() + self.element_end('enum') + return NamedConstant(name) + + def parse_string(self): + self.element_start('string') + value = self.character_data() + self.element_end('string') + return Literal(value) + + def parse_bytes(self): + self.element_start('bytes') + value = binascii.a2b_hex(self.character_data()) + self.element_end('bytes') + return Literal(value) + + def parse_array(self): + self.element_start('array') + elems = [] + while self.token.type != ELEMENT_END: + elems.append(self.parse_elem()) + self.element_end('array') + return Array(elems) + + def parse_elem(self): + self.element_start('elem') + value = self.parse_value() + self.element_end('elem') + return value + + def parse_struct(self): + attrs = self.element_start('struct') + name = attrs['name'] + members = [] + while self.token.type != ELEMENT_END: + members.append(self.parse_member()) + self.element_end('struct') + return Struct(name, members) + + def parse_member(self): + attrs = self.element_start('member') + name = attrs['name'] + value = self.parse_value() + self.element_end('member') + + return name, value + + def parse_ptr(self): + self.element_start('ptr') + address = self.character_data() + self.element_end('ptr') + + return Pointer(address) + + def handle_call(self, call): + pass + + +class TraceDumper(TraceParser): + + def __init__(self, fp): + TraceParser.__init__(self, fp) + self.formatter = format.DefaultFormatter(sys.stdout) + self.pretty_printer = PrettyPrinter(self.formatter) + + def handle_call(self, call): + call.visit(self.pretty_printer) + self.formatter.newline() + + +class Main: + '''Common main class for all retrace command line utilities.''' + + def __init__(self): + pass + + def main(self): + optparser = self.get_optparser() + (options, args) = optparser.parse_args(sys.argv[1:]) + + if args: + for arg in args: + if arg.endswith('.gz'): + from gzip import GzipFile + stream = GzipFile(arg, 'rt') + elif arg.endswith('.bz2'): + from bz2 import BZ2File + stream = BZ2File(arg, 'rU') + else: + stream = open(arg, 'rt') + self.process_arg(stream, options) + else: + self.process_arg(stream, options) + + def get_optparser(self): + optparser = optparse.OptionParser( + usage="\n\t%prog [options] [traces] ...") + return optparser + + def process_arg(self, stream, options): + parser = TraceDumper(stream) + parser.parse() + + +if __name__ == '__main__': + Main().main() diff --git a/src/gallium/state_trackers/python/retrace/parser.py b/src/gallium/state_trackers/python/retrace/parser.py new file mode 100755 index 0000000000..bd47c9a6b0 --- /dev/null +++ b/src/gallium/state_trackers/python/retrace/parser.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +from parse import * + + +if __name__ == '__main__': + Main().main() diff --git a/src/gallium/state_trackers/python/samples/tri.py b/src/gallium/state_trackers/python/samples/tri.py new file mode 100644 index 0000000000..b721e0b575 --- /dev/null +++ b/src/gallium/state_trackers/python/samples/tri.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +from gallium import * + + +def make_image(surface): + data = surface.get_tile_rgba8(0, 0, surface.width, surface.height) + + import Image + outimage = Image.fromstring('RGBA', (surface.width, surface.height), data, "raw", 'RGBA', 0, 1) + return outimage + +def save_image(filename, surface): + outimage = make_image(surface) + outimage.save(filename, "PNG") + +def show_image(surface): + outimage = make_image(surface) + + import Tkinter as tk + from PIL import Image, ImageTk + root = tk.Tk() + + root.title('background image') + + image1 = ImageTk.PhotoImage(outimage) + w = image1.width() + h = image1.height() + x = 100 + y = 100 + root.geometry("%dx%d+%d+%d" % (w, h, x, y)) + panel1 = tk.Label(root, image=image1) + panel1.pack(side='top', fill='both', expand='yes') + panel1.image = image1 + root.mainloop() + + +def test(dev): + ctx = dev.context_create() + + width = 255 + height = 255 + minz = 0.0 + maxz = 1.0 + + # disabled blending/masking + blend = Blend() + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.colormask = PIPE_MASK_RGBA + ctx.set_blend(blend) + + # depth/stencil/alpha + depth_stencil_alpha = DepthStencilAlpha() + depth_stencil_alpha.depth.enabled = 1 + depth_stencil_alpha.depth.writemask = 1 + depth_stencil_alpha.depth.func = PIPE_FUNC_LESS + ctx.set_depth_stencil_alpha(depth_stencil_alpha) + + # rasterizer + rasterizer = Rasterizer() + rasterizer.front_winding = PIPE_WINDING_CW + rasterizer.cull_mode = PIPE_WINDING_NONE + rasterizer.scissor = 1 + ctx.set_rasterizer(rasterizer) + + # viewport + viewport = Viewport() + scale = FloatArray(4) + scale[0] = width / 2.0 + scale[1] = -height / 2.0 + scale[2] = (maxz - minz) / 2.0 + scale[3] = 1.0 + viewport.scale = scale + translate = FloatArray(4) + translate[0] = width / 2.0 + translate[1] = height / 2.0 + translate[2] = (maxz - minz) / 2.0 + translate[3] = 0.0 + viewport.translate = translate + ctx.set_viewport(viewport) + + # samplers + sampler = Sampler() + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE + sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.normalized_coords = 1 + ctx.set_sampler(0, sampler) + + # scissor + scissor = Scissor() + scissor.minx = 0 + scissor.miny = 0 + scissor.maxx = width + scissor.maxy = height + ctx.set_scissor(scissor) + + clip = Clip() + clip.nr = 0 + ctx.set_clip(clip) + + # framebuffer + cbuf = dev.texture_create( + PIPE_FORMAT_X8R8G8B8_UNORM, + width, height, + tex_usage=PIPE_TEXTURE_USAGE_DISPLAY_TARGET, + ).get_surface() + zbuf = dev.texture_create( + PIPE_FORMAT_Z16_UNORM, + width, height, + tex_usage=PIPE_TEXTURE_USAGE_DEPTH_STENCIL, + ).get_surface() + fb = Framebuffer() + fb.width = width + fb.height = height + fb.nr_cbufs = 1 + fb.set_cbuf(0, cbuf) + fb.set_zsbuf(zbuf) + ctx.set_framebuffer(fb) + rgba = FloatArray(4); + rgba[0] = 0.0 + rgba[1] = 0.0 + rgba[2] = 0.0 + rgba[3] = 0.0 + ctx.clear(PIPE_CLEAR_COLOR | PIPE_CLEAR_DEPTHSTENCIL, rgba, 1.0, 0xff) + + # vertex shader + vs = Shader(''' + VERT1.1 + DCL IN[0], POSITION, CONSTANT + DCL IN[1], COLOR, CONSTANT + DCL OUT[0], POSITION, CONSTANT + DCL OUT[1], COLOR, CONSTANT + 0:MOV OUT[0], IN[0] + 1:MOV OUT[1], IN[1] + 2:END + ''') + ctx.set_vertex_shader(vs) + + # fragment shader + fs = Shader(''' + FRAG1.1 + DCL IN[0], COLOR, LINEAR + DCL OUT[0], COLOR, CONSTANT + 0:MOV OUT[0], IN[0] + 1:END + ''') + ctx.set_fragment_shader(fs) + + nverts = 3 + nattrs = 2 + verts = FloatArray(nverts * nattrs * 4) + + verts[ 0] = 0.0 # x1 + verts[ 1] = 0.8 # y1 + verts[ 2] = 0.2 # z1 + verts[ 3] = 1.0 # w1 + verts[ 4] = 1.0 # r1 + verts[ 5] = 0.0 # g1 + verts[ 6] = 0.0 # b1 + verts[ 7] = 1.0 # a1 + verts[ 8] = -0.8 # x2 + verts[ 9] = -0.8 # y2 + verts[10] = 0.5 # z2 + verts[11] = 1.0 # w2 + verts[12] = 0.0 # r2 + verts[13] = 1.0 # g2 + verts[14] = 0.0 # b2 + verts[15] = 1.0 # a2 + verts[16] = 0.8 # x3 + verts[17] = -0.8 # y3 + verts[18] = 0.8 # z3 + verts[19] = 1.0 # w3 + verts[20] = 0.0 # r3 + verts[21] = 0.0 # g3 + verts[22] = 1.0 # b3 + verts[23] = 1.0 # a3 + + ctx.draw_vertices(PIPE_PRIM_TRIANGLES, + nverts, + nattrs, + verts) + + ctx.flush() + + show_image(cbuf) + #show_image(zbuf) + #save_image('cbuf.png', cbuf) + #save_image('zbuf.png', zbuf) + + + +def main(): + dev = Device() + test(dev) + + +if __name__ == '__main__': + main() diff --git a/src/gallium/state_trackers/python/st_device.c b/src/gallium/state_trackers/python/st_device.c new file mode 100644 index 0000000000..ea7d18738f --- /dev/null +++ b/src/gallium/state_trackers/python/st_device.c @@ -0,0 +1,305 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "pipe/p_shader_tokens.h" +#include "pipe/p_inlines.h" +#include "cso_cache/cso_context.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "util/u_simple_shaders.h" +#include "trace/tr_screen.h" +#include "trace/tr_context.h" + +#include "st_device.h" +#include "st_winsys.h" + + +static void +st_device_really_destroy(struct st_device *st_dev) +{ + if(st_dev->screen) { + /* FIXME: Don't really destroy until we keep track of every single + * reference or we end up causing a segmentation fault every time + * python exits. */ +#if 0 + st_dev->screen->destroy(st_dev->screen); +#endif + } + + FREE(st_dev); +} + + +static void +st_device_reference(struct st_device **ptr, struct st_device *st_dev) +{ + struct st_device *old_dev = *ptr; + + if (pipe_reference((struct pipe_reference **)ptr, &st_dev->reference)) + st_device_really_destroy(old_dev); +} + + +void +st_device_destroy(struct st_device *st_dev) +{ + st_device_reference(&st_dev, NULL); +} + + +static struct st_device * +st_device_create_from_st_winsys(const struct st_winsys *st_ws) +{ + struct st_device *st_dev; + + if(!st_ws->screen_create || + !st_ws->context_create) + return NULL; + + st_dev = CALLOC_STRUCT(st_device); + if(!st_dev) + return NULL; + + pipe_reference_init(&st_dev->reference, 1); + st_dev->st_ws = st_ws; + + st_dev->real_screen = st_ws->screen_create(); + if(!st_dev->real_screen) { + st_device_destroy(st_dev); + return NULL; + } + + st_dev->screen = trace_screen_create(st_dev->real_screen); + if(!st_dev->screen) { + st_device_destroy(st_dev); + return NULL; + } + + return st_dev; +} + + +struct st_device * +st_device_create(boolean hardware) { + if(hardware) + return st_device_create_from_st_winsys(&st_hardpipe_winsys); + else + return st_device_create_from_st_winsys(&st_softpipe_winsys); +} + + +void +st_context_destroy(struct st_context *st_ctx) +{ + unsigned i; + + if(st_ctx) { + struct st_device *st_dev = st_ctx->st_dev; + + if(st_ctx->cso) { + cso_delete_vertex_shader(st_ctx->cso, st_ctx->vs); + cso_delete_fragment_shader(st_ctx->cso, st_ctx->fs); + + cso_destroy_context(st_ctx->cso); + } + + if(st_ctx->pipe) + st_ctx->pipe->destroy(st_ctx->pipe); + + for(i = 0; i < PIPE_MAX_SAMPLERS; ++i) + pipe_texture_reference(&st_ctx->sampler_textures[i], NULL); + pipe_texture_reference(&st_ctx->default_texture, NULL); + + FREE(st_ctx); + + st_device_reference(&st_dev, NULL); + } +} + + +struct st_context * +st_context_create(struct st_device *st_dev) +{ + struct st_context *st_ctx; + + st_ctx = CALLOC_STRUCT(st_context); + if(!st_ctx) + return NULL; + + st_device_reference(&st_ctx->st_dev, st_dev); + + st_ctx->real_pipe = st_dev->st_ws->context_create(st_dev->real_screen); + if(!st_ctx->real_pipe) { + st_context_destroy(st_ctx); + return NULL; + } + + st_ctx->pipe = trace_context_create(st_dev->screen, st_ctx->real_pipe); + if(!st_ctx->pipe) { + st_context_destroy(st_ctx); + return NULL; + } + + st_ctx->cso = cso_create_context(st_ctx->pipe); + if(!st_ctx->cso) { + st_context_destroy(st_ctx); + return NULL; + } + + /* disabled blending/masking */ + { + struct pipe_blend_state blend; + memset(&blend, 0, sizeof(blend)); + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.colormask = PIPE_MASK_RGBA; + cso_set_blend(st_ctx->cso, &blend); + } + + /* no-op depth/stencil/alpha */ + { + struct pipe_depth_stencil_alpha_state depthstencil; + memset(&depthstencil, 0, sizeof(depthstencil)); + cso_set_depth_stencil_alpha(st_ctx->cso, &depthstencil); + } + + /* rasterizer */ + { + struct pipe_rasterizer_state rasterizer; + memset(&rasterizer, 0, sizeof(rasterizer)); + rasterizer.front_winding = PIPE_WINDING_CW; + rasterizer.cull_mode = PIPE_WINDING_NONE; + cso_set_rasterizer(st_ctx->cso, &rasterizer); + } + + /* clip */ + { + struct pipe_clip_state clip; + memset(&clip, 0, sizeof(clip)); + st_ctx->pipe->set_clip_state(st_ctx->pipe, &clip); + } + + /* identity viewport */ + { + struct pipe_viewport_state viewport; + viewport.scale[0] = 1.0; + viewport.scale[1] = 1.0; + viewport.scale[2] = 1.0; + viewport.scale[3] = 1.0; + viewport.translate[0] = 0.0; + viewport.translate[1] = 0.0; + viewport.translate[2] = 0.0; + viewport.translate[3] = 0.0; + cso_set_viewport(st_ctx->cso, &viewport); + } + + /* samplers */ + { + struct pipe_sampler_state sampler; + unsigned i; + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; + sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + sampler.normalized_coords = 1; + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) + cso_single_sampler(st_ctx->cso, i, &sampler); + cso_single_sampler_done(st_ctx->cso); + } + + /* default textures */ + { + struct pipe_screen *screen = st_dev->screen; + struct pipe_texture templat; + struct pipe_transfer *transfer; + unsigned i; + + memset( &templat, 0, sizeof( templat ) ); + templat.target = PIPE_TEXTURE_2D; + templat.format = PIPE_FORMAT_A8R8G8B8_UNORM; + templat.block.size = 4; + templat.block.width = 1; + templat.block.height = 1; + templat.width[0] = 1; + templat.height[0] = 1; + templat.depth[0] = 1; + templat.last_level = 0; + + st_ctx->default_texture = screen->texture_create( screen, &templat ); + if(st_ctx->default_texture) { + transfer = screen->get_tex_transfer(screen, + st_ctx->default_texture, + 0, 0, 0, + PIPE_TRANSFER_WRITE, + 0, 0, + st_ctx->default_texture->width[0], + st_ctx->default_texture->height[0]); + if (transfer) { + uint32_t *map; + map = (uint32_t *) screen->transfer_map(screen, transfer); + if(map) { + *map = 0x00000000; + screen->transfer_unmap(screen, transfer); + } + screen->tex_transfer_destroy(transfer); + } + } + + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) + pipe_texture_reference(&st_ctx->sampler_textures[i], st_ctx->default_texture); + + cso_set_sampler_textures(st_ctx->cso, PIPE_MAX_SAMPLERS, st_ctx->sampler_textures); + } + + /* vertex shader */ + { + const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_GENERIC }; + const uint semantic_indexes[] = { 0, 0 }; + st_ctx->vs = util_make_vertex_passthrough_shader(st_ctx->pipe, + 2, + semantic_names, + semantic_indexes); + cso_set_vertex_shader_handle(st_ctx->cso, st_ctx->vs); + } + + /* fragment shader */ + { + st_ctx->fs = util_make_fragment_passthrough_shader(st_ctx->pipe); + cso_set_fragment_shader_handle(st_ctx->cso, st_ctx->fs); + } + + return st_ctx; +} diff --git a/src/gallium/state_trackers/python/st_device.h b/src/gallium/state_trackers/python/st_device.h new file mode 100644 index 0000000000..a246b6a1f2 --- /dev/null +++ b/src/gallium/state_trackers/python/st_device.h @@ -0,0 +1,106 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_DEVICE_H_ +#define ST_DEVICE_H_ + + +#include "pipe/p_state.h" + +struct cso_context; +struct pipe_screen; +struct pipe_context; +struct st_winsys; + + +struct st_surface +{ + struct pipe_texture *texture; + unsigned face; + unsigned level; + unsigned zslice; +}; + + +struct st_context { + struct st_device *st_dev; + + struct pipe_context *real_pipe; + struct pipe_context *pipe; + + struct cso_context *cso; + + void *vs; + void *fs; + + struct pipe_texture *default_texture; + struct pipe_texture *sampler_textures[PIPE_MAX_SAMPLERS]; + + unsigned num_vertex_buffers; + struct pipe_vertex_buffer vertex_buffers[PIPE_MAX_ATTRIBS]; + + unsigned num_vertex_elements; + struct pipe_vertex_element vertex_elements[PIPE_MAX_ATTRIBS]; + + struct pipe_framebuffer_state framebuffer; +}; + + +struct st_device { + /* FIXME: we also need to refcount for textures and surfaces... */ + struct pipe_reference reference; + + const struct st_winsys *st_ws; + + struct pipe_screen *real_screen; + struct pipe_screen *screen; +}; + + +static INLINE struct pipe_surface * +st_pipe_surface(struct st_surface *surface, unsigned usage) +{ + struct pipe_texture *texture = surface->texture; + struct pipe_screen *screen = texture->screen; + return screen->get_tex_surface(screen, texture, surface->face, surface->level, surface->zslice, usage); +} + +struct st_context * +st_context_create(struct st_device *st_dev); + +void +st_context_destroy(struct st_context *st_ctx); + +struct st_device * +st_device_create(boolean hardware); + +void +st_device_destroy(struct st_device *st_dev); + + +#endif /* ST_DEVICE_H_ */ diff --git a/src/gallium/state_trackers/python/st_hardpipe_winsys.c b/src/gallium/state_trackers/python/st_hardpipe_winsys.c new file mode 100644 index 0000000000..43aaaabf2a --- /dev/null +++ b/src/gallium/state_trackers/python/st_hardpipe_winsys.c @@ -0,0 +1,237 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Bismarck, ND., USA + * 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. + * + * + **************************************************************************/ + +/** + * @file + * Get a hardware accelerated Gallium screen/context from the OpenGL driver. + */ + + +#include "pipe/p_compiler.h" + +#ifdef PIPE_OS_WINDOWS +#include <windows.h> +#include <GL/gl.h> +#else +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <GL/gl.h> +#include <GL/glx.h> +#endif + +#include "st_winsys.h" + + +typedef struct pipe_screen * (GLAPIENTRY *PFNGETGALLIUMSCREENMESAPROC) (void); +typedef struct pipe_context * (GLAPIENTRY* PFNCREATEGALLIUMCONTEXTMESAPROC) (void); + +static PFNGETGALLIUMSCREENMESAPROC pfnGetGalliumScreenMESA = NULL; +static PFNCREATEGALLIUMCONTEXTMESAPROC pfnCreateGalliumContextMESA = NULL; + + +/* XXX: Force init_gallium symbol to be linked */ +extern void init_gallium(void); +void (*force_init_gallium_linkage)(void) = &init_gallium; + + +#ifdef PIPE_OS_WINDOWS + +static INLINE boolean +st_hardpipe_load(void) +{ + WNDCLASS wc; + HWND hwnd; + HGLRC hglrc; + HDC hdc; + PIXELFORMATDESCRIPTOR pfd; + int iPixelFormat; + + if(pfnGetGalliumScreenMESA && pfnCreateGalliumContextMESA) + return TRUE; + + memset(&wc, 0, sizeof wc); + wc.lpfnWndProc = DefWindowProc; + wc.lpszClassName = "gallium"; + wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + hwnd = CreateWindow(wc.lpszClassName, "gallium", 0, 0, 0, 0, 0, NULL, 0, wc.hInstance, NULL); + if (!hwnd) + return FALSE; + + hdc = GetDC(hwnd); + if (!hdc) + return FALSE; + + pfd.cColorBits = 3; + pfd.cRedBits = 1; + pfd.cGreenBits = 1; + pfd.cBlueBits = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + pfd.iLayerType = PFD_MAIN_PLANE; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + + iPixelFormat = ChoosePixelFormat(hdc, &pfd); + if (!iPixelFormat) { + pfd.dwFlags |= PFD_DOUBLEBUFFER; + iPixelFormat = ChoosePixelFormat(hdc, &pfd); + } + if (!iPixelFormat) + return FALSE; + + SetPixelFormat(hdc, iPixelFormat, &pfd); + hglrc = wglCreateContext(hdc); + if (!hglrc) + return FALSE; + + if (!wglMakeCurrent(hdc, hglrc)) + return FALSE; + + pfnGetGalliumScreenMESA = (PFNGETGALLIUMSCREENMESAPROC)wglGetProcAddress("wglGetGalliumScreenMESA"); + if(!pfnGetGalliumScreenMESA) + return FALSE; + + pfnCreateGalliumContextMESA = (PFNCREATEGALLIUMCONTEXTMESAPROC)wglGetProcAddress("wglCreateGalliumContextMESA"); + if(!pfnCreateGalliumContextMESA) + return FALSE; + + DestroyWindow(hwnd); + + return TRUE; +} + +#else + +static INLINE boolean +st_hardpipe_load(void) +{ + Display *dpy; + int scrnum; + Window root; + int attribSingle[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + None }; + int attribDouble[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + None }; + XVisualInfo *visinfo; + GLXContext ctx = NULL; + XSetWindowAttributes attr; + unsigned long mask; + int width = 100, height = 100; + Window win; + + dpy = XOpenDisplay(NULL); + if (!dpy) + return FALSE; + + scrnum = 0; + + root = RootWindow(dpy, scrnum); + + visinfo = glXChooseVisual(dpy, scrnum, attribSingle); + if (!visinfo) + visinfo = glXChooseVisual(dpy, scrnum, attribDouble); + if (!visinfo) + return FALSE; + + ctx = glXCreateContext( dpy, visinfo, NULL, True ); + + if (!ctx) + return FALSE; + + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone); + attr.event_mask = StructureNotifyMask | ExposureMask; + + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + win = XCreateWindow(dpy, root, 0, 0, width, height, + 0, visinfo->depth, InputOutput, + visinfo->visual, mask, &attr); + + if (!glXMakeCurrent(dpy, win, ctx)) + return FALSE; + + pfnGetGalliumScreenMESA = (PFNGETGALLIUMSCREENMESAPROC)glXGetProcAddressARB((const GLubyte *)"glXGetGalliumScreenMESA"); + if(!pfnGetGalliumScreenMESA) + return FALSE; + + pfnCreateGalliumContextMESA = (PFNCREATEGALLIUMCONTEXTMESAPROC)glXGetProcAddressARB((const GLubyte *)"glXCreateGalliumContextMESA"); + if(!pfnCreateGalliumContextMESA) + return FALSE; + + glXDestroyContext(dpy, ctx); + XFree(visinfo); + XDestroyWindow(dpy, win); + XCloseDisplay(dpy); + + return TRUE; +} + +#endif + + +static struct pipe_screen * +st_hardpipe_screen_create(void) +{ + if(st_hardpipe_load()) + return pfnGetGalliumScreenMESA(); + else + return st_softpipe_winsys.screen_create(); +} + + +static struct pipe_context * +st_hardpipe_context_create(struct pipe_screen *screen) +{ + if(st_hardpipe_load()) { + if(screen == pfnGetGalliumScreenMESA()) + return pfnCreateGalliumContextMESA(); + else + return NULL; + } + else + return st_softpipe_winsys.context_create(screen); +} + + +const struct st_winsys st_hardpipe_winsys = { + &st_hardpipe_screen_create, + &st_hardpipe_context_create +}; diff --git a/src/gallium/state_trackers/python/st_sample.c b/src/gallium/state_trackers/python/st_sample.c new file mode 100644 index 0000000000..53a01891e1 --- /dev/null +++ b/src/gallium/state_trackers/python/st_sample.c @@ -0,0 +1,570 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "pipe/p_compiler.h" +#include "pipe/p_format.h" +#include "pipe/p_state.h" +#include "pipe/p_inlines.h" +#include "util/u_tile.h" +#include "util/u_math.h" +#include "util/u_memory.h" + +#include "st_device.h" +#include "st_sample.h" + + +/** + * Use our own pseudo random generator to ensure consistent runs among + * multiple runs and platforms. + * + * @sa http://en.wikipedia.org/wiki/Linear_congruential_generator + */ +static uint32_t st_random(void) { + static uint64_t seed = UINT64_C(0xbb9a063afb0a739d); + + seed = UINT64_C(134775813) * seed + UINT64_C(1); + + return (uint16_t)(seed >> 32); +} + + +/** + * We don't want to include the patent-encumbered DXT code here, so instead + * we store several uncompressed/compressed data pairs for hardware testing + * purposes. + */ +struct dxt_data +{ + uint8_t rgba[16*4]; + uint8_t raw[16]; +}; + + +static const struct dxt_data +dxt1_rgb_data[] = { + { + { + 0x99, 0xb0, 0x8e, 0xff, + 0x5d, 0x62, 0x89, 0xff, + 0x99, 0xb0, 0x8e, 0xff, + 0x99, 0xb0, 0x8e, 0xff, + 0xd6, 0xff, 0x94, 0xff, + 0x5d, 0x62, 0x89, 0xff, + 0x99, 0xb0, 0x8e, 0xff, + 0xd6, 0xff, 0x94, 0xff, + 0x5d, 0x62, 0x89, 0xff, + 0x5d, 0x62, 0x89, 0xff, + 0x99, 0xb0, 0x8e, 0xff, + 0x21, 0x14, 0x84, 0xff, + 0x5d, 0x62, 0x89, 0xff, + 0x21, 0x14, 0x84, 0xff, + 0x21, 0x14, 0x84, 0xff, + 0x99, 0xb0, 0x8e, 0xff + }, + {0xf2, 0xd7, 0xb0, 0x20, 0xae, 0x2c, 0x6f, 0x97} + }, + { + { + 0xb5, 0xcf, 0x9c, 0xff, + 0x83, 0x8c, 0x8b, 0xff, + 0x21, 0x08, 0x6b, 0xff, + 0x83, 0x8c, 0x8b, 0xff, + 0x52, 0x4a, 0x7b, 0xff, + 0x83, 0x8c, 0x8b, 0xff, + 0x83, 0x8c, 0x8b, 0xff, + 0xb5, 0xcf, 0x9c, 0xff, + 0x21, 0x08, 0x6b, 0xff, + 0xb5, 0xcf, 0x9c, 0xff, + 0x83, 0x8c, 0x8b, 0xff, + 0x52, 0x4a, 0x7b, 0xff, + 0xb5, 0xcf, 0x9c, 0xff, + 0x83, 0x8c, 0x8b, 0xff, + 0x52, 0x4a, 0x7b, 0xff, + 0x83, 0x8c, 0x8b, 0xff + }, + {0x73, 0xb6, 0x4d, 0x20, 0x98, 0x2b, 0xe1, 0xb8} + }, + { + { + 0x00, 0x2c, 0xff, 0xff, + 0x94, 0x8d, 0x7b, 0xff, + 0x4a, 0x5c, 0xbd, 0xff, + 0x4a, 0x5c, 0xbd, 0xff, + 0x4a, 0x5c, 0xbd, 0xff, + 0x94, 0x8d, 0x7b, 0xff, + 0x94, 0x8d, 0x7b, 0xff, + 0x94, 0x8d, 0x7b, 0xff, + 0xde, 0xbe, 0x39, 0xff, + 0x94, 0x8d, 0x7b, 0xff, + 0xde, 0xbe, 0x39, 0xff, + 0xde, 0xbe, 0x39, 0xff, + 0xde, 0xbe, 0x39, 0xff, + 0xde, 0xbe, 0x39, 0xff, + 0xde, 0xbe, 0x39, 0xff, + 0x94, 0x8d, 0x7b, 0xff + }, + {0xe7, 0xdd, 0x7f, 0x01, 0xf9, 0xab, 0x08, 0x80} + }, + { + { + 0x6b, 0x24, 0x21, 0xff, + 0x7b, 0x4f, 0x5d, 0xff, + 0x7b, 0x4f, 0x5d, 0xff, + 0x8b, 0x7a, 0x99, 0xff, + 0x7b, 0x4f, 0x5d, 0xff, + 0x7b, 0x4f, 0x5d, 0xff, + 0x6b, 0x24, 0x21, 0xff, + 0x8b, 0x7a, 0x99, 0xff, + 0x9c, 0xa6, 0xd6, 0xff, + 0x6b, 0x24, 0x21, 0xff, + 0x7b, 0x4f, 0x5d, 0xff, + 0x8b, 0x7a, 0x99, 0xff, + 0x6b, 0x24, 0x21, 0xff, + 0x8b, 0x7a, 0x99, 0xff, + 0x7b, 0x4f, 0x5d, 0xff, + 0x9c, 0xa6, 0xd6, 0xff + }, + {0x3a, 0x9d, 0x24, 0x69, 0xbd, 0x9f, 0xb4, 0x39} + } +}; + + +static const struct dxt_data +dxt1_rgba_data[] = { + { + { + 0x00, 0x00, 0x00, 0x00, + 0x4e, 0xaa, 0x90, 0xff, + 0x4e, 0xaa, 0x90, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x4e, 0xaa, 0x90, 0xff, + 0x29, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x4e, 0xaa, 0x90, 0xff, + 0x73, 0x55, 0x21, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x4e, 0xaa, 0x90, 0xff, + 0x4e, 0xaa, 0x90, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x4e, 0xaa, 0x90, 0xff + }, + {0xff, 0x2f, 0xa4, 0x72, 0xeb, 0xb2, 0xbd, 0xbe} + }, + { + { + 0xb5, 0xe3, 0x63, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x6b, 0x24, 0x84, 0xff, + 0xb5, 0xe3, 0x63, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0xb5, 0xe3, 0x63, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x6b, 0x24, 0x84, 0xff, + 0x6b, 0x24, 0x84, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0xb5, 0xe3, 0x63, 0xff, + 0x90, 0x83, 0x73, 0xff, + 0xb5, 0xe3, 0x63, 0xff + }, + {0x30, 0x69, 0x0c, 0xb7, 0x4d, 0xf7, 0x0f, 0x67} + }, + { + { + 0x00, 0x00, 0x00, 0x00, + 0xc6, 0x86, 0x8c, 0xff, + 0xc6, 0x86, 0x8c, 0xff, + 0x21, 0x65, 0x42, 0xff, + 0x21, 0x65, 0x42, 0xff, + 0x21, 0x65, 0x42, 0xff, + 0x21, 0x65, 0x42, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x21, 0x65, 0x42, 0xff, + 0xc6, 0x86, 0x8c, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xc6, 0x86, 0x8c, 0xff + }, + {0x28, 0x23, 0x31, 0xc4, 0x17, 0xc0, 0xd3, 0x7f} + }, + { + { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xc6, 0xe3, 0x9c, 0xff, + 0x7b, 0x1c, 0x52, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x7b, 0x1c, 0x52, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0x7b, 0x1c, 0x52, 0xff, + 0xa0, 0x7f, 0x77, 0xff, + 0xc6, 0xe3, 0x9c, 0xff, + 0x00, 0x00, 0x00, 0x00, + 0xa0, 0x7f, 0x77, 0xff + }, + {0xea, 0x78, 0x13, 0xc7, 0x7f, 0xfc, 0x33, 0xb6} + }, +}; + + +static const struct dxt_data +dxt3_rgba_data[] = { + { + { + 0x6d, 0xc6, 0x96, 0x77, + 0x6d, 0xc6, 0x96, 0xee, + 0x6d, 0xc6, 0x96, 0xaa, + 0x8c, 0xff, 0xb5, 0x44, + 0x6d, 0xc6, 0x96, 0xff, + 0x6d, 0xc6, 0x96, 0x88, + 0x31, 0x55, 0x5a, 0x66, + 0x6d, 0xc6, 0x96, 0x99, + 0x31, 0x55, 0x5a, 0xbb, + 0x31, 0x55, 0x5a, 0x55, + 0x31, 0x55, 0x5a, 0x11, + 0x6d, 0xc6, 0x96, 0xcc, + 0x6d, 0xc6, 0x96, 0xcc, + 0x6d, 0xc6, 0x96, 0x11, + 0x31, 0x55, 0x5a, 0x44, + 0x31, 0x55, 0x5a, 0x88 + }, + {0xe7, 0x4a, 0x8f, 0x96, 0x5b, 0xc1, 0x1c, 0x84, 0xf6, 0x8f, 0xab, 0x32, 0x2a, 0x9a, 0x95, 0x5a} + }, + { + { + 0xad, 0xeb, 0x73, 0x99, + 0x97, 0xaa, 0x86, 0x66, + 0x6b, 0x28, 0xad, 0x99, + 0xad, 0xeb, 0x73, 0x99, + 0x6b, 0x28, 0xad, 0x22, + 0xad, 0xeb, 0x73, 0xff, + 0x97, 0xaa, 0x86, 0x55, + 0x6b, 0x28, 0xad, 0x55, + 0x6b, 0x28, 0xad, 0x44, + 0xad, 0xeb, 0x73, 0x33, + 0x6b, 0x28, 0xad, 0xee, + 0x6b, 0x28, 0xad, 0x99, + 0x97, 0xaa, 0x86, 0x66, + 0xad, 0xeb, 0x73, 0xbb, + 0x97, 0xaa, 0x86, 0x99, + 0xad, 0xeb, 0x73, 0xbb + }, + {0x69, 0x99, 0xf2, 0x55, 0x34, 0x9e, 0xb6, 0xb9, 0x4e, 0xaf, 0x55, 0x69, 0x18, 0x61, 0x51, 0x22} + }, + { + { + 0x63, 0xd7, 0xd6, 0x00, + 0x57, 0x62, 0x5d, 0xdd, + 0x57, 0x62, 0x5d, 0xcc, + 0x57, 0x62, 0x5d, 0xbb, + 0x52, 0x28, 0x21, 0xaa, + 0x57, 0x62, 0x5d, 0xcc, + 0x57, 0x62, 0x5d, 0xcc, + 0x57, 0x62, 0x5d, 0x66, + 0x57, 0x62, 0x5d, 0x22, + 0x57, 0x62, 0x5d, 0xdd, + 0x63, 0xd7, 0xd6, 0xee, + 0x57, 0x62, 0x5d, 0x33, + 0x63, 0xd7, 0xd6, 0x55, + 0x52, 0x28, 0x21, 0x55, + 0x57, 0x62, 0x5d, 0x11, + 0x5d, 0x9c, 0x99, 0xee + }, + {0xd0, 0xbc, 0xca, 0x6c, 0xd2, 0x3e, 0x55, 0xe1, 0xba, 0x66, 0x44, 0x51, 0xfc, 0xfd, 0xcf, 0xb4} + }, + { + { + 0x94, 0x6f, 0x60, 0x22, + 0x94, 0x6f, 0x60, 0x22, + 0xc5, 0xab, 0x76, 0x11, + 0xc5, 0xab, 0x76, 0xee, + 0x63, 0x34, 0x4a, 0xdd, + 0x63, 0x34, 0x4a, 0x33, + 0x94, 0x6f, 0x60, 0x77, + 0xf7, 0xe7, 0x8c, 0x00, + 0x94, 0x6f, 0x60, 0x33, + 0x63, 0x34, 0x4a, 0xaa, + 0x94, 0x6f, 0x60, 0x77, + 0x63, 0x34, 0x4a, 0xcc, + 0x94, 0x6f, 0x60, 0xaa, + 0xf7, 0xe7, 0x8c, 0x99, + 0x63, 0x34, 0x4a, 0x44, + 0xc5, 0xab, 0x76, 0xaa + }, + {0x22, 0xe1, 0x3d, 0x07, 0xa3, 0xc7, 0x9a, 0xa4, 0x31, 0xf7, 0xa9, 0x61, 0xaf, 0x35, 0x77, 0x93} + }, +}; + + +static const struct dxt_data +dxt5_rgba_data[] = { + { + { + 0x6d, 0xc6, 0x96, 0x74, + 0x6d, 0xc6, 0x96, 0xf8, + 0x6d, 0xc6, 0x96, 0xb6, + 0x8c, 0xff, 0xb5, 0x53, + 0x6d, 0xc6, 0x96, 0xf8, + 0x6d, 0xc6, 0x96, 0x95, + 0x31, 0x55, 0x5a, 0x53, + 0x6d, 0xc6, 0x96, 0x95, + 0x31, 0x55, 0x5a, 0xb6, + 0x31, 0x55, 0x5a, 0x53, + 0x31, 0x55, 0x5a, 0x11, + 0x6d, 0xc6, 0x96, 0xd7, + 0x6d, 0xc6, 0x96, 0xb6, + 0x6d, 0xc6, 0x96, 0x11, + 0x31, 0x55, 0x5a, 0x32, + 0x31, 0x55, 0x5a, 0x95 + }, + {0xf8, 0x11, 0xc5, 0x0c, 0x9a, 0x73, 0xb4, 0x9c, 0xf6, 0x8f, 0xab, 0x32, 0x2a, 0x9a, 0x95, 0x5a} + }, + { + { + 0xad, 0xeb, 0x73, 0xa1, + 0x97, 0xaa, 0x86, 0x65, + 0x6b, 0x28, 0xad, 0xa1, + 0xad, 0xeb, 0x73, 0xa1, + 0x6b, 0x28, 0xad, 0x2a, + 0xad, 0xeb, 0x73, 0xfb, + 0x97, 0xaa, 0x86, 0x47, + 0x6b, 0x28, 0xad, 0x65, + 0x6b, 0x28, 0xad, 0x47, + 0xad, 0xeb, 0x73, 0x47, + 0x6b, 0x28, 0xad, 0xdd, + 0x6b, 0x28, 0xad, 0xa1, + 0x97, 0xaa, 0x86, 0x65, + 0xad, 0xeb, 0x73, 0xbf, + 0x97, 0xaa, 0x86, 0xa1, + 0xad, 0xeb, 0x73, 0xbf + }, + {0xfb, 0x2a, 0x34, 0x19, 0xdc, 0xbf, 0xe8, 0x71, 0x4e, 0xaf, 0x55, 0x69, 0x18, 0x61, 0x51, 0x22} + }, + { + { + 0x63, 0xd7, 0xd6, 0x00, + 0x57, 0x62, 0x5d, 0xf5, + 0x57, 0x62, 0x5d, 0xd2, + 0x57, 0x62, 0x5d, 0xaf, + 0x52, 0x28, 0x21, 0xaf, + 0x57, 0x62, 0x5d, 0xd2, + 0x57, 0x62, 0x5d, 0xd2, + 0x57, 0x62, 0x5d, 0x69, + 0x57, 0x62, 0x5d, 0x23, + 0x57, 0x62, 0x5d, 0xd2, + 0x63, 0xd7, 0xd6, 0xf5, + 0x57, 0x62, 0x5d, 0x46, + 0x63, 0xd7, 0xd6, 0x46, + 0x52, 0x28, 0x21, 0x69, + 0x57, 0x62, 0x5d, 0x23, + 0x5d, 0x9c, 0x99, 0xf5 + }, + {0xf5, 0x00, 0x81, 0x36, 0xa9, 0x17, 0xec, 0x1e, 0xba, 0x66, 0x44, 0x51, 0xfc, 0xfd, 0xcf, 0xb4} + }, + { + { + 0x94, 0x6f, 0x60, 0x25, + 0x94, 0x6f, 0x60, 0x25, + 0xc5, 0xab, 0x76, 0x05, + 0xc5, 0xab, 0x76, 0xe8, + 0x63, 0x34, 0x4a, 0xe8, + 0x63, 0x34, 0x4a, 0x25, + 0x94, 0x6f, 0x60, 0x86, + 0xf7, 0xe7, 0x8c, 0x05, + 0x94, 0x6f, 0x60, 0x25, + 0x63, 0x34, 0x4a, 0xa7, + 0x94, 0x6f, 0x60, 0x66, + 0x63, 0x34, 0x4a, 0xc7, + 0x94, 0x6f, 0x60, 0xa7, + 0xf7, 0xe7, 0x8c, 0xa7, + 0x63, 0x34, 0x4a, 0x45, + 0xc5, 0xab, 0x76, 0xa7 + }, + {0xe8, 0x05, 0x7f, 0x80, 0x33, 0x5f, 0xb5, 0x79, 0x31, 0xf7, 0xa9, 0x61, 0xaf, 0x35, 0x77, 0x93} + }, +}; + + +static INLINE void +st_sample_dxt_pixel_block(enum pipe_format format, + const struct pipe_format_block *block, + uint8_t *raw, + float *rgba, unsigned rgba_stride, + unsigned w, unsigned h) +{ + const struct dxt_data *data; + unsigned n; + unsigned i; + unsigned x, y, ch; + + switch(format) { + case PIPE_FORMAT_DXT1_RGB: + data = dxt1_rgb_data; + n = sizeof(dxt1_rgb_data)/sizeof(dxt1_rgb_data[0]); + break; + case PIPE_FORMAT_DXT1_RGBA: + data = dxt1_rgba_data; + n = sizeof(dxt1_rgba_data)/sizeof(dxt1_rgba_data[0]); + break; + case PIPE_FORMAT_DXT3_RGBA: + data = dxt3_rgba_data; + n = sizeof(dxt3_rgba_data)/sizeof(dxt3_rgba_data[0]); + break; + case PIPE_FORMAT_DXT5_RGBA: + data = dxt5_rgba_data; + n = sizeof(dxt5_rgba_data)/sizeof(dxt5_rgba_data[0]); + break; + default: + assert(0); + return; + } + + i = st_random() % n; + + for(y = 0; y < h; ++y) + for(x = 0; x < w; ++x) + for(ch = 0; ch < 4; ++ch) + rgba[y*rgba_stride + x*4 + ch] = (float)(data[i].rgba[y*4*4 + x*4 + ch])/255.0f; + + memcpy(raw, data[i].raw, block->size); +} + + +static INLINE void +st_sample_generic_pixel_block(enum pipe_format format, + const struct pipe_format_block *block, + uint8_t *raw, + float *rgba, unsigned rgba_stride, + unsigned w, unsigned h) +{ + unsigned i; + unsigned x, y, ch; + + for(i = 0; i < block->size; ++i) + raw[i] = (uint8_t)st_random(); + + + pipe_tile_raw_to_rgba(format, + raw, + w, h, + rgba, rgba_stride); + + if(format == PIPE_FORMAT_YCBCR || format == PIPE_FORMAT_YCBCR_REV) { + for(y = 0; y < h; ++y) { + for(x = 0; x < w; ++x) { + for(ch = 0; ch < 4; ++ch) { + unsigned offset = y*rgba_stride + x*4 + ch; + rgba[offset] = CLAMP(rgba[offset], 0.0f, 1.0f); + } + } + } + } +} + + +/** + * Randomly sample pixels. + */ +void +st_sample_pixel_block(enum pipe_format format, + const struct pipe_format_block *block, + void *raw, + float *rgba, unsigned rgba_stride, + unsigned w, unsigned h) +{ + switch(format) { + case PIPE_FORMAT_DXT1_RGB: + case PIPE_FORMAT_DXT1_RGBA: + case PIPE_FORMAT_DXT3_RGBA: + case PIPE_FORMAT_DXT5_RGBA: + st_sample_dxt_pixel_block(format, block, raw, rgba, rgba_stride, w, h); + break; + + default: + st_sample_generic_pixel_block(format, block, raw, rgba, rgba_stride, w, h); + break; + } +} + + +void +st_sample_surface(struct st_surface *surface, float *rgba) +{ + struct pipe_texture *texture = surface->texture; + struct pipe_screen *screen = texture->screen; + unsigned width = texture->width[surface->level]; + unsigned height = texture->height[surface->level]; + uint rgba_stride = width * 4; + struct pipe_transfer *transfer; + void *raw; + + transfer = screen->get_tex_transfer(screen, + surface->texture, + surface->face, + surface->level, + surface->zslice, + PIPE_TRANSFER_WRITE, + 0, 0, + width, + height); + if (!transfer) + return; + + raw = screen->transfer_map(screen, transfer); + if (raw) { + const struct pipe_format_block *block = &texture->block; + uint x, y; + + for (y = 0; y < transfer->nblocksy; ++y) { + for (x = 0; x < transfer->nblocksx; ++x) { + st_sample_pixel_block(texture->format, + block, + (uint8_t *) raw + y * transfer->stride + x * block->size, + rgba + y * block->height * rgba_stride + x * block->width * 4, + rgba_stride, + MIN2(block->width, width - x*block->width), + MIN2(block->height, height - y*block->height)); + } + } + + screen->transfer_unmap(screen, transfer); + } + + screen->tex_transfer_destroy(transfer); +} diff --git a/src/gallium/state_trackers/python/st_sample.h b/src/gallium/state_trackers/python/st_sample.h new file mode 100644 index 0000000000..0a27083549 --- /dev/null +++ b/src/gallium/state_trackers/python/st_sample.h @@ -0,0 +1,47 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_SAMPLE_H_ +#define ST_SAMPLE_H_ + + +#include "pipe/p_format.h" + + +void +st_sample_pixel_block(enum pipe_format format, + const struct pipe_format_block *block, + void *raw, + float *rgba, unsigned rgba_stride, + unsigned w, unsigned h); + +void +st_sample_surface(struct st_surface *surface, float *rgba); + + +#endif /* ST_SAMPLE_H_ */ diff --git a/src/gallium/state_trackers/python/st_softpipe_winsys.c b/src/gallium/state_trackers/python/st_softpipe_winsys.c new file mode 100644 index 0000000000..f0a4826a00 --- /dev/null +++ b/src/gallium/state_trackers/python/st_softpipe_winsys.c @@ -0,0 +1,270 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Bismarck, ND., USA + * 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. + * + * + **************************************************************************/ + +/** + * @file + * Softpipe support. + * + * @author Keith Whitwell + * @author Brian Paul + * @author Jose Fonseca + */ + + +#include "pipe/internal/p_winsys_screen.h"/* port to just p_screen */ +#include "pipe/p_format.h" +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "util/u_math.h" +#include "util/u_memory.h" +#include "softpipe/sp_winsys.h" +#include "st_winsys.h" + + +struct st_softpipe_buffer +{ + struct pipe_buffer base; + boolean userBuffer; /** Is this a user-space buffer? */ + void *data; + void *mapped; +}; + + +/** Cast wrapper */ +static INLINE struct st_softpipe_buffer * +st_softpipe_buffer( struct pipe_buffer *buf ) +{ + return (struct st_softpipe_buffer *)buf; +} + + +static void * +st_softpipe_buffer_map(struct pipe_winsys *winsys, + struct pipe_buffer *buf, + unsigned flags) +{ + struct st_softpipe_buffer *st_softpipe_buf = st_softpipe_buffer(buf); + st_softpipe_buf->mapped = st_softpipe_buf->data; + return st_softpipe_buf->mapped; +} + + +static void +st_softpipe_buffer_unmap(struct pipe_winsys *winsys, + struct pipe_buffer *buf) +{ + struct st_softpipe_buffer *st_softpipe_buf = st_softpipe_buffer(buf); + st_softpipe_buf->mapped = NULL; +} + + +static void +st_softpipe_buffer_destroy(struct pipe_buffer *buf) +{ + struct st_softpipe_buffer *oldBuf = st_softpipe_buffer(buf); + + if (oldBuf->data) { + if (!oldBuf->userBuffer) + align_free(oldBuf->data); + + oldBuf->data = NULL; + } + + FREE(oldBuf); +} + + +static void +st_softpipe_flush_frontbuffer(struct pipe_winsys *winsys, + struct pipe_surface *surf, + void *context_private) +{ +} + + + +static const char * +st_softpipe_get_name(struct pipe_winsys *winsys) +{ + return "softpipe"; +} + + +static struct pipe_buffer * +st_softpipe_buffer_create(struct pipe_winsys *winsys, + unsigned alignment, + unsigned usage, + unsigned size) +{ + struct st_softpipe_buffer *buffer = CALLOC_STRUCT(st_softpipe_buffer); + + pipe_reference_init(&buffer->base.reference, 1); + buffer->base.alignment = alignment; + buffer->base.usage = usage; + buffer->base.size = size; + + buffer->data = align_malloc(size, alignment); + + return &buffer->base; +} + + +/** + * Create buffer which wraps user-space data. + */ +static struct pipe_buffer * +st_softpipe_user_buffer_create(struct pipe_winsys *winsys, + void *ptr, + unsigned bytes) +{ + struct st_softpipe_buffer *buffer; + + buffer = CALLOC_STRUCT(st_softpipe_buffer); + if(!buffer) + return NULL; + + pipe_reference_init(&buffer->base.reference, 1); + buffer->base.size = bytes; + buffer->userBuffer = TRUE; + buffer->data = ptr; + + return &buffer->base; +} + + +/** + * Round n up to next multiple. + */ +static INLINE unsigned +round_up(unsigned n, unsigned multiple) +{ + return (n + multiple - 1) & ~(multiple - 1); +} + + +static struct pipe_buffer * +st_softpipe_surface_buffer_create(struct pipe_winsys *winsys, + unsigned width, unsigned height, + enum pipe_format format, + unsigned usage, + unsigned *stride) +{ + const unsigned alignment = 64; + struct pipe_format_block block; + unsigned nblocksx, nblocksy; + + pf_get_block(format, &block); + nblocksx = pf_get_nblocksx(&block, width); + nblocksy = pf_get_nblocksy(&block, height); + *stride = round_up(nblocksx * block.size, alignment); + + return winsys->buffer_create(winsys, alignment, + usage, + *stride * nblocksy); +} + + +static void +st_softpipe_fence_reference(struct pipe_winsys *winsys, + struct pipe_fence_handle **ptr, + struct pipe_fence_handle *fence) +{ +} + + +static int +st_softpipe_fence_signalled(struct pipe_winsys *winsys, + struct pipe_fence_handle *fence, + unsigned flag) +{ + return 0; +} + + +static int +st_softpipe_fence_finish(struct pipe_winsys *winsys, + struct pipe_fence_handle *fence, + unsigned flag) +{ + return 0; +} + + +static void +st_softpipe_destroy(struct pipe_winsys *winsys) +{ + FREE(winsys); +} + + +static struct pipe_screen * +st_softpipe_screen_create(void) +{ + static struct pipe_winsys *winsys; + struct pipe_screen *screen; + + winsys = CALLOC_STRUCT(pipe_winsys); + if(!winsys) + return NULL; + + winsys->destroy = st_softpipe_destroy; + + winsys->buffer_create = st_softpipe_buffer_create; + winsys->user_buffer_create = st_softpipe_user_buffer_create; + winsys->buffer_map = st_softpipe_buffer_map; + winsys->buffer_unmap = st_softpipe_buffer_unmap; + winsys->buffer_destroy = st_softpipe_buffer_destroy; + + winsys->surface_buffer_create = st_softpipe_surface_buffer_create; + + winsys->fence_reference = st_softpipe_fence_reference; + winsys->fence_signalled = st_softpipe_fence_signalled; + winsys->fence_finish = st_softpipe_fence_finish; + + winsys->flush_frontbuffer = st_softpipe_flush_frontbuffer; + winsys->get_name = st_softpipe_get_name; + + screen = softpipe_create_screen(winsys); + if(!screen) + st_softpipe_destroy(winsys); + + return screen; +} + + +static struct pipe_context * +st_softpipe_context_create(struct pipe_screen *screen) +{ + return softpipe_create(screen); +} + + +const struct st_winsys st_softpipe_winsys = { + &st_softpipe_screen_create, + &st_softpipe_context_create, +}; diff --git a/src/gallium/state_trackers/python/st_winsys.h b/src/gallium/state_trackers/python/st_winsys.h new file mode 100644 index 0000000000..b8cb612d86 --- /dev/null +++ b/src/gallium/state_trackers/python/st_winsys.h @@ -0,0 +1,52 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef ST_WINSYS_H_ +#define ST_WINSYS_H_ + + +struct pipe_screen; +struct pipe_context; + + +struct st_winsys +{ + struct pipe_screen * + (*screen_create)(void); + + struct pipe_context * + (*context_create)(struct pipe_screen *screen); +}; + + +extern const struct st_winsys st_softpipe_winsys; + +extern const struct st_winsys st_hardpipe_winsys; + + +#endif /* ST_WINSYS_H_ */ diff --git a/src/gallium/state_trackers/python/tests/.gitignore b/src/gallium/state_trackers/python/tests/.gitignore new file mode 100644 index 0000000000..0dbbaeea16 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/.gitignore @@ -0,0 +1,3 @@ +*.txt +*.tsv +*.dot diff --git a/src/gallium/state_trackers/python/tests/base.py b/src/gallium/state_trackers/python/tests/base.py new file mode 100755 index 0000000000..202ccfc350 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/base.py @@ -0,0 +1,344 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2009 VMware, Inc. +# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +"""Base classes for tests. + +Loosely inspired on Python's unittest module. +""" + + +import os.path +import sys + +from gallium import * + + +# Enumerate all pixel formats +formats = {} +for name, value in globals().items(): + if name.startswith("PIPE_FORMAT_") and isinstance(value, int): + formats[value] = name + +def is_depth_stencil_format(format): + # FIXME: make and use binding to pf_is_depth_stencil + return format in ( + PIPE_FORMAT_Z32_UNORM, + PIPE_FORMAT_Z24S8_UNORM, + PIPE_FORMAT_Z24X8_UNORM, + PIPE_FORMAT_Z16_UNORM, + ) + +def make_image(width, height, rgba): + import Image + outimage = Image.new( + mode='RGB', + size=(width, height), + color=(0,0,0)) + outpixels = outimage.load() + for y in range(0, height): + for x in range(0, width): + offset = (y*width + x)*4 + r, g, b, a = [int(min(max(rgba[offset + ch], 0.0), 1.0)*255) for ch in range(4)] + outpixels[x, y] = r, g, b + return outimage + +def save_image(width, height, rgba, filename): + outimage = make_image(width, height, rgba) + outimage.save(filename, "PNG") + +def show_image(width, height, **rgbas): + import Tkinter as tk + from PIL import Image, ImageTk + + root = tk.Tk() + + x = 64 + y = 64 + + labels = rgbas.keys() + labels.sort() + for i in range(len(labels)): + label = labels[i] + outimage = make_image(width, height, rgbas[label]) + + if i: + window = tk.Toplevel(root) + else: + window = root + window.title(label) + image1 = ImageTk.PhotoImage(outimage) + w = image1.width() + h = image1.height() + window.geometry("%dx%d+%d+%d" % (w, h, x, y)) + panel1 = tk.Label(window, image=image1) + panel1.pack(side='top', fill='both', expand='yes') + panel1.image = image1 + x += w + 2 + + root.mainloop() + + +class TestFailure(Exception): + + pass + +class TestSkip(Exception): + + pass + + +class Test: + + def __init__(self): + pass + + def _run(self, result): + raise NotImplementedError + + def run(self): + result = TestResult() + self._run(result) + result.summary() + + def assert_rgba(self, surface, x, y, w, h, expected_rgba, pixel_tol=4.0/256, surface_tol=0.85): + total = h*w + different = surface.compare_tile_rgba(x, y, w, h, expected_rgba, tol=pixel_tol) + if different: + sys.stderr.write("%u out of %u pixels differ\n" % (different, total)) + + if float(total - different)/float(total) < surface_tol: + if 0: + rgba = FloatArray(h*w*4) + surface.get_tile_rgba(x, y, w, h, rgba) + show_image(w, h, Result=rgba, Expected=expected_rgba) + save_image(w, h, rgba, "result.png") + save_image(w, h, expected_rgba, "expected.png") + #sys.exit(0) + + raise TestFailure + + +class TestCase(Test): + + tags = () + + def __init__(self, dev, **kargs): + Test.__init__(self) + self.dev = dev + self.__dict__.update(kargs) + + def description(self): + descriptions = [] + for tag in self.tags: + value = self.get(tag) + if value is not None and value != '': + descriptions.append(tag + '=' + str(value)) + return ' '.join(descriptions) + + def get(self, tag): + try: + method = getattr(self, '_get_' + tag) + except AttributeError: + return getattr(self, tag, None) + else: + return method() + + def _get_target(self): + return { + PIPE_TEXTURE_1D: "1d", + PIPE_TEXTURE_2D: "2d", + PIPE_TEXTURE_3D: "3d", + PIPE_TEXTURE_CUBE: "cube", + }[self.target] + + def _get_format(self): + name = formats[self.format] + if name.startswith('PIPE_FORMAT_'): + name = name[12:] + name = name.lower() + return name + + def _get_face(self): + if self.target == PIPE_TEXTURE_CUBE: + return { + PIPE_TEX_FACE_POS_X: "+x", + PIPE_TEX_FACE_NEG_X: "-x", + PIPE_TEX_FACE_POS_Y: "+y", + PIPE_TEX_FACE_NEG_Y: "-y", + PIPE_TEX_FACE_POS_Z: "+z", + PIPE_TEX_FACE_NEG_Z: "-z", + }[self.face] + else: + return '' + + def test(self): + raise NotImplementedError + + def _run(self, result): + result.test_start(self) + try: + self.test() + except KeyboardInterrupt: + raise + except TestSkip: + result.test_skipped(self) + except TestFailure: + result.test_failed(self) + else: + result.test_passed(self) + + +class TestSuite(Test): + + def __init__(self, tests = None): + Test.__init__(self) + if tests is None: + self.tests = [] + else: + self.tests = tests + + def add_test(self, test): + self.tests.append(test) + + def _run(self, result): + for test in self.tests: + test._run(result) + + +class TestResult: + + def __init__(self): + self.tests = 0 + self.passed = 0 + self.skipped = 0 + self.failed = 0 + + self.names = ['result'] + self.types = ['pass skip fail'] + self.rows = [] + + def test_start(self, test): + sys.stdout.write("Running %s...\n" % test.description()) + sys.stdout.flush() + self.tests += 1 + + def test_passed(self, test): + sys.stdout.write("PASS\n") + sys.stdout.flush() + self.passed += 1 + self.log_result(test, 'pass') + + def test_skipped(self, test): + sys.stdout.write("SKIP\n") + sys.stdout.flush() + self.skipped += 1 + #self.log_result(test, 'skip') + + def test_failed(self, test): + sys.stdout.write("FAIL\n") + sys.stdout.flush() + self.failed += 1 + self.log_result(test, 'fail') + + def log_result(self, test, result): + row = ['']*len(self.names) + + # add result + assert self.names[0] == 'result' + assert result in ('pass', 'skip', 'fail') + row[0] = result + + # add tags + for tag in test.tags: + value = test.get(tag) + + # infer type + if value is None: + continue + elif isinstance(value, (int, float)): + value = str(value) + type = 'c' # continous + elif isinstance(value, basestring): + type = 'd' # discrete + else: + assert False + value = str(value) + type = 'd' # discrete + + # insert value + try: + col = self.names.index(tag, 1) + except ValueError: + self.names.append(tag) + self.types.append(type) + row.append(value) + else: + row[col] = value + assert self.types[col] == type + + self.rows.append(row) + + def summary(self): + sys.stdout.write("%u tests, %u passed, %u skipped, %u failed\n\n" % (self.tests, self.passed, self.skipped, self.failed)) + sys.stdout.flush() + + name, ext = os.path.splitext(os.path.basename(sys.argv[0])) + filename = name + '.tsv' + stream = file(filename, 'wt') + + # header + stream.write('\t'.join(self.names) + '\n') + stream.write('\t'.join(self.types) + '\n') + stream.write('class\n') + + # rows + for row in self.rows: + row += ['']*(len(self.names) - len(row)) + stream.write('\t'.join(row) + '\n') + + stream.close() + + # See http://www.ailab.si/orange/doc/ofb/c_otherclass.htm + try: + import orange + import orngTree + except ImportError: + sys.stderr.write('Install Orange from http://www.ailab.si/orange/ for a classification tree.\n') + return + + data = orange.ExampleTable(filename) + + tree = orngTree.TreeLearner(data, sameMajorityPruning=1, mForPruning=2) + + orngTree.printTxt(tree, maxDepth=4) + + file(name+'.txt', 'wt').write(orngTree.dumpTree(tree)) + + orngTree.printDot(tree, fileName=name+'.dot', nodeShape='ellipse', leafShape='box') diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-abs.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-abs.sh new file mode 100644 index 0000000000..7a0006bf66 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-abs.sh @@ -0,0 +1,13 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +IMM FLT32 { -0.5, -0.4, -0.6, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +ABS OUT[0], TEMP[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-add.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-add.sh new file mode 100644 index 0000000000..f7836c85dd --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-add.sh @@ -0,0 +1,8 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +ADD OUT[0], IN[0], IN[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-dp3.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-dp3.sh new file mode 100644 index 0000000000..c89cd748a8 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-dp3.sh @@ -0,0 +1,8 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DP3 OUT[0], IN[0], IN[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-dp4.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-dp4.sh new file mode 100644 index 0000000000..6517e3c494 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-dp4.sh @@ -0,0 +1,8 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DP4 OUT[0], IN[0].xyzx, IN[0].xyzx + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-dst.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-dst.sh new file mode 100644 index 0000000000..464880ba68 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-dst.sh @@ -0,0 +1,8 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DST OUT[0], IN[0], IN[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-ex2.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-ex2.sh new file mode 100644 index 0000000000..2684076f1d --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-ex2.sh @@ -0,0 +1,11 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +EX2 TEMP[0], IN[0].xxxx +MUL OUT[0], TEMP[0], IN[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-flr.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-flr.sh new file mode 100644 index 0000000000..ad11e28918 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-flr.sh @@ -0,0 +1,15 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +IMM FLT32 { 2.5, 4.0, 2.0, 1.0 } +IMM FLT32 { 0.4, 0.25, 0.5, 1.0 } + +MUL TEMP[0], IN[0], IMM[0] +FLR TEMP[0], TEMP[0] +MUL OUT[0], TEMP[0], IMM[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-frc.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-frc.sh new file mode 100644 index 0000000000..4f3aa30d66 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-frc.sh @@ -0,0 +1,13 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +IMM FLT32 { 2.7, 3.1, 4.5, 1.0 } + +MUL TEMP[0], IN[0], IMM[0] +FRC OUT[0], TEMP[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-lg2.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-lg2.sh new file mode 100644 index 0000000000..54c7c64459 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-lg2.sh @@ -0,0 +1,15 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +IMM FLT32 { 1.0, 0.0, 0.0, 0.0 } +IMM FLT32 { 0.5, 0.0, 0.0, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +LG2 TEMP[0].x, TEMP[0].xxxx +ADD OUT[0], TEMP[0], IMM[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-lit.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-lit.sh new file mode 100644 index 0000000000..0e78ef86b5 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-lit.sh @@ -0,0 +1,8 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +LIT OUT[0], IN[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-lrp.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-lrp.sh new file mode 100644 index 0000000000..e9ee0f8147 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-lrp.sh @@ -0,0 +1,11 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +ABS TEMP[0], IN[0] +LRP OUT[0], TEMP[0], IN[0].xxxx, IN[0].yyyy + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-mad.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-mad.sh new file mode 100644 index 0000000000..439acd5bbd --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-mad.sh @@ -0,0 +1,11 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +IMM FLT32 { 0.5, 0.4, 0.6, 1.0 } +IMM FLT32 { 0.5, 0.4, 0.6, 0.0 } + +MAD OUT[0], IN[0], IMM[0], IMM[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-max.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-max.sh new file mode 100644 index 0000000000..ab21b245dd --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-max.sh @@ -0,0 +1,10 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +IMM FLT32 { 0.4, 0.4, 0.4, 0.0 } + +MAX OUT[0], IN[0], IMM[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-min.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-min.sh new file mode 100644 index 0000000000..969ae73d98 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-min.sh @@ -0,0 +1,10 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +IMM FLT32 { 0.6, 0.6, 0.6, 1.0 } + +MIN OUT[0], IN[0], IMM[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-mov.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-mov.sh new file mode 100644 index 0000000000..612975e057 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-mov.sh @@ -0,0 +1,8 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +MOV OUT[0], IN[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-mul.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-mul.sh new file mode 100644 index 0000000000..ed158b0fc6 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-mul.sh @@ -0,0 +1,10 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +IMM FLT32 { 0.5, 0.6, 0.7, 1.0 } + +MUL OUT[0], IN[0], IMM[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-rcp.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-rcp.sh new file mode 100644 index 0000000000..cc9feef07e --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-rcp.sh @@ -0,0 +1,15 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +IMM FLT32 { 1.0, 0.0, 0.0, 0.0 } +IMM FLT32 { 1.5, 0.0, 0.0, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +RCP TEMP[0].x, TEMP[0].xxxx +SUB OUT[0], TEMP[0], IMM[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-rsq.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-rsq.sh new file mode 100644 index 0000000000..695621fdc9 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-rsq.sh @@ -0,0 +1,15 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +IMM FLT32 { 1.0, 0.0, 0.0, 0.0 } +IMM FLT32 { 1.5, 0.0, 0.0, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +RSQ TEMP[0].x, TEMP[0].xxxx +SUB OUT[0], TEMP[0], IMM[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-sge.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-sge.sh new file mode 100644 index 0000000000..9505bc3c3e --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-sge.sh @@ -0,0 +1,13 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +IMM FLT32 { 0.6, 0.6, 0.6, 0.0 } + +SGE TEMP[0], IN[0], IMM[0] +MUL OUT[0], IN[0], TEMP[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-slt.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-slt.sh new file mode 100644 index 0000000000..f2a1521cbf --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-slt.sh @@ -0,0 +1,13 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +IMM FLT32 { 0.6, 0.6, 0.6, 0.0 } + +SLT TEMP[0], IN[0], IMM[0] +MUL OUT[0], IN[0], TEMP[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-abs.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-abs.sh new file mode 100644 index 0000000000..9cd4b68295 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-abs.sh @@ -0,0 +1,13 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +IMM FLT32 { -0.3, -0.5, -0.4, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +MOV OUT[0], |TEMP[0]| + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-absneg.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-absneg.sh new file mode 100644 index 0000000000..acd6aa750d --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-absneg.sh @@ -0,0 +1,15 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +IMM FLT32 { -0.2, -0.3, -0.4, 0.0 } +IMM FLT32 { -1.0, -1.0, -1.0, -1.0 } + +ADD TEMP[0], IN[0], IMM[0] +MOV TEMP[0], -|TEMP[0]| +MUL OUT[0], TEMP[0], IMM[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-neg.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-neg.sh new file mode 100644 index 0000000000..ba1b61503b --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-neg.sh @@ -0,0 +1,11 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +DCL TEMP[0] + +SUB TEMP[0], IN[0], IN[0].yzxw +MOV OUT[0], -TEMP[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-swz.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-swz.sh new file mode 100644 index 0000000000..192aa7bb26 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-srcmod-swz.sh @@ -0,0 +1,8 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +MOV OUT[0], IN[0].yxzw + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-sub.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-sub.sh new file mode 100644 index 0000000000..83441fa820 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-sub.sh @@ -0,0 +1,8 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +SUB OUT[0], IN[0], IN[0].yzxw + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-xpd.sh b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-xpd.sh new file mode 100644 index 0000000000..d6f66c4927 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/frag-xpd.sh @@ -0,0 +1,8 @@ +FRAG1.1 + +DCL IN[0], COLOR, LINEAR +DCL OUT[0], COLOR + +XPD OUT[0], IN[0], IN[0].yzxw + +END diff --git a/src/gallium/state_trackers/python/tests/regress/fragment-shader/fragment-shader.py b/src/gallium/state_trackers/python/tests/regress/fragment-shader/fragment-shader.py new file mode 100644 index 0000000000..d60fb38d1a --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/fragment-shader/fragment-shader.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2009 VMware, Inc. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +from gallium import * + +def make_image(surface): + data = surface.get_tile_rgba8(0, 0, surface.width, surface.height) + + import Image + outimage = Image.fromstring('RGBA', (surface.width, surface.height), data, "raw", 'RGBA', 0, 1) + return outimage + +def save_image(filename, surface): + outimage = make_image(surface) + outimage.save(filename, "PNG") + +def test(dev, name): + ctx = dev.context_create() + + width = 320 + height = 320 + minz = 0.0 + maxz = 1.0 + + # disabled blending/masking + blend = Blend() + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.colormask = PIPE_MASK_RGBA + ctx.set_blend(blend) + + # depth/stencil/alpha + depth_stencil_alpha = DepthStencilAlpha() + depth_stencil_alpha.depth.enabled = 0 + depth_stencil_alpha.depth.writemask = 1 + depth_stencil_alpha.depth.func = PIPE_FUNC_LESS + ctx.set_depth_stencil_alpha(depth_stencil_alpha) + + # rasterizer + rasterizer = Rasterizer() + rasterizer.front_winding = PIPE_WINDING_CW + rasterizer.cull_mode = PIPE_WINDING_NONE + rasterizer.scissor = 1 + ctx.set_rasterizer(rasterizer) + + # viewport + viewport = Viewport() + scale = FloatArray(4) + scale[0] = width / 2.0 + scale[1] = -height / 2.0 + scale[2] = (maxz - minz) / 2.0 + scale[3] = 1.0 + viewport.scale = scale + translate = FloatArray(4) + translate[0] = width / 2.0 + translate[1] = height / 2.0 + translate[2] = (maxz - minz) / 2.0 + translate[3] = 0.0 + viewport.translate = translate + ctx.set_viewport(viewport) + + # samplers + sampler = Sampler() + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE + sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.normalized_coords = 1 + ctx.set_sampler(0, sampler) + + # scissor + scissor = Scissor() + scissor.minx = 0 + scissor.miny = 0 + scissor.maxx = width + scissor.maxy = height + ctx.set_scissor(scissor) + + clip = Clip() + clip.nr = 0 + ctx.set_clip(clip) + + # framebuffer + cbuf = dev.texture_create( + PIPE_FORMAT_X8R8G8B8_UNORM, + width, height, + tex_usage=PIPE_TEXTURE_USAGE_DISPLAY_TARGET, + ).get_surface() + fb = Framebuffer() + fb.width = width + fb.height = height + fb.nr_cbufs = 1 + fb.set_cbuf(0, cbuf) + ctx.set_framebuffer(fb) + rgba = FloatArray(4); + rgba[0] = 0.5 + rgba[1] = 0.5 + rgba[2] = 0.5 + rgba[3] = 0.5 + ctx.clear(PIPE_CLEAR_COLOR, rgba, 0.0, 0) + + # vertex shader + vs = Shader(''' + VERT1.1 + DCL IN[0], POSITION + DCL IN[1], COLOR + DCL OUT[0], POSITION + DCL OUT[1], COLOR + MOV OUT[0], IN[0] + MOV OUT[1], IN[1] + END + ''') + ctx.set_vertex_shader(vs) + + # fragment shader + fs = Shader(file('frag-' + name + '.sh', 'rt').read()) + ctx.set_fragment_shader(fs) + + xy = [ + -0.8, -0.8, + 0.8, -0.8, + 0.0, 0.8, + ] + color = [ + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0, + ] + + nverts = 3 + nattrs = 2 + verts = FloatArray(nverts * nattrs * 4) + + for i in range(0, nverts): + verts[i * nattrs * 4 + 0] = xy[i * 2 + 0] # x + verts[i * nattrs * 4 + 1] = xy[i * 2 + 1] # y + verts[i * nattrs * 4 + 2] = 0.5 # z + verts[i * nattrs * 4 + 3] = 1.0 # w + verts[i * nattrs * 4 + 4] = color[i * 3 + 0] # r + verts[i * nattrs * 4 + 5] = color[i * 3 + 1] # g + verts[i * nattrs * 4 + 6] = color[i * 3 + 2] # b + verts[i * nattrs * 4 + 7] = 1.0 # a + + ctx.draw_vertices(PIPE_PRIM_TRIANGLES, + nverts, + nattrs, + verts) + + ctx.flush() + + save_image('frag-' + name + '.png', cbuf) + +def main(): + tests = [ + 'abs', + 'add', + 'dp3', + 'dp4', + 'dst', + 'ex2', + 'flr', + 'frc', + 'lg2', + 'lit', + 'lrp', + 'mad', + 'max', + 'min', + 'mov', + 'mul', + 'rcp', + 'rsq', + 'sge', + 'slt', + 'srcmod-abs', + 'srcmod-absneg', + 'srcmod-neg', + 'srcmod-swz', + 'sub', + 'xpd', + ] + + dev = Device() + for t in tests: + test(dev, t) + +if __name__ == '__main__': + main() diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-abs.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-abs.sh new file mode 100644 index 0000000000..f0d0d5de17 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-abs.sh @@ -0,0 +1,15 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR +DCL TEMP[0] + +IMM FLT32 { 0.2, 0.2, 0.0, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +ABS OUT[0], TEMP[0] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-add.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-add.sh new file mode 100644 index 0000000000..936c851c9d --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-add.sh @@ -0,0 +1,13 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +IMM FLT32 { 0.2, -0.1, 0.0, 0.0 } + +ADD OUT[0], IN[0], IMM[0] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-arl.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-arl.sh new file mode 100644 index 0000000000..7638e96346 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-arl.sh @@ -0,0 +1,23 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0] + +DCL ADDR[0] + +IMM FLT32 { 3.0, 1.0, 1.0, 1.0 } +IMM FLT32 { 1.0, 0.0, 0.0, 1.0 } +IMM FLT32 { 0.0, 1.0, 0.0, 1.0 } +IMM FLT32 { 0.0, 0.0, 1.0, 1.0 } +IMM FLT32 { 1.0, 1.0, 0.0, 1.0 } +IMM FLT32 { 0.0, 1.0, 1.0, 1.0 } + +MOV OUT[0], IN[0] +MUL TEMP[0], IN[0], IMM[0] +ARL ADDR[0].x, TEMP[0] +MOV OUT[1], IMM[ADDR[0].x + 3] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-arr.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-arr.sh new file mode 100644 index 0000000000..28ce6f9a0c --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-arr.sh @@ -0,0 +1,23 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0] + +DCL ADDR[0] + +IMM FLT32 { 3.0, 1.0, 1.0, 1.0 } +IMM FLT32 { 1.0, 0.0, 0.0, 1.0 } +IMM FLT32 { 0.0, 1.0, 0.0, 1.0 } +IMM FLT32 { 0.0, 0.0, 1.0, 1.0 } +IMM FLT32 { 1.0, 1.0, 0.0, 1.0 } +IMM FLT32 { 0.0, 1.0, 1.0, 1.0 } + +MOV OUT[0], IN[0] +MUL TEMP[0], IN[0], IMM[0] +ARR ADDR[0].x, TEMP[0] +MOV OUT[1], IMM[ADDR[0].x + 3] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-dp3.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-dp3.sh new file mode 100644 index 0000000000..b57d68520f --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-dp3.sh @@ -0,0 +1,16 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR +DCL TEMP[0] + +IMM FLT32 { 0.0, 0.0, 1.0, 1.0 } + +DP3 TEMP[0].xy, IN[0], IN[0] +MOV TEMP[0].zw, IMM[0] +MUL OUT[0], IN[0], TEMP[0] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-dp4.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-dp4.sh new file mode 100644 index 0000000000..0eb31719c5 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-dp4.sh @@ -0,0 +1,16 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR +DCL TEMP[0] + +IMM FLT32 { 0.0, 0.0, 1.0, 1.0 } + +DP4 TEMP[0].xy, IN[0], IN[0] +MOV TEMP[0].zw, IMM[0] +MUL OUT[0], IN[0], TEMP[0] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-dst.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-dst.sh new file mode 100644 index 0000000000..dc5e0eb92e --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-dst.sh @@ -0,0 +1,11 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +MOV OUT[0], IN[0] +DST OUT[1], IN[1], IN[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-ex2.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-ex2.sh new file mode 100644 index 0000000000..34057af4e6 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-ex2.sh @@ -0,0 +1,18 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0..1] + +IMM FLT32 { 0.3, 0.3, 0.3, 1.0 } + +EX2 TEMP[0], IN[0] +EX2 TEMP[1], IN[1].yyyy +MUL TEMP[0], TEMP[0], IMM[0] +MOV OUT[0], IN[0] +MUL OUT[1], TEMP[0], TEMP[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-flr.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-flr.sh new file mode 100644 index 0000000000..44ad708119 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-flr.sh @@ -0,0 +1,23 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0] + +DCL ADDR[0] + +IMM FLT32 { 3.0, 1.0, 1.0, 1.0 } +IMM FLT32 { 1.0, 0.0, 0.0, 1.0 } +IMM FLT32 { 0.0, 1.0, 0.0, 1.0 } +IMM FLT32 { 0.0, 0.0, 1.0, 1.0 } +IMM FLT32 { 1.0, 1.0, 0.0, 1.0 } +IMM FLT32 { 0.0, 1.0, 1.0, 1.0 } + +MOV OUT[0], IN[0] +MUL TEMP[0], IN[0], IMM[0] +FLR ADDR[0].x, TEMP[0] +MOV OUT[1], IMM[ADDR[0].x + 3] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-frc.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-frc.sh new file mode 100644 index 0000000000..d179749de8 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-frc.sh @@ -0,0 +1,15 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0] + +IMM FLT32 { 2.7, 3.1, 4.5, 1.0 } + +MUL TEMP[0], IN[0].xyxw, IMM[0] +MOV OUT[0], IN[0] +FRC OUT[1], TEMP[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-lg2.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-lg2.sh new file mode 100644 index 0000000000..f6e08d087c --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-lg2.sh @@ -0,0 +1,18 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0] + +IMM FLT32 { 1.0, 0.0, 0.0, 0.0 } +IMM FLT32 { 0.5, 0.0, 0.0, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +LG2 TEMP[0].x, TEMP[0].xxxx +ADD OUT[0], TEMP[0], IMM[1] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-lit.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-lit.sh new file mode 100644 index 0000000000..da98f30928 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-lit.sh @@ -0,0 +1,11 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +MOV OUT[0], IN[0] +LIT OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-lrp.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-lrp.sh new file mode 100644 index 0000000000..8c262580e2 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-lrp.sh @@ -0,0 +1,14 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0] + +ABS TEMP[0], IN[0] +MOV OUT[0], IN[0] +LRP OUT[1], TEMP[0], IN[1].xxxx, IN[1].yyyy + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-mad.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-mad.sh new file mode 100644 index 0000000000..eb07a3bd56 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-mad.sh @@ -0,0 +1,14 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +IMM FLT32 { 0.5, 1.0, 1.0, 1.0 } +IMM FLT32 { 0.5, 0.0, 0.0, 0.0 } + +MAD OUT[0], IN[0], IMM[0], IMM[1] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-max.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-max.sh new file mode 100644 index 0000000000..2d8b1fe3bf --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-max.sh @@ -0,0 +1,13 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +IMM FLT32 { 0.5, 0.5, 0.5, 0.0 } + +MOV OUT[0], IN[0] +MAX OUT[1], IN[1], IMM[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-min.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-min.sh new file mode 100644 index 0000000000..84af0e2905 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-min.sh @@ -0,0 +1,13 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +IMM FLT32 { 0.5, 0.5, 0.5, 0.0 } + +MOV OUT[0], IN[0] +MIN OUT[1], IN[1], IMM[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-mov.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-mov.sh new file mode 100644 index 0000000000..bcdec07c20 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-mov.sh @@ -0,0 +1,11 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +MOV OUT[0], IN[0] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-mul.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-mul.sh new file mode 100644 index 0000000000..f3b57c3038 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-mul.sh @@ -0,0 +1,13 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +IMM FLT32 { 0.6, 0.6, 1.0, 1.0 } + +MUL OUT[0], IN[0], IMM[0] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-rcp.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-rcp.sh new file mode 100644 index 0000000000..78af589b5c --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-rcp.sh @@ -0,0 +1,18 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0] + +IMM FLT32 { 1.0, 0.0, 0.0, 0.0 } +IMM FLT32 { 1.5, 0.0, 0.0, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +RCP TEMP[0].x, TEMP[0].xxxx +SUB OUT[0], TEMP[0], IMM[1] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-rsq.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-rsq.sh new file mode 100644 index 0000000000..1675c7d5ff --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-rsq.sh @@ -0,0 +1,18 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0] + +IMM FLT32 { 1.0, 0.0, 0.0, 0.0 } +IMM FLT32 { 1.5, 0.0, 0.0, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +RSQ TEMP[0].x, TEMP[0].xxxx +SUB OUT[0], TEMP[0], IMM[1] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-sge.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-sge.sh new file mode 100644 index 0000000000..3d92cd5aae --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-sge.sh @@ -0,0 +1,16 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0] + +IMM FLT32 { -0.1, -0.1, 1.0, 0.0 } + +SGE TEMP[0], IN[0], IMM[0] +MOV OUT[0], IN[0] +MUL OUT[1], IN[1], TEMP[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-slt.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-slt.sh new file mode 100644 index 0000000000..85c60ff4ec --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-slt.sh @@ -0,0 +1,16 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +DCL TEMP[0] + +IMM FLT32 { 0.6, 0.6, 0.0, 0.0 } + +SLT TEMP[0], IN[0], IMM[0] +MOV OUT[0], IN[0] +MUL OUT[1], IN[1], TEMP[0] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-abs.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-abs.sh new file mode 100644 index 0000000000..6db417a62e --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-abs.sh @@ -0,0 +1,15 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR +DCL TEMP[0] + +IMM FLT32 { 0.1, 0.1, 0.0, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +MOV OUT[0], |TEMP[0]| +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-absneg.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-absneg.sh new file mode 100644 index 0000000000..fc83238052 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-absneg.sh @@ -0,0 +1,16 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR +DCL TEMP[0] + +IMM FLT32 { -0.2, -0.2, 0.0, 0.0 } + +ADD TEMP[0], IN[0], IMM[0] +MOV OUT[0].xy, -|TEMP[0]| +MOV OUT[0].zw, IN[0] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-neg.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-neg.sh new file mode 100644 index 0000000000..ce4e90b5e1 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-neg.sh @@ -0,0 +1,12 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +MOV OUT[0].xy, -IN[0] +MOV OUT[0].zw, IN[0] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-swz.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-swz.sh new file mode 100644 index 0000000000..c03de4c674 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-srcmod-swz.sh @@ -0,0 +1,11 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +MOV OUT[0], IN[0].yxzw +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-sub.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-sub.sh new file mode 100644 index 0000000000..a583b95828 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-sub.sh @@ -0,0 +1,13 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +IMM FLT32 { 0.1, 0.1, 0.0, 0.0 } + +SUB OUT[0], IN[0], IMM[0] +MOV OUT[1], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-xpd.sh b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-xpd.sh new file mode 100644 index 0000000000..8def8943b0 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vert-xpd.sh @@ -0,0 +1,11 @@ +VERT1.1 + +DCL IN[0], POSITION +DCL IN[1], COLOR +DCL OUT[0], POSITION +DCL OUT[1], COLOR + +MOV OUT[0], IN[0] +XPD OUT[1], IN[0], IN[1] + +END diff --git a/src/gallium/state_trackers/python/tests/regress/vertex-shader/vertex-shader.py b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vertex-shader.py new file mode 100644 index 0000000000..472769f259 --- /dev/null +++ b/src/gallium/state_trackers/python/tests/regress/vertex-shader/vertex-shader.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2009 VMware, Inc. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +from gallium import * + +def make_image(surface): + data = surface.get_tile_rgba8(0, 0, surface.width, surface.height) + + import Image + outimage = Image.fromstring('RGBA', (surface.width, surface.height), data, "raw", 'RGBA', 0, 1) + return outimage + +def save_image(filename, surface): + outimage = make_image(surface) + outimage.save(filename, "PNG") + +def test(dev, name): + ctx = dev.context_create() + + width = 320 + height = 320 + minz = 0.0 + maxz = 1.0 + + # disabled blending/masking + blend = Blend() + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.colormask = PIPE_MASK_RGBA + ctx.set_blend(blend) + + # depth/stencil/alpha + depth_stencil_alpha = DepthStencilAlpha() + depth_stencil_alpha.depth.enabled = 0 + depth_stencil_alpha.depth.writemask = 1 + depth_stencil_alpha.depth.func = PIPE_FUNC_LESS + ctx.set_depth_stencil_alpha(depth_stencil_alpha) + + # rasterizer + rasterizer = Rasterizer() + rasterizer.front_winding = PIPE_WINDING_CW + rasterizer.cull_mode = PIPE_WINDING_NONE + rasterizer.scissor = 1 + ctx.set_rasterizer(rasterizer) + + # viewport + viewport = Viewport() + scale = FloatArray(4) + scale[0] = width / 2.0 + scale[1] = -height / 2.0 + scale[2] = (maxz - minz) / 2.0 + scale[3] = 1.0 + viewport.scale = scale + translate = FloatArray(4) + translate[0] = width / 2.0 + translate[1] = height / 2.0 + translate[2] = (maxz - minz) / 2.0 + translate[3] = 0.0 + viewport.translate = translate + ctx.set_viewport(viewport) + + # samplers + sampler = Sampler() + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE + sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.normalized_coords = 1 + ctx.set_sampler(0, sampler) + + # scissor + scissor = Scissor() + scissor.minx = 0 + scissor.miny = 0 + scissor.maxx = width + scissor.maxy = height + ctx.set_scissor(scissor) + + clip = Clip() + clip.nr = 0 + ctx.set_clip(clip) + + # framebuffer + cbuf = dev.texture_create( + PIPE_FORMAT_X8R8G8B8_UNORM, + width, height, + tex_usage=PIPE_TEXTURE_USAGE_DISPLAY_TARGET, + ).get_surface() + fb = Framebuffer() + fb.width = width + fb.height = height + fb.nr_cbufs = 1 + fb.set_cbuf(0, cbuf) + ctx.set_framebuffer(fb) + rgba = FloatArray(4); + rgba[0] = 0.5 + rgba[1] = 0.5 + rgba[2] = 0.5 + rgba[3] = 0.5 + ctx.clear(PIPE_CLEAR_COLOR, rgba, 0.0, 0) + + # vertex shader + vs = Shader(file('vert-' + name + '.sh', 'rt').read()) + ctx.set_vertex_shader(vs) + + # fragment shader + fs = Shader(''' + FRAG1.1 + DCL IN[0], COLOR, LINEAR + DCL OUT[0], COLOR, CONSTANT + 0:MOV OUT[0], IN[0] + 1:END + ''') + ctx.set_fragment_shader(fs) + + xy = [ + 0.0, 0.8, + -0.2, 0.4, + 0.2, 0.4, + -0.4, 0.0, + 0.0, 0.0, + 0.4, 0.0, + -0.6, -0.4, + -0.2, -0.4, + 0.2, -0.4, + 0.6, -0.4, + -0.8, -0.8, + -0.4, -0.8, + 0.0, -0.8, + 0.4, -0.8, + 0.8, -0.8, + ] + color = [ + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0, + ] + tri = [ + 1, 2, 0, + 3, 4, 1, + 4, 2, 1, + 4, 5, 2, + 6, 7, 3, + 7, 4, 3, + 7, 8, 4, + 8, 5, 4, + 8, 9, 5, + 10, 11, 6, + 11, 7, 6, + 11, 12, 7, + 12, 8, 7, + 12, 13, 8, + 13, 9, 8, + 13, 14, 9, + ] + + nverts = 16 * 3 + nattrs = 2 + verts = FloatArray(nverts * nattrs * 4) + + for i in range(0, nverts): + verts[i * nattrs * 4 + 0] = xy[tri[i] * 2 + 0] # x + verts[i * nattrs * 4 + 1] = xy[tri[i] * 2 + 1] # y + verts[i * nattrs * 4 + 2] = 0.5 # z + verts[i * nattrs * 4 + 3] = 1.0 # w + verts[i * nattrs * 4 + 4] = color[(i % 3) * 3 + 0] # r + verts[i * nattrs * 4 + 5] = color[(i % 3) * 3 + 1] # g + verts[i * nattrs * 4 + 6] = color[(i % 3) * 3 + 2] # b + verts[i * nattrs * 4 + 7] = 1.0 # a + + ctx.draw_vertices(PIPE_PRIM_TRIANGLES, + nverts, + nattrs, + verts) + + ctx.flush() + + save_image('vert-' + name + '.png', cbuf) + +def main(): + tests = [ + 'abs', + 'add', + 'arl', + 'arr', + 'dp3', + 'dp4', + 'dst', + 'ex2', + 'flr', + 'frc', + 'lg2', + 'lit', + 'lrp', + 'mad', + 'max', + 'min', + 'mov', + 'mul', + 'rcp', + 'rsq', + 'sge', + 'slt', + 'srcmod-abs', + 'srcmod-absneg', + 'srcmod-neg', + 'srcmod-swz', + 'sub', + 'xpd', + ] + + dev = Device() + for t in tests: + test(dev, t) + +if __name__ == '__main__': + main() diff --git a/src/gallium/state_trackers/python/tests/surface_copy.py b/src/gallium/state_trackers/python/tests/surface_copy.py new file mode 100755 index 0000000000..3ceecbbd3a --- /dev/null +++ b/src/gallium/state_trackers/python/tests/surface_copy.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2009 VMware, Inc. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +from gallium import * +from base import * + + +def lods(*dims): + size = max(dims) + lods = 0 + while size: + lods += 1 + size >>= 1 + return lods + + +class TextureTest(TestCase): + + tags = ( + 'target', + 'format', + 'width', + 'height', + 'depth', + 'last_level', + 'face', + 'level', + 'zslice', + ) + + def test(self): + dev = self.dev + + target = self.target + format = self.format + width = self.width + height = self.height + depth = self.depth + last_level = self.last_level + face = self.face + level = self.level + zslice = self.zslice + + # textures + dst_texture = dev.texture_create( + target = target, + format = format, + width = width, + height = height, + depth = depth, + last_level = last_level, + tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET, + ) + if dst_texture is None: + raise TestSkip + + dst_surface = dst_texture.get_surface(face = face, level = level, zslice = zslice) + + src_texture = dev.texture_create( + target = target, + format = format, + width = dst_surface.width, + height = dst_surface.height, + depth = 1, + last_level = 0, + tex_usage = PIPE_TEXTURE_USAGE_SAMPLER, + ) + + src_surface = src_texture.get_surface() + + x = 0 + y = 0 + w = dst_surface.width + h = dst_surface.height + + stride = dst_surface.nblocksx * dst_texture.block.size + size = dst_surface.nblocksy * stride + src_raw = os.urandom(size) + + src_surface.put_tile_raw(0, 0, w, h, src_raw, stride) + + ctx = self.dev.context_create() + + ctx.surface_copy(dst_surface, 0, 0, + src_surface, 0, 0, w, h) + + ctx.flush() + + dst_raw = dst_surface.get_tile_raw(0, 0, w, h) + + if dst_raw != src_raw: + raise TestFailure + + + +def main(): + dev = Device() + suite = TestSuite() + + targets = [ + PIPE_TEXTURE_2D, + PIPE_TEXTURE_CUBE, + #PIPE_TEXTURE_3D, + ] + + formats = [ + PIPE_FORMAT_A8R8G8B8_UNORM, + PIPE_FORMAT_X8R8G8B8_UNORM, + PIPE_FORMAT_A8R8G8B8_SRGB, + PIPE_FORMAT_R5G6B5_UNORM, + PIPE_FORMAT_A1R5G5B5_UNORM, + PIPE_FORMAT_A4R4G4B4_UNORM, + PIPE_FORMAT_Z32_UNORM, + PIPE_FORMAT_Z24S8_UNORM, + PIPE_FORMAT_Z24X8_UNORM, + PIPE_FORMAT_Z16_UNORM, + PIPE_FORMAT_S8_UNORM, + PIPE_FORMAT_A8_UNORM, + PIPE_FORMAT_L8_UNORM, + PIPE_FORMAT_DXT1_RGB, + PIPE_FORMAT_DXT1_RGBA, + PIPE_FORMAT_DXT3_RGBA, + PIPE_FORMAT_DXT5_RGBA, + ] + + sizes = [64, 32, 16, 8, 4, 2, 1] + #sizes = [1020, 508, 252, 62, 30, 14, 6, 3] + #sizes = [64] + #sizes = [63] + + faces = [ + PIPE_TEX_FACE_POS_X, + PIPE_TEX_FACE_NEG_X, + PIPE_TEX_FACE_POS_Y, + PIPE_TEX_FACE_NEG_Y, + PIPE_TEX_FACE_POS_Z, + PIPE_TEX_FACE_NEG_Z, + ] + + for target in targets: + for format in formats: + for size in sizes: + if target == PIPE_TEXTURE_3D: + depth = size + else: + depth = 1 + for face in faces: + if target != PIPE_TEXTURE_CUBE and face: + continue + levels = lods(size) + for last_level in range(levels): + for level in range(0, last_level + 1): + zslice = 0 + while zslice < depth >> level: + test = TextureTest( + dev = dev, + target = target, + format = format, + width = size, + height = size, + depth = depth, + last_level = last_level, + face = face, + level = level, + zslice = zslice, + ) + suite.add_test(test) + zslice = (zslice + 1)*2 - 1 + suite.run() + + +if __name__ == '__main__': + main() diff --git a/src/gallium/state_trackers/python/tests/texture_render.py b/src/gallium/state_trackers/python/tests/texture_render.py new file mode 100755 index 0000000000..0b76932b6e --- /dev/null +++ b/src/gallium/state_trackers/python/tests/texture_render.py @@ -0,0 +1,320 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2009 VMware, Inc. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +from gallium import * +from base import * + + +def lods(*dims): + size = max(dims) + lods = 0 + while size: + lods += 1 + size >>= 1 + return lods + + +class TextureTest(TestCase): + + tags = ( + 'target', + 'format', + 'width', + 'height', + 'depth', + 'last_level', + 'face', + 'level', + 'zslice', + ) + + def test(self): + dev = self.dev + + target = self.target + format = self.format + width = self.width + height = self.height + depth = self.depth + last_level = self.last_level + face = self.face + level = self.level + zslice = self.zslice + + # textures + dst_texture = dev.texture_create( + target = target, + format = format, + width = width, + height = height, + depth = depth, + last_level = last_level, + tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET, + ) + if dst_texture is None: + raise TestSkip + + dst_surface = dst_texture.get_surface(face = face, level = level, zslice = zslice) + + ref_texture = dev.texture_create( + target = target, + format = format, + width = dst_surface.width, + height = dst_surface.height, + depth = 1, + last_level = 0, + tex_usage = PIPE_TEXTURE_USAGE_SAMPLER, + ) + + ref_surface = ref_texture.get_surface() + + src_texture = dev.texture_create( + target = target, + format = PIPE_FORMAT_A8R8G8B8_UNORM, + width = dst_surface.width, + height = dst_surface.height, + depth = 1, + last_level = 0, + tex_usage = PIPE_TEXTURE_USAGE_SAMPLER, + ) + + src_surface = src_texture.get_surface() + + expected_rgba = FloatArray(height*width*4) + ref_surface.sample_rgba(expected_rgba) + + src_surface.put_tile_rgba(0, 0, src_surface.width, src_surface.height, expected_rgba) + + ctx = self.dev.context_create() + + # disabled blending/masking + blend = Blend() + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.colormask = PIPE_MASK_RGBA + ctx.set_blend(blend) + + # no-op depth/stencil/alpha + depth_stencil_alpha = DepthStencilAlpha() + ctx.set_depth_stencil_alpha(depth_stencil_alpha) + + # rasterizer + rasterizer = Rasterizer() + rasterizer.front_winding = PIPE_WINDING_CW + rasterizer.cull_mode = PIPE_WINDING_NONE + rasterizer.bypass_vs_clip_and_viewport = 1 + ctx.set_rasterizer(rasterizer) + + # samplers + sampler = Sampler() + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.normalized_coords = 1 + sampler.min_lod = 0 + sampler.max_lod = PIPE_MAX_TEXTURE_LEVELS - 1 + ctx.set_sampler(0, sampler) + ctx.set_sampler_texture(0, src_texture) + + # framebuffer + cbuf_tex = dev.texture_create( + PIPE_FORMAT_A8R8G8B8_UNORM, + width, + height, + tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET, + ) + + fb = Framebuffer() + fb.width = dst_surface.width + fb.height = dst_surface.height + fb.nr_cbufs = 1 + fb.set_cbuf(0, dst_surface) + ctx.set_framebuffer(fb) + rgba = FloatArray(4); + rgba[0] = 0.0 + rgba[1] = 0.0 + rgba[2] = 0.0 + rgba[3] = 0.0 + ctx.clear(PIPE_CLEAR_COLOR, rgba, 0.0, 0) + del fb + + # vertex shader + vs = Shader(''' + VERT1.1 + DCL IN[0], POSITION, CONSTANT + DCL IN[1], GENERIC, CONSTANT + DCL OUT[0], POSITION, CONSTANT + DCL OUT[1], GENERIC, CONSTANT + 0:MOV OUT[0], IN[0] + 1:MOV OUT[1], IN[1] + 2:END + ''') + #vs.dump() + ctx.set_vertex_shader(vs) + + # fragment shader + fs = Shader(''' + FRAG1.1 + DCL IN[0], GENERIC[0], LINEAR + DCL OUT[0], COLOR, CONSTANT + DCL SAMP[0], CONSTANT + 0:TEX OUT[0], IN[0], SAMP[0], 2D + 1:END + ''') + #fs.dump() + ctx.set_fragment_shader(fs) + + nverts = 4 + nattrs = 2 + verts = FloatArray(nverts * nattrs * 4) + + x = 0 + y = 0 + w = dst_surface.width + h = dst_surface.height + + pos = [ + [x, y], + [x+w, y], + [x+w, y+h], + [x, y+h], + ] + + tex = [ + [0.0, 0.0], + [1.0, 0.0], + [1.0, 1.0], + [0.0, 1.0], + ] + + for i in range(0, 4): + j = 8*i + verts[j + 0] = pos[i][0] # x + verts[j + 1] = pos[i][1] # y + verts[j + 2] = 0.0 # z + verts[j + 3] = 1.0 # w + verts[j + 4] = tex[i][0] # s + verts[j + 5] = tex[i][1] # r + verts[j + 6] = 0.0 + verts[j + 7] = 1.0 + + ctx.draw_vertices(PIPE_PRIM_TRIANGLE_FAN, + nverts, + nattrs, + verts) + + ctx.flush() + + self.assert_rgba(dst_surface, x, y, w, h, expected_rgba, 4.0/256, 0.85) + + + +def main(): + dev = Device() + suite = TestSuite() + + targets = [ + PIPE_TEXTURE_2D, + PIPE_TEXTURE_CUBE, + #PIPE_TEXTURE_3D, + ] + + formats = [ + PIPE_FORMAT_A8R8G8B8_UNORM, + PIPE_FORMAT_X8R8G8B8_UNORM, + #PIPE_FORMAT_A8R8G8B8_SRGB, + PIPE_FORMAT_R5G6B5_UNORM, + PIPE_FORMAT_A1R5G5B5_UNORM, + PIPE_FORMAT_A4R4G4B4_UNORM, + #PIPE_FORMAT_Z32_UNORM, + #PIPE_FORMAT_Z24S8_UNORM, + #PIPE_FORMAT_Z24X8_UNORM, + #PIPE_FORMAT_Z16_UNORM, + #PIPE_FORMAT_S8_UNORM, + PIPE_FORMAT_A8_UNORM, + PIPE_FORMAT_L8_UNORM, + #PIPE_FORMAT_DXT1_RGB, + #PIPE_FORMAT_DXT1_RGBA, + #PIPE_FORMAT_DXT3_RGBA, + #PIPE_FORMAT_DXT5_RGBA, + ] + + sizes = [64, 32, 16, 8, 4, 2, 1] + #sizes = [1020, 508, 252, 62, 30, 14, 6, 3] + #sizes = [64] + #sizes = [63] + + faces = [ + PIPE_TEX_FACE_POS_X, + PIPE_TEX_FACE_NEG_X, + PIPE_TEX_FACE_POS_Y, + PIPE_TEX_FACE_NEG_Y, + PIPE_TEX_FACE_POS_Z, + PIPE_TEX_FACE_NEG_Z, + ] + + for target in targets: + for format in formats: + for size in sizes: + if target == PIPE_TEXTURE_3D: + depth = size + else: + depth = 1 + for face in faces: + if target != PIPE_TEXTURE_CUBE and face: + continue + levels = lods(size) + for last_level in range(levels): + for level in range(0, last_level + 1): + zslice = 0 + while zslice < depth >> level: + test = TextureTest( + dev = dev, + target = target, + format = format, + width = size, + height = size, + depth = depth, + last_level = last_level, + face = face, + level = level, + zslice = zslice, + ) + suite.add_test(test) + zslice = (zslice + 1)*2 - 1 + suite.run() + + +if __name__ == '__main__': + main() diff --git a/src/gallium/state_trackers/python/tests/texture_sample.py b/src/gallium/state_trackers/python/tests/texture_sample.py new file mode 100755 index 0000000000..c7b78abbbe --- /dev/null +++ b/src/gallium/state_trackers/python/tests/texture_sample.py @@ -0,0 +1,591 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2009 VMware, Inc. +# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +from gallium import * +from base import * + + +def lods(*dims): + size = max(dims) + lods = 0 + while size: + lods += 1 + size >>= 1 + return lods + + +def minify(dims, level = 1): + return [max(dim>>level, 1) for dim in dims] + + +def tex_coords(texture, face, level, zslice): + st = [ + [0.0, 0.0], + [1.0, 0.0], + [1.0, 1.0], + [0.0, 1.0], + ] + + if texture.target == PIPE_TEXTURE_2D: + return [[s, t, 0.0] for s, t in st] + elif texture.target == PIPE_TEXTURE_3D: + depth = texture.get_depth(level) + if depth > 1: + r = float(zslice)/float(depth - 1) + else: + r = 0.0 + return [[s, t, r] for s, t in st] + elif texture.target == PIPE_TEXTURE_CUBE: + result = [] + for s, t in st: + # See http://developer.nvidia.com/object/cube_map_ogl_tutorial.html + sc = 2.0*s - 1.0 + tc = 2.0*t - 1.0 + if face == PIPE_TEX_FACE_POS_X: + rx = 1.0 + ry = -tc + rz = -sc + if face == PIPE_TEX_FACE_NEG_X: + rx = -1.0 + ry = -tc + rz = sc + if face == PIPE_TEX_FACE_POS_Y: + rx = sc + ry = 1.0 + rz = tc + if face == PIPE_TEX_FACE_NEG_Y: + rx = sc + ry = -1.0 + rz = -tc + if face == PIPE_TEX_FACE_POS_Z: + rx = sc + ry = -tc + rz = 1.0 + if face == PIPE_TEX_FACE_NEG_Z: + rx = -sc + ry = -tc + rz = -1.0 + result.append([rx, ry, rz]) + return result + +def is_pot(n): + return n & (n - 1) == 0 + + +class TextureColorSampleTest(TestCase): + + tags = ( + 'target', + 'format', + 'width', + 'height', + 'depth', + 'last_level', + 'face', + 'level', + 'zslice', + ) + + def test(self): + dev = self.dev + + target = self.target + format = self.format + width = self.width + height = self.height + depth = self.depth + last_level = self.last_level + face = self.face + level = self.level + zslice = self.zslice + + tex_usage = PIPE_TEXTURE_USAGE_SAMPLER + geom_flags = 0 + if width != height: + geom_flags |= PIPE_TEXTURE_GEOM_NON_SQUARE + if not is_pot(width) or not is_pot(height) or not is_pot(depth): + geom_flags |= PIPE_TEXTURE_GEOM_NON_POWER_OF_TWO + + if not dev.is_format_supported(format, target, tex_usage, geom_flags): + raise TestSkip + + ctx = self.dev.context_create() + + # disabled blending/masking + blend = Blend() + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.colormask = PIPE_MASK_RGBA + ctx.set_blend(blend) + + # no-op depth/stencil/alpha + depth_stencil_alpha = DepthStencilAlpha() + ctx.set_depth_stencil_alpha(depth_stencil_alpha) + + # rasterizer + rasterizer = Rasterizer() + rasterizer.front_winding = PIPE_WINDING_CW + rasterizer.cull_mode = PIPE_WINDING_NONE + rasterizer.bypass_vs_clip_and_viewport = 1 + ctx.set_rasterizer(rasterizer) + + # samplers + sampler = Sampler() + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.normalized_coords = 1 + sampler.min_lod = 0 + sampler.max_lod = PIPE_MAX_TEXTURE_LEVELS - 1 + ctx.set_sampler(0, sampler) + + # texture + texture = dev.texture_create( + target = target, + format = format, + width = width, + height = height, + depth = depth, + last_level = last_level, + tex_usage = tex_usage, + ) + + expected_rgba = FloatArray(height*width*4) + texture.get_surface( + face = face, + level = level, + zslice = zslice, + ).sample_rgba(expected_rgba) + + ctx.set_sampler_texture(0, texture) + + # framebuffer + cbuf_tex = dev.texture_create( + PIPE_FORMAT_A8R8G8B8_UNORM, + width, + height, + tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET, + ) + + cbuf = cbuf_tex.get_surface() + fb = Framebuffer() + fb.width = width + fb.height = height + fb.nr_cbufs = 1 + fb.set_cbuf(0, cbuf) + ctx.set_framebuffer(fb) + rgba = FloatArray(4); + rgba[0] = 0.5 + rgba[1] = 0.5 + rgba[2] = 0.5 + rgba[3] = 0.5 + ctx.clear(PIPE_CLEAR_COLOR, rgba, 0.0, 0) + del fb + + # vertex shader + vs = Shader(''' + VERT1.1 + DCL IN[0], POSITION, CONSTANT + DCL IN[1], GENERIC, CONSTANT + DCL OUT[0], POSITION, CONSTANT + DCL OUT[1], GENERIC, CONSTANT + 0:MOV OUT[0], IN[0] + 1:MOV OUT[1], IN[1] + 2:END + ''') + #vs.dump() + ctx.set_vertex_shader(vs) + + # fragment shader + op = { + PIPE_TEXTURE_1D: "1D", + PIPE_TEXTURE_2D: "2D", + PIPE_TEXTURE_3D: "3D", + PIPE_TEXTURE_CUBE: "CUBE", + }[target] + fs = Shader(''' + FRAG1.1 + DCL IN[0], GENERIC[0], LINEAR + DCL OUT[0], COLOR, CONSTANT + DCL SAMP[0], CONSTANT + 0:TEX OUT[0], IN[0], SAMP[0], %s + 1:END + ''' % op) + #fs.dump() + ctx.set_fragment_shader(fs) + + nverts = 4 + nattrs = 2 + verts = FloatArray(nverts * nattrs * 4) + + x = 0 + y = 0 + w, h = minify((width, height), level) + + pos = [ + [x, y], + [x+w, y], + [x+w, y+h], + [x, y+h], + ] + + tex = tex_coords(texture, face, level, zslice) + + for i in range(0, 4): + j = 8*i + verts[j + 0] = pos[i][0] # x + verts[j + 1] = pos[i][1] # y + verts[j + 2] = 0.0 # z + verts[j + 3] = 1.0 # w + verts[j + 4] = tex[i][0] # s + verts[j + 5] = tex[i][1] # r + verts[j + 6] = tex[i][2] # q + verts[j + 7] = 1.0 + + ctx.draw_vertices(PIPE_PRIM_TRIANGLE_FAN, + nverts, + nattrs, + verts) + + ctx.flush() + + cbuf = cbuf_tex.get_surface() + + self.assert_rgba(cbuf, x, y, w, h, expected_rgba, 4.0/256, 0.85) + + +class TextureDepthSampleTest(TestCase): + + tags = ( + 'target', + 'format', + 'width', + 'height', + 'depth', + 'last_level', + 'face', + 'level', + 'zslice', + ) + + def test(self): + dev = self.dev + + target = self.target + format = self.format + width = self.width + height = self.height + depth = self.depth + last_level = self.last_level + face = self.face + level = self.level + zslice = self.zslice + + tex_usage = PIPE_TEXTURE_USAGE_SAMPLER + geom_flags = 0 + if width != height: + geom_flags |= PIPE_TEXTURE_GEOM_NON_SQUARE + if not is_pot(width) or not is_pot(height) or not is_pot(depth): + geom_flags |= PIPE_TEXTURE_GEOM_NON_POWER_OF_TWO + + if not dev.is_format_supported(format, target, tex_usage, geom_flags): + raise TestSkip + + ctx = self.dev.context_create() + + # disabled blending/masking + blend = Blend() + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO + blend.colormask = PIPE_MASK_RGBA + ctx.set_blend(blend) + + # depth/stencil/alpha + depth_stencil_alpha = DepthStencilAlpha() + depth_stencil_alpha.depth.enabled = 1 + depth_stencil_alpha.depth.writemask = 1 + depth_stencil_alpha.depth.func = PIPE_FUNC_LESS + ctx.set_depth_stencil_alpha(depth_stencil_alpha) + + # rasterizer + rasterizer = Rasterizer() + rasterizer.front_winding = PIPE_WINDING_CW + rasterizer.cull_mode = PIPE_WINDING_NONE + rasterizer.bypass_vs_clip_and_viewport = 1 + ctx.set_rasterizer(rasterizer) + + # samplers + sampler = Sampler() + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST + sampler.normalized_coords = 1 + sampler.min_lod = 0 + sampler.max_lod = PIPE_MAX_TEXTURE_LEVELS - 1 + ctx.set_sampler(0, sampler) + + # texture + texture = dev.texture_create( + target = target, + format = format, + width = width, + height = height, + depth = depth, + last_level = last_level, + tex_usage = tex_usage, + ) + + expected_rgba = FloatArray(height*width*4) + texture.get_surface( + face = face, + level = level, + zslice = zslice, + ).sample_rgba(expected_rgba) + + ctx.set_sampler_texture(0, texture) + + # framebuffer + cbuf_tex = dev.texture_create( + PIPE_FORMAT_A8R8G8B8_UNORM, + width, + height, + tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET, + ) + + zsbuf_tex = dev.texture_create( + PIPE_FORMAT_Z24X8_UNORM, + width, + height, + tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET, + ) + + cbuf = cbuf_tex.get_surface() + zsbuf = zsbuf_tex.get_surface() + fb = Framebuffer() + fb.width = width + fb.height = height + fb.nr_cbufs = 1 + fb.set_cbuf(0, cbuf) + fb.set_zsbuf(zsbuf) + ctx.set_framebuffer(fb) + rgba = FloatArray(4); + rgba[0] = 0.5 + rgba[1] = 0.5 + rgba[2] = 0.5 + rgba[3] = 0.5 + ctx.clear(PIPE_CLEAR_DEPTHSTENCIL, rgba, 1.0, 0) + del fb + + # vertex shader + vs = Shader(''' + VERT1.1 + DCL IN[0], POSITION, CONSTANT + DCL IN[1], GENERIC, CONSTANT + DCL OUT[0], POSITION, CONSTANT + DCL OUT[1], GENERIC, CONSTANT + 0:MOV OUT[0], IN[0] + 1:MOV OUT[1], IN[1] + 2:END + ''') + #vs.dump() + ctx.set_vertex_shader(vs) + + # fragment shader + op = { + PIPE_TEXTURE_1D: "1D", + PIPE_TEXTURE_2D: "2D", + PIPE_TEXTURE_3D: "3D", + PIPE_TEXTURE_CUBE: "CUBE", + }[target] + fs = Shader(''' + FRAG1.1 + DCL IN[0], GENERIC[0], LINEAR + DCL SAMP[0], CONSTANT + DCL OUT[0].z, POSITION + 0:TEX OUT[0].z, IN[0], SAMP[0], %s + 1:END + ''' % op) + #fs.dump() + ctx.set_fragment_shader(fs) + + nverts = 4 + nattrs = 2 + verts = FloatArray(nverts * nattrs * 4) + + x = 0 + y = 0 + w, h = minify((width, height), level) + + pos = [ + [x, y], + [x+w, y], + [x+w, y+h], + [x, y+h], + ] + + tex = tex_coords(texture, face, level, zslice) + + for i in range(0, 4): + j = 8*i + verts[j + 0] = pos[i][0] # x + verts[j + 1] = pos[i][1] # y + verts[j + 2] = 0.0 # z + verts[j + 3] = 1.0 # w + verts[j + 4] = tex[i][0] # s + verts[j + 5] = tex[i][1] # r + verts[j + 6] = tex[i][2] # q + verts[j + 7] = 1.0 + + ctx.draw_vertices(PIPE_PRIM_TRIANGLE_FAN, + nverts, + nattrs, + verts) + + ctx.flush() + + zsbuf = zsbuf_tex.get_surface() + + self.assert_rgba(zsbuf, x, y, w, h, expected_rgba, 4.0/256, 0.85) + + + + +def main(): + dev = Device() + suite = TestSuite() + + targets = [ + PIPE_TEXTURE_2D, + PIPE_TEXTURE_CUBE, + PIPE_TEXTURE_3D, + ] + + color_formats = [ + PIPE_FORMAT_A8R8G8B8_UNORM, + PIPE_FORMAT_X8R8G8B8_UNORM, + #PIPE_FORMAT_A8R8G8B8_SRGB, + PIPE_FORMAT_R5G6B5_UNORM, + PIPE_FORMAT_A1R5G5B5_UNORM, + PIPE_FORMAT_A4R4G4B4_UNORM, + PIPE_FORMAT_A8_UNORM, + PIPE_FORMAT_L8_UNORM, + PIPE_FORMAT_YCBCR, + PIPE_FORMAT_DXT1_RGB, + #PIPE_FORMAT_DXT1_RGBA, + #PIPE_FORMAT_DXT3_RGBA, + #PIPE_FORMAT_DXT5_RGBA, + ] + + depth_formats = [ + PIPE_FORMAT_Z32_UNORM, + PIPE_FORMAT_Z24S8_UNORM, + PIPE_FORMAT_Z24X8_UNORM, + PIPE_FORMAT_Z16_UNORM, + ] + + sizes = [64, 32, 16, 8, 4, 2, 1] + #sizes = [1020, 508, 252, 62, 30, 14, 6, 3] + #sizes = [64] + #sizes = [63] + + faces = [ + PIPE_TEX_FACE_POS_X, + PIPE_TEX_FACE_NEG_X, + PIPE_TEX_FACE_POS_Y, + PIPE_TEX_FACE_NEG_Y, + PIPE_TEX_FACE_POS_Z, + PIPE_TEX_FACE_NEG_Z, + ] + + for format in color_formats: + for target in targets: + for size in sizes: + if target == PIPE_TEXTURE_3D: + depth = size + else: + depth = 1 + for face in faces: + if target != PIPE_TEXTURE_CUBE and face: + continue + levels = lods(size) + for last_level in range(levels): + for level in range(0, last_level + 1): + zslice = 0 + while zslice < depth >> level: + test = TextureColorSampleTest( + dev = dev, + target = target, + format = format, + width = size, + height = size, + depth = depth, + last_level = last_level, + face = face, + level = level, + zslice = zslice, + ) + suite.add_test(test) + zslice = (zslice + 1)*2 - 1 + for format in depth_formats: + target = PIPE_TEXTURE_2D + depth = 1 + face = 0 + last_level = 0 + level = 0 + zslice = 0 + for size in sizes: + test = TextureDepthSampleTest( + dev = dev, + target = target, + format = format, + width = size, + height = size, + depth = depth, + last_level = last_level, + face = face, + level = level, + zslice = zslice, + ) + suite.add_test(test) + suite.run() + + +if __name__ == '__main__': + main() diff --git a/src/gallium/state_trackers/python/tests/texture_transfer.py b/src/gallium/state_trackers/python/tests/texture_transfer.py new file mode 100755 index 0000000000..e65b425adf --- /dev/null +++ b/src/gallium/state_trackers/python/tests/texture_transfer.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +########################################################################## +# +# Copyright 2009 VMware, Inc. +# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sub license, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice (including the +# next paragraph) shall be included in all copies or substantial portions +# of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +########################################################################## + + +import os + +from gallium import * +from base import * + + +def lods(*dims): + size = max(dims) + lods = 0 + while size: + lods += 1 + size >>= 1 + return lods + + +class TextureTest(TestCase): + + tags = ( + 'target', + 'format', + 'width', + 'height', + 'depth', + 'last_level', + 'face', + 'level', + 'zslice', + ) + + def test(self): + dev = self.dev + + target = self.target + format = self.format + width = self.width + height = self.height + depth = self.depth + last_level = self.last_level + face = self.face + level = self.level + zslice = self.zslice + + tex_usage = 0 + + texture = dev.texture_create( + target = target, + format = format, + width = width, + height = height, + depth = depth, + last_level = last_level, + tex_usage = tex_usage, + ) + if texture is None: + raise TestSkip + + surface = texture.get_surface(face, level, zslice) + + stride = surface.nblocksx * texture.block.size + size = surface.nblocksy * stride + + in_raw = os.urandom(size) + + surface.put_tile_raw(0, 0, surface.width, surface.height, in_raw, stride) + + out_raw = surface.get_tile_raw(0, 0, surface.width, surface.height) + + if in_raw != out_raw: + raise TestFailure + + +def main(): + dev = Device() + suite = TestSuite() + + targets = [ + PIPE_TEXTURE_2D, + PIPE_TEXTURE_CUBE, + PIPE_TEXTURE_3D, + ] + + formats = [ + PIPE_FORMAT_A8R8G8B8_UNORM, + PIPE_FORMAT_X8R8G8B8_UNORM, + PIPE_FORMAT_A8R8G8B8_SRGB, + PIPE_FORMAT_R5G6B5_UNORM, + PIPE_FORMAT_A1R5G5B5_UNORM, + PIPE_FORMAT_A4R4G4B4_UNORM, + PIPE_FORMAT_Z32_UNORM, + PIPE_FORMAT_Z24S8_UNORM, + PIPE_FORMAT_Z24X8_UNORM, + PIPE_FORMAT_Z16_UNORM, + PIPE_FORMAT_S8_UNORM, + PIPE_FORMAT_A8_UNORM, + PIPE_FORMAT_L8_UNORM, + PIPE_FORMAT_DXT1_RGB, + PIPE_FORMAT_DXT1_RGBA, + PIPE_FORMAT_DXT3_RGBA, + PIPE_FORMAT_DXT5_RGBA, + ] + + sizes = [64, 32, 16, 8, 4, 2, 1] + #sizes = [1020, 508, 252, 62, 30, 14, 6, 3] + #sizes = [64] + #sizes = [63] + + faces = [ + PIPE_TEX_FACE_POS_X, + PIPE_TEX_FACE_NEG_X, + PIPE_TEX_FACE_POS_Y, + PIPE_TEX_FACE_NEG_Y, + PIPE_TEX_FACE_POS_Z, + PIPE_TEX_FACE_NEG_Z, + ] + + for target in targets: + for format in formats: + for size in sizes: + if target == PIPE_TEXTURE_3D: + depth = size + else: + depth = 1 + for face in faces: + if target != PIPE_TEXTURE_CUBE and face: + continue + levels = lods(size) + for last_level in range(levels): + for level in range(0, last_level + 1): + zslice = 0 + while zslice < depth >> level: + test = TextureTest( + dev = dev, + target = target, + format = format, + width = size, + height = size, + depth = depth, + last_level = last_level, + face = face, + level = level, + zslice = zslice, + ) + suite.add_test(test) + zslice = (zslice + 1)*2 - 1 + suite.run() + + +if __name__ == '__main__': + main() diff --git a/src/gallium/state_trackers/python/tests/tree.py b/src/gallium/state_trackers/python/tests/tree.py new file mode 100755 index 0000000000..0c1bcda4cf --- /dev/null +++ b/src/gallium/state_trackers/python/tests/tree.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# +# See also: +# http://www.ailab.si/orange/doc/ofb/c_otherclass.htm + +import os.path +import sys + +import orange +import orngTree + +for arg in sys.argv[1:]: + name, ext = os.path.splitext(arg) + + data = orange.ExampleTable(arg) + + tree = orngTree.TreeLearner(data, sameMajorityPruning=1, mForPruning=2) + + orngTree.printTxt(tree) + + file(name+'.txt', 'wt').write(orngTree.dumpTree(tree) + '\n') + + orngTree.printDot(tree, fileName=name+'.dot', nodeShape='ellipse', leafShape='box') diff --git a/src/gallium/state_trackers/vega/Makefile b/src/gallium/state_trackers/vega/Makefile new file mode 100644 index 0000000000..b8c805b06c --- /dev/null +++ b/src/gallium/state_trackers/vega/Makefile @@ -0,0 +1,128 @@ +# src/mesa/Makefile + +TOP = ../../../.. +include $(TOP)/configs/current +GALLIUM = $(TOP) + +### Lists of source files, included by Makefiles + +VG_SOURCES = \ + api_context.c \ + api_filters.c \ + api_images.c \ + api_masks.c \ + api_misc.c \ + api_paint.c \ + api_params.c \ + api_path.c \ + api_text.c \ + api_transform.c \ + vgu.c \ + vg_context.c \ + vg_state.c \ + vg_tracker.c \ + vg_translate.c \ + polygon.c \ + bezier.c \ + path.c \ + paint.c \ + arc.c \ + image.c \ + renderer.c \ + stroker.c \ + mask.c \ + shader.c \ + shaders_cache.c + + +### All the core C sources + +ALL_SOURCES = \ + $(VG_SOURCES) + + +### Object files +VG_OBJECTS = \ + $(VG_SOURCES:.c=.o) + +### Include directories + +INCLUDE_DIRS = \ + -I$(TOP)/include \ + -I$(GALLIUM)/include \ + -I$(GALLIUM)/src/gallium/include \ + -I$(GALLIUM)/src/gallium/auxiliary + +VG_LIB = OpenVG +VG_LIB_NAME = lib$(VG_LIB).so + +VG_MAJOR = 1 +VG_MINOR = 0 +VG_TINY = 0 + +GALLIUM_LIBS = \ + $(GALLIUM)/src/gallium/auxiliary/pipebuffer/libpipebuffer.a \ + $(GALLIUM)/src/gallium/auxiliary/sct/libsct.a \ + $(GALLIUM)/src/gallium/auxiliary/draw/libdraw.a \ + $(GALLIUM)/src/gallium/auxiliary/rtasm/librtasm.a \ + $(GALLIUM)/src/gallium/auxiliary/translate/libtranslate.a \ + $(GALLIUM)/src/gallium/auxiliary/cso_cache/libcso_cache.a \ + $(GALLIUM)/src/gallium/auxiliary/util/libutil.a \ + $(GALLIUM)/src/gallium/auxiliary/tgsi/libtgsi.a + +.SUFFIXES : .cpp + +.c.o: + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@ + +.cpp.o: + $(CXX) -c $(INCLUDE_DIRS) $(CXXFLAGS) $< -o $@ + +.S.o: + $(CC) -c $(INCLUDE_DIRS) $(CFLAGS) $< -o $@ + + +default: depend subdirs $(TOP)/$(LIB_DIR)/$(VG_LIB_NAME) + +# Make the OpenVG library +$(TOP)/$(LIB_DIR)/$(VG_LIB_NAME): $(VG_OBJECTS) $(GALLIUM_LIBS) + $(TOP)/bin/mklib -o $(VG_LIB) \ + -major $(VG_MAJOR) \ + -minor $(VG_MINOR) \ + -patch $(VG_TINY) \ + -install $(TOP)/$(LIB_DIR) \ + $(VG_OBJECTS) $(GALLIUM_LIBS) \ + -Wl,--whole-archive $(LIBS) -Wl,--no-whole-archive $(SYS_LIBS) + +###################################################################### +# Generic stuff + +depend: $(ALL_SOURCES) + @ echo "running $(MKDEP)" + @ rm -f depend # workaround oops on gutsy?!? + @ touch depend + @ $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) $(ALL_SOURCES) \ + > /dev/null 2>/dev/null + + +subdirs: + +install: default + $(INSTALL) -d $(INSTALL_DIR)/include/VG + $(INSTALL) -d $(INSTALL_DIR)/$(LIB_DIR) + $(INSTALL) -m 644 $(TOP)/include/VG/*.h $(INSTALL_DIR)/include/VG + @if [ -e $(TOP)/$(LIB_DIR)/$(VG_LIB_NAME) ]; then \ + $(INSTALL) $(TOP)/$(LIB_DIR)/libOpenVG* $(INSTALL_DIR)/$(LIB_DIR); \ + fi + +# Emacs tags +tags: + etags `find . -name \*.[ch]` $(TOP)/include/VG/*.h + +clean: + -rm -f *.o + -rm -f */*.o + -rm -f */*/*.o + -rm -f depend depend.bak + +include depend diff --git a/src/gallium/state_trackers/vega/api_consts.h b/src/gallium/state_trackers/vega/api_consts.h new file mode 100644 index 0000000000..e1b48d4a46 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_consts.h @@ -0,0 +1,56 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef API_CONSTS_H +#define API_CONSTS_H + +/*must be at least 32*/ +#define VEGA_MAX_SCISSOR_RECTS 32 + +/*must be at least 16*/ +#define VEGA_MAX_DASH_COUNT 32 + +/*must be at least 7*/ +#define VEGA_MAX_KERNEL_SIZE 7 + +/*must be at least 15*/ +#define VEGA_MAX_SEPARABLE_KERNEL_SIZE 15 + +/*must be at least 32*/ +#define VEGA_MAX_COLOR_RAMP_STOPS 256 + +#define VEGA_MAX_IMAGE_WIDTH 2048 + +#define VEGA_MAX_IMAGE_HEIGHT 2048 + +#define VEGA_MAX_IMAGE_PIXELS (2048*2048) + +#define VEGA_MAX_IMAGE_BYTES (2048*2048 * 4) + +/*must be at least 128*/ +#define VEGA_MAX_GAUSSIAN_STD_DEVIATION 128 + +#endif diff --git a/src/gallium/state_trackers/vega/api_context.c b/src/gallium/state_trackers/vega/api_context.c new file mode 100644 index 0000000000..47db102dd2 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_context.c @@ -0,0 +1,75 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "VG/openvg.h" + +#include "vg_context.h" + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" + +VGErrorCode vgGetError(void) +{ + struct vg_context *ctx = vg_current_context(); + VGErrorCode error = VG_NO_CONTEXT_ERROR; + + if (!ctx) + return error; + + error = ctx->_error; + ctx->_error = VG_NO_ERROR; + + return error; +} + +void vgFlush(void) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_context *pipe; + + if (!ctx) + return; + + pipe = ctx->pipe; + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); +} + +void vgFinish(void) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_fence_handle *fence = NULL; + struct pipe_context *pipe; + + if (!ctx) + return; + + pipe = ctx->pipe; + + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence); + + pipe->screen->fence_finish(pipe->screen, fence, 0); + pipe->screen->fence_reference(pipe->screen, &fence, NULL); +} diff --git a/src/gallium/state_trackers/vega/api_filters.c b/src/gallium/state_trackers/vega/api_filters.c new file mode 100644 index 0000000000..862cbb03c4 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_filters.c @@ -0,0 +1,805 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "VG/openvg.h" + +#include "vg_context.h" +#include "image.h" +#include "renderer.h" +#include "shaders_cache.h" +#include "st_inlines.h" + +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "pipe/p_inlines.h" +#include "pipe/p_screen.h" +#include "pipe/p_shader_tokens.h" + +#include "util/u_memory.h" + + +#include "asm_filters.h" + + +struct filter_info { + struct vg_image *dst; + struct vg_image *src; + struct vg_shader * (*setup_shader)(struct vg_context *, void *); + void *user_data; + const void *const_buffer; + VGint const_buffer_len; + VGTilingMode tiling_mode; + struct pipe_texture *extra_texture; +}; + +static INLINE struct pipe_texture *create_texture_1d(struct vg_context *ctx, + const VGuint *color_data, + const VGint color_data_len) +{ + struct pipe_context *pipe = ctx->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_texture *tex = 0; + struct pipe_texture templ; + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_1D; + templ.format = PIPE_FORMAT_A8R8G8B8_UNORM; + templ.last_level = 0; + templ.width[0] = color_data_len; + templ.height[0] = 1; + templ.depth[0] = 1; + pf_get_block(PIPE_FORMAT_A8R8G8B8_UNORM, &templ.block); + templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER; + + tex = screen->texture_create(screen, &templ); + + { /* upload color_data */ + struct pipe_transfer *transfer = + screen->get_tex_transfer(screen, tex, + 0, 0, 0, + PIPE_TRANSFER_READ_WRITE , + 0, 0, tex->width[0], tex->height[0]); + void *map = screen->transfer_map(screen, transfer); + memcpy(map, color_data, sizeof(VGint)*color_data_len); + screen->transfer_unmap(screen, transfer); + screen->tex_transfer_destroy(transfer); + } + + return tex; +} + +static INLINE struct pipe_surface * setup_framebuffer(struct vg_image *dst) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_context *pipe = ctx->pipe; + struct pipe_framebuffer_state fb; + struct pipe_surface *dst_surf = pipe->screen->get_tex_surface( + pipe->screen, dst->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + + /* drawing dest */ + memset(&fb, 0, sizeof(fb)); + fb.width = dst->x + dst_surf->width; + fb.height = dst->y + dst_surf->height; + fb.nr_cbufs = 1; + fb.cbufs[0] = dst_surf; + { + VGint i; + for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) + fb.cbufs[i] = 0; + } + cso_set_framebuffer(ctx->cso_context, &fb); + + return dst_surf; +} + +static void setup_viewport(struct vg_image *dst) +{ + struct vg_context *ctx = vg_current_context(); + vg_set_viewport(ctx, VEGA_Y0_TOP); +} + +static void setup_blend() +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_blend_state blend; + memset(&blend, 0, sizeof(blend)); + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + if (ctx->state.vg.filter_channel_mask & VG_RED) + blend.colormask |= PIPE_MASK_R; + if (ctx->state.vg.filter_channel_mask & VG_GREEN) + blend.colormask |= PIPE_MASK_G; + if (ctx->state.vg.filter_channel_mask & VG_BLUE) + blend.colormask |= PIPE_MASK_B; + if (ctx->state.vg.filter_channel_mask & VG_ALPHA) + blend.colormask |= PIPE_MASK_A; + blend.blend_enable = 1; + cso_set_blend(ctx->cso_context, &blend); +} + +static void setup_constant_buffer(struct vg_context *ctx, const void *buffer, + VGint param_bytes) +{ + struct pipe_context *pipe = ctx->pipe; + struct pipe_constant_buffer *cbuf = &ctx->filter.buffer; + + /* We always need to get a new buffer, to keep the drivers simple and + * avoid gratuitous rendering synchronization. */ + pipe_buffer_reference(&cbuf->buffer, NULL); + + cbuf->buffer = pipe_buffer_create(pipe->screen, 16, + PIPE_BUFFER_USAGE_CONSTANT, + param_bytes); + + if (cbuf->buffer) { + st_no_flush_pipe_buffer_write(ctx, cbuf->buffer, + 0, param_bytes, buffer); + } + + ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf); +} + +static void setup_samplers(struct vg_context *ctx, struct filter_info *info) +{ + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + struct pipe_texture *textures[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_state sampler[3]; + int num_samplers = 0; + int num_textures = 0; + + samplers[0] = NULL; + samplers[1] = NULL; + samplers[2] = NULL; + samplers[3] = NULL; + textures[0] = NULL; + textures[1] = NULL; + textures[2] = NULL; + textures[3] = NULL; + + memset(&sampler[0], 0, sizeof(struct pipe_sampler_state)); + sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler[0].wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler[0].min_img_filter = PIPE_TEX_MIPFILTER_LINEAR; + sampler[0].mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR; + sampler[0].normalized_coords = 1; + + switch(info->tiling_mode) { + case VG_TILE_FILL: + sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER; + sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER; + memcpy(sampler[0].border_color, + ctx->state.vg.tile_fill_color, + sizeof(VGfloat) * 4); + break; + case VG_TILE_PAD: + sampler[0].wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler[0].wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + break; + case VG_TILE_REPEAT: + sampler[0].wrap_s = PIPE_TEX_WRAP_REPEAT; + sampler[0].wrap_t = PIPE_TEX_WRAP_REPEAT; + break; + case VG_TILE_REFLECT: + sampler[0].wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT; + sampler[0].wrap_t = PIPE_TEX_WRAP_MIRROR_REPEAT; + break; + default: + debug_assert(!"Unknown tiling mode"); + } + + samplers[0] = &sampler[0]; + textures[0] = info->src->texture; + ++num_samplers; + ++num_textures; + + if (info->extra_texture) { + memcpy(&sampler[1], &sampler[0], sizeof(struct pipe_sampler_state)); + samplers[1] = &sampler[1]; + textures[1] = info->extra_texture; + ++num_samplers; + ++num_textures; + } + + + cso_set_samplers(ctx->cso_context, num_samplers, (const struct pipe_sampler_state **)samplers); + cso_set_sampler_textures(ctx->cso_context, num_textures, textures); +} + +static struct vg_shader * setup_color_matrix(struct vg_context *ctx, void *user_data) +{ + struct vg_shader *shader = + shader_create_from_text(ctx->pipe, color_matrix_asm, 200, + PIPE_SHADER_FRAGMENT); + cso_set_fragment_shader_handle(ctx->cso_context, shader->driver); + return shader; +} + +static struct vg_shader * setup_convolution(struct vg_context *ctx, void *user_data) +{ + char buffer[1024]; + VGint num_consts = (VGint)(long)(user_data); + struct vg_shader *shader; + + snprintf(buffer, 1023, convolution_asm, num_consts, num_consts / 2 + 1); + + shader = shader_create_from_text(ctx->pipe, buffer, 200, + PIPE_SHADER_FRAGMENT); + + cso_set_fragment_shader_handle(ctx->cso_context, shader->driver); + return shader; +} + +static struct vg_shader * setup_lookup(struct vg_context *ctx, void *user_data) +{ + struct vg_shader *shader = + shader_create_from_text(ctx->pipe, lookup_asm, + 200, PIPE_SHADER_FRAGMENT); + + cso_set_fragment_shader_handle(ctx->cso_context, shader->driver); + return shader; +} + + +static struct vg_shader * setup_lookup_single(struct vg_context *ctx, void *user_data) +{ + char buffer[1024]; + VGImageChannel channel = (VGImageChannel)(user_data); + struct vg_shader *shader; + + switch(channel) { + case VG_RED: + snprintf(buffer, 1023, lookup_single_asm, "xxxx"); + break; + case VG_GREEN: + snprintf(buffer, 1023, lookup_single_asm, "yyyy"); + break; + case VG_BLUE: + snprintf(buffer, 1023, lookup_single_asm, "zzzz"); + break; + case VG_ALPHA: + snprintf(buffer, 1023, lookup_single_asm, "wwww"); + break; + default: + debug_assert(!"Unknown color channel"); + } + + shader = shader_create_from_text(ctx->pipe, buffer, 200, + PIPE_SHADER_FRAGMENT); + + cso_set_fragment_shader_handle(ctx->cso_context, shader->driver); + return shader; +} + +static void execute_filter(struct vg_context *ctx, + struct filter_info *info) +{ + struct pipe_surface *dst_surf; + struct vg_shader *shader; + + cso_save_framebuffer(ctx->cso_context); + cso_save_fragment_shader(ctx->cso_context); + cso_save_viewport(ctx->cso_context); + cso_save_blend(ctx->cso_context); + cso_save_samplers(ctx->cso_context); + cso_save_sampler_textures(ctx->cso_context); + + dst_surf = setup_framebuffer(info->dst); + setup_viewport(info->dst); + setup_blend(); + setup_constant_buffer(ctx, info->const_buffer, info->const_buffer_len); + shader = info->setup_shader(ctx, info->user_data); + setup_samplers(ctx, info); + + renderer_draw_texture(ctx->renderer, + info->src->texture, + info->dst->x, info->dst->y, + info->dst->x + info->dst->width, + info->dst->y + info->dst->height, + info->dst->x, info->dst->y, + info->dst->x + info->dst->width, + info->dst->y + info->dst->height); + + cso_restore_framebuffer(ctx->cso_context); + cso_restore_fragment_shader(ctx->cso_context); + cso_restore_viewport(ctx->cso_context); + cso_restore_blend(ctx->cso_context); + cso_restore_samplers(ctx->cso_context); + cso_restore_sampler_textures(ctx->cso_context); + + vg_shader_destroy(ctx, shader); + + pipe_surface_reference(&dst_surf, NULL); +} + +void vgColorMatrix(VGImage dst, VGImage src, + const VGfloat * matrix) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *d, *s; + struct filter_info info; + + if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (!matrix || !is_aligned(matrix)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + d = (struct vg_image*)dst; + s = (struct vg_image*)src; + + if (vg_image_overlaps(d, s)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + info.dst = d; + info.src = s; + info.setup_shader = &setup_color_matrix; + info.user_data = NULL; + info.const_buffer = matrix; + info.const_buffer_len = 20 * sizeof(VGfloat); + info.tiling_mode = VG_TILE_PAD; + info.extra_texture = 0; + execute_filter(ctx, &info); +} + +static VGfloat texture_offset(VGfloat width, VGint kernelSize, VGint current, VGint shift) +{ + VGfloat diff = current - shift; + + return diff / width; +} + +void vgConvolve(VGImage dst, VGImage src, + VGint kernelWidth, VGint kernelHeight, + VGint shiftX, VGint shiftY, + const VGshort * kernel, + VGfloat scale, + VGfloat bias, + VGTilingMode tilingMode) +{ + struct vg_context *ctx = vg_current_context(); + VGfloat *buffer; + VGint buffer_len; + VGint i, j; + VGint idx = 0; + struct vg_image *d, *s; + VGint kernel_size = kernelWidth * kernelHeight; + struct filter_info info; + const VGint max_kernel_size = vgGeti(VG_MAX_KERNEL_SIZE); + + if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (kernelWidth <= 0 || kernelHeight <= 0 || + kernelWidth > max_kernel_size || kernelHeight > max_kernel_size) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (!kernel || !is_aligned_to(kernel, 2)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (tilingMode < VG_TILE_FILL || + tilingMode > VG_TILE_REFLECT) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + d = (struct vg_image*)dst; + s = (struct vg_image*)src; + + if (vg_image_overlaps(d, s)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + vg_validate_state(ctx); + + buffer_len = 8 + 2 * 4 * kernel_size; + buffer = (VGfloat*)malloc(buffer_len * sizeof(VGfloat)); + + buffer[0] = 0.f; + buffer[1] = 1.f; + buffer[2] = 2.f; /*unused*/ + buffer[3] = 4.f; /*unused*/ + + buffer[4] = kernelWidth * kernelHeight; + buffer[5] = scale; + buffer[6] = bias; + buffer[7] = 0.f; + + idx = 8; + for (j = 0; j < kernelHeight; ++j) { + for (i = 0; i < kernelWidth; ++i) { + VGint index = j * kernelWidth + i; + VGfloat x, y; + + x = texture_offset(s->width, kernelWidth, i, shiftX); + y = texture_offset(s->height, kernelHeight, j, shiftY); + + buffer[idx + index*4 + 0] = x; + buffer[idx + index*4 + 1] = y; + buffer[idx + index*4 + 2] = 0.f; + buffer[idx + index*4 + 3] = 0.f; + } + } + idx += kernel_size * 4; + + for (j = 0; j < kernelHeight; ++j) { + for (i = 0; i < kernelWidth; ++i) { + /* transpose the kernel */ + VGint index = j * kernelWidth + i; + VGint kindex = (kernelWidth - i - 1) * kernelHeight + (kernelHeight - j - 1); + buffer[idx + index*4 + 0] = kernel[kindex]; + buffer[idx + index*4 + 1] = kernel[kindex]; + buffer[idx + index*4 + 2] = kernel[kindex]; + buffer[idx + index*4 + 3] = kernel[kindex]; + } + } + + info.dst = d; + info.src = s; + info.setup_shader = &setup_convolution; + info.user_data = (void*)(long)(buffer_len/4); + info.const_buffer = buffer; + info.const_buffer_len = buffer_len * sizeof(VGfloat); + info.tiling_mode = tilingMode; + info.extra_texture = 0; + execute_filter(ctx, &info); + + free(buffer); +} + +void vgSeparableConvolve(VGImage dst, VGImage src, + VGint kernelWidth, + VGint kernelHeight, + VGint shiftX, VGint shiftY, + const VGshort * kernelX, + const VGshort * kernelY, + VGfloat scale, + VGfloat bias, + VGTilingMode tilingMode) +{ + struct vg_context *ctx = vg_current_context(); + VGshort *kernel; + VGint i, j, idx = 0; + const VGint max_kernel_size = vgGeti(VG_MAX_SEPARABLE_KERNEL_SIZE); + + if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (kernelWidth <= 0 || kernelHeight <= 0 || + kernelWidth > max_kernel_size || kernelHeight > max_kernel_size) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (!kernelX || !kernelY || + !is_aligned_to(kernelX, 2) || !is_aligned_to(kernelY, 2)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (tilingMode < VG_TILE_FILL || + tilingMode > VG_TILE_REFLECT) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + kernel = malloc(sizeof(VGshort)*kernelWidth*kernelHeight); + for (i = 0; i < kernelWidth; ++i) { + for (j = 0; j < kernelHeight; ++j) { + kernel[idx] = kernelX[i] * kernelY[j]; + ++idx; + } + } + vgConvolve(dst, src, kernelWidth, kernelHeight, shiftX, shiftY, + kernel, scale, bias, tilingMode); + free(kernel); +} + +static INLINE VGfloat compute_gaussian_componenet(VGfloat x, VGfloat y, + VGfloat stdDeviationX, + VGfloat stdDeviationY) +{ + VGfloat mult = 1 / ( 2 * M_PI * stdDeviationX * stdDeviationY); + VGfloat e = exp( - ( pow(x, 2)/(2*pow(stdDeviationX, 2)) + + pow(y, 2)/(2*pow(stdDeviationY, 2)) ) ); + return mult * e; +} + +static INLINE VGint compute_kernel_size(VGfloat deviation) +{ + VGint size = ceil(2.146 * deviation); + if (size > 11) + return 11; + return size; +} + +static void compute_gaussian_kernel(VGfloat *kernel, + VGint width, VGint height, + VGfloat stdDeviationX, + VGfloat stdDeviationY) +{ + VGint i, j; + VGfloat scale = 0.0f; + + for (j = 0; j < height; ++j) { + for (i = 0; i < width; ++i) { + VGint idx = (height - j -1) * width + (width - i -1); + kernel[idx] = compute_gaussian_componenet(i-(ceil(width/2))-1, + j-ceil(height/2)-1, + stdDeviationX, stdDeviationY); + scale += kernel[idx]; + } + } + + for (j = 0; j < height; ++j) { + for (i = 0; i < width; ++i) { + VGint idx = j * width + i; + kernel[idx] /= scale; + } + } +} + +void vgGaussianBlur(VGImage dst, VGImage src, + VGfloat stdDeviationX, + VGfloat stdDeviationY, + VGTilingMode tilingMode) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *d, *s; + VGfloat *buffer, *kernel; + VGint kernel_width, kernel_height, kernel_size; + VGint buffer_len; + VGint idx, i, j; + struct filter_info info; + + if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (stdDeviationX <= 0 || stdDeviationY <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (tilingMode < VG_TILE_FILL || + tilingMode > VG_TILE_REFLECT) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + d = (struct vg_image*)dst; + s = (struct vg_image*)src; + + if (vg_image_overlaps(d, s)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + kernel_width = compute_kernel_size(stdDeviationX); + kernel_height = compute_kernel_size(stdDeviationY); + kernel_size = kernel_width * kernel_height; + kernel = malloc(sizeof(VGfloat)*kernel_size); + compute_gaussian_kernel(kernel, kernel_width, kernel_height, + stdDeviationX, stdDeviationY); + + buffer_len = 8 + 2 * 4 * kernel_size; + buffer = (VGfloat*)malloc(buffer_len * sizeof(VGfloat)); + + buffer[0] = 0.f; + buffer[1] = 1.f; + buffer[2] = 2.f; /*unused*/ + buffer[3] = 4.f; /*unused*/ + + buffer[4] = kernel_width * kernel_height; + buffer[5] = 1.f;/*scale*/ + buffer[6] = 0.f;/*bias*/ + buffer[7] = 0.f; + + idx = 8; + for (j = 0; j < kernel_height; ++j) { + for (i = 0; i < kernel_width; ++i) { + VGint index = j * kernel_width + i; + VGfloat x, y; + + x = texture_offset(s->width, kernel_width, i, kernel_width/2); + y = texture_offset(s->height, kernel_height, j, kernel_height/2); + + buffer[idx + index*4 + 0] = x; + buffer[idx + index*4 + 1] = y; + buffer[idx + index*4 + 2] = 0.f; + buffer[idx + index*4 + 3] = 0.f; + } + } + idx += kernel_size * 4; + + for (j = 0; j < kernel_height; ++j) { + for (i = 0; i < kernel_width; ++i) { + /* transpose the kernel */ + VGint index = j * kernel_width + i; + VGint kindex = (kernel_width - i - 1) * kernel_height + (kernel_height - j - 1); + buffer[idx + index*4 + 0] = kernel[kindex]; + buffer[idx + index*4 + 1] = kernel[kindex]; + buffer[idx + index*4 + 2] = kernel[kindex]; + buffer[idx + index*4 + 3] = kernel[kindex]; + } + } + + info.dst = d; + info.src = s; + info.setup_shader = &setup_convolution; + info.user_data = (void*)(long)(buffer_len/4); + info.const_buffer = buffer; + info.const_buffer_len = buffer_len * sizeof(VGfloat); + info.tiling_mode = tilingMode; + info.extra_texture = 0; + execute_filter(ctx, &info); + + free(buffer); + free(kernel); +} + +void vgLookup(VGImage dst, VGImage src, + const VGubyte * redLUT, + const VGubyte * greenLUT, + const VGubyte * blueLUT, + const VGubyte * alphaLUT, + VGboolean outputLinear, + VGboolean outputPremultiplied) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *d, *s; + VGuint color_data[256]; + VGint i; + struct pipe_texture *lut_texture; + VGfloat buffer[4]; + struct filter_info info; + + if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (!redLUT || !greenLUT || !blueLUT || !alphaLUT) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + d = (struct vg_image*)dst; + s = (struct vg_image*)src; + + if (vg_image_overlaps(d, s)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + for (i = 0; i < 256; ++i) { + color_data[i] = blueLUT[i] << 24 | greenLUT[i] << 16 | + redLUT[i] << 8 | alphaLUT[i]; + } + lut_texture = create_texture_1d(ctx, color_data, 255); + + buffer[0] = 0.f; + buffer[1] = 0.f; + buffer[2] = 1.f; + buffer[3] = 1.f; + + info.dst = d; + info.src = s; + info.setup_shader = &setup_lookup; + info.user_data = NULL; + info.const_buffer = buffer; + info.const_buffer_len = 4 * sizeof(VGfloat); + info.tiling_mode = VG_TILE_PAD; + info.extra_texture = lut_texture; + + execute_filter(ctx, &info); + + pipe_texture_reference(&lut_texture, NULL); +} + +void vgLookupSingle(VGImage dst, VGImage src, + const VGuint * lookupTable, + VGImageChannel sourceChannel, + VGboolean outputLinear, + VGboolean outputPremultiplied) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *d, *s; + struct pipe_texture *lut_texture; + VGfloat buffer[4]; + struct filter_info info; + VGuint color_data[256]; + VGint i; + + if (dst == VG_INVALID_HANDLE || src == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (!lookupTable || !is_aligned(lookupTable)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (sourceChannel != VG_RED && sourceChannel != VG_GREEN && + sourceChannel != VG_BLUE && sourceChannel != VG_ALPHA) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + d = (struct vg_image*)dst; + s = (struct vg_image*)src; + + if (vg_image_overlaps(d, s)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + for (i = 0; i < 256; ++i) { + VGuint rgba = lookupTable[i]; + VGubyte blue, green, red, alpha; + red = (rgba & 0xff000000)>>24; + green = (rgba & 0x00ff0000)>>16; + blue = (rgba & 0x0000ff00)>> 8; + alpha = (rgba & 0x000000ff)>> 0; + color_data[i] = blue << 24 | green << 16 | + red << 8 | alpha; + } + lut_texture = create_texture_1d(ctx, color_data, 256); + + buffer[0] = 0.f; + buffer[1] = 0.f; + buffer[2] = 1.f; + buffer[3] = 1.f; + + info.dst = d; + info.src = s; + info.setup_shader = &setup_lookup_single; + info.user_data = (void*)sourceChannel; + info.const_buffer = buffer; + info.const_buffer_len = 4 * sizeof(VGfloat); + info.tiling_mode = VG_TILE_PAD; + info.extra_texture = lut_texture; + + execute_filter(ctx, &info); + + pipe_texture_reference(&lut_texture, NULL); +} diff --git a/src/gallium/state_trackers/vega/api_images.c b/src/gallium/state_trackers/vega/api_images.c new file mode 100644 index 0000000000..c437553bc2 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_images.c @@ -0,0 +1,489 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "image.h" + +#include "VG/openvg.h" + +#include "vg_context.h" +#include "vg_translate.h" +#include "api_consts.h" +#include "image.h" + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_inlines.h" +#include "util/u_blit.h" +#include "util/u_tile.h" +#include "util/u_memory.h" + +static INLINE VGboolean supported_image_format(VGImageFormat format) +{ + switch(format) { + case VG_sRGBX_8888: + case VG_sRGBA_8888: + case VG_sRGBA_8888_PRE: + case VG_sRGB_565: + case VG_sRGBA_5551: + case VG_sRGBA_4444: + case VG_sL_8: + case VG_lRGBX_8888: + case VG_lRGBA_8888: + case VG_lRGBA_8888_PRE: + case VG_lL_8: + case VG_A_8: + case VG_BW_1: +#ifdef OPENVG_VERSION_1_1 + case VG_A_1: + case VG_A_4: +#endif + case VG_sXRGB_8888: + case VG_sARGB_8888: + case VG_sARGB_8888_PRE: + case VG_sARGB_1555: + case VG_sARGB_4444: + case VG_lXRGB_8888: + case VG_lARGB_8888: + case VG_lARGB_8888_PRE: + case VG_sBGRX_8888: + case VG_sBGRA_8888: + case VG_sBGRA_8888_PRE: + case VG_sBGR_565: + case VG_sBGRA_5551: + case VG_sBGRA_4444: + case VG_lBGRX_8888: + case VG_lBGRA_8888: + case VG_lBGRA_8888_PRE: + case VG_sXBGR_8888: + case VG_sABGR_8888: + case VG_sABGR_8888_PRE: + case VG_sABGR_1555: + case VG_sABGR_4444: + case VG_lXBGR_8888: + case VG_lABGR_8888: + case VG_lABGR_8888_PRE: + return VG_TRUE; + default: + return VG_FALSE; + } + return VG_FALSE; +} + +VGImage vgCreateImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality) +{ + struct vg_context *ctx = vg_current_context(); + + if (!supported_image_format(format)) { + vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); + return VG_INVALID_HANDLE; + } + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + if (width > vgGeti(VG_MAX_IMAGE_WIDTH) || + height > vgGeti(VG_MAX_IMAGE_HEIGHT)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + if (width * height > vgGeti(VG_MAX_IMAGE_PIXELS)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + + if (!(allowedQuality & ((VG_IMAGE_QUALITY_NONANTIALIASED | + VG_IMAGE_QUALITY_FASTER | + VG_IMAGE_QUALITY_BETTER)))) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + + return (VGImage)image_create(format, width, height); +} + +void vgDestroyImage(VGImage image) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *img = (struct vg_image *)image; + + if (image == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (!vg_object_is_valid((void*)image, VG_OBJECT_IMAGE)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + image_destroy(img); +} + +void vgClearImage(VGImage image, + VGint x, VGint y, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *img; + + if (image == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + img = (struct vg_image*)image; + + if (x + width < 0 || y + height < 0) + return; + + image_clear(img, x, y, width, height); + +} + +void vgImageSubData(VGImage image, + const void * data, + VGint dataStride, + VGImageFormat dataFormat, + VGint x, VGint y, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *img; + + if (image == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (!supported_image_format(dataFormat)) { + vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); + return; + } + if (width <= 0 || height <= 0 || !data || !is_aligned(data)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + img = (struct vg_image*)(image); + image_sub_data(img, data, dataStride, dataFormat, + x, y, width, height); +} + +void vgGetImageSubData(VGImage image, + void * data, + VGint dataStride, + VGImageFormat dataFormat, + VGint x, VGint y, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *img; + + if (image == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (!supported_image_format(dataFormat)) { + vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); + return; + } + if (width <= 0 || height <= 0 || !data || !is_aligned(data)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + img = (struct vg_image*)image; + image_get_sub_data(img, data, dataStride, dataFormat, + x, y, width, height); +} + +VGImage vgChildImage(VGImage parent, + VGint x, VGint y, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *p; + + if (parent == VG_INVALID_HANDLE || + !vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, (void*)parent) || + !vg_object_is_valid((void*)parent, VG_OBJECT_IMAGE)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return VG_INVALID_HANDLE; + } + if (width <= 0 || height <= 0 || x < 0 || y < 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + p = (struct vg_image *)parent; + if (x > p->width || y > p->height) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + if (x + width > p->width || y + height > p->height) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + + return (VGImage)image_child_image(p, x, y, width, height); +} + +VGImage vgGetParent(VGImage image) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *img; + + if (image == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return VG_INVALID_HANDLE; + } + + img = (struct vg_image*)image; + if (img->parent) + return (VGImage)img->parent; + else + return image; +} + +void vgCopyImage(VGImage dst, VGint dx, VGint dy, + VGImage src, VGint sx, VGint sy, + VGint width, VGint height, + VGboolean dither) +{ + struct vg_context *ctx = vg_current_context(); + + if (src == VG_INVALID_HANDLE || dst == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + vg_validate_state(ctx); + image_copy((struct vg_image*)dst, dx, dy, + (struct vg_image*)src, sx, sy, + width, height, dither); +} + +void vgDrawImage(VGImage image) +{ + struct vg_context *ctx = vg_current_context(); + + if (!ctx) + return; + + if (image == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + vg_validate_state(ctx); + image_draw((struct vg_image*)image); +} + +void vgSetPixels(VGint dx, VGint dy, + VGImage src, VGint sx, VGint sy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + + vg_validate_state(ctx); + + if (src == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + image_set_pixels(dx, dy, (struct vg_image*)src, sx, sy, width, + height); +} + +void vgGetPixels(VGImage dst, VGint dx, VGint dy, + VGint sx, VGint sy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *img; + + if (dst == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + img = (struct vg_image*)dst; + + image_get_pixels(img, dx, dy, + sx, sy, width, height); +} + +void vgWritePixels(const void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint dx, VGint dy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_context *pipe = ctx->pipe; + + if (!supported_image_format(dataFormat)) { + vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); + return; + } + if (!data || !is_aligned(data)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + vg_validate_state(ctx); + { + struct vg_image *img = image_create(dataFormat, width, height); + image_sub_data(img, data, dataStride, dataFormat, 0, 0, + width, height); +#if 0 + struct matrix *matrix = &ctx->state.vg.image_user_to_surface_matrix; + matrix_translate(matrix, dx, dy); + image_draw(img); + matrix_translate(matrix, -dx, -dy); +#else + /* this looks like a better approach */ + image_set_pixels(dx, dy, img, 0, 0, width, height); +#endif + image_destroy(img); + } + /* make sure rendering has completed */ + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); +} + +void vgReadPixels(void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint sx, VGint sy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_context *pipe = ctx->pipe; + struct pipe_screen *screen = pipe->screen; + + struct st_framebuffer *stfb = ctx->draw_buffer; + struct st_renderbuffer *strb = stfb->strb; + struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; + + VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; + VGfloat *df = (VGfloat*)temp; + VGint y = (fb->height - sy) - 1, yStep = -1; + VGint i; + VGubyte *dst = (VGubyte *)data; + VGint xoffset = 0, yoffset = 0; + + if (!supported_image_format(dataFormat)) { + vg_set_error(ctx, VG_UNSUPPORTED_IMAGE_FORMAT_ERROR); + return; + } + if (!data || !is_aligned(data)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + /* make sure rendering has completed */ + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + if (sx < 0) { + xoffset = -sx; + xoffset *= _vega_size_for_format(dataFormat); + width += sx; + sx = 0; + } + if (sy < 0) { + yoffset = -sy; + height += sy; + sy = 0; + y = (fb->height - sy) - 1; + yoffset *= dataStride; + } + + { + struct pipe_transfer *transfer; + + transfer = screen->get_tex_transfer(screen, strb->texture, 0, 0, 0, + PIPE_TRANSFER_READ, + 0, 0, width, height); + + /* Do a row at a time to flip image data vertically */ + for (i = 0; i < height; i++) { +#if 0 + debug_printf("%d-%d == %d\n", sy, height, y); +#endif + pipe_get_tile_rgba(transfer, sx, y, width, 1, df); + y += yStep; + _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, + dst + yoffset + xoffset); + dst += dataStride; + } + + screen->tex_transfer_destroy(transfer); + } +} + +void vgCopyPixels(VGint dx, VGint dy, + VGint sx, VGint sy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; + struct st_renderbuffer *strb = ctx->draw_buffer->strb; + + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + /* do nothing if we copy from outside the fb */ + if (dx >= (VGint)fb->width || dy >= (VGint)fb->height || + sx >= (VGint)fb->width || sy >= (VGint)fb->height) + return; + + vg_validate_state(ctx); + /* make sure rendering has completed */ + vgFinish(); + + vg_copy_surface(ctx, strb->surface, dx, dy, + strb->surface, sx, sy, width, height); +} diff --git a/src/gallium/state_trackers/vega/api_masks.c b/src/gallium/state_trackers/vega/api_masks.c new file mode 100644 index 0000000000..4f9f3dae17 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_masks.c @@ -0,0 +1,373 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "VG/openvg.h" + +#include "mask.h" +#include "renderer.h" + +#include "vg_context.h" +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "pipe/internal/p_winsys_screen.h" /* for winsys->update_buffer */ + +#include "util/u_pack_color.h" +#include "util/u_draw_quad.h" +#include "util/u_memory.h" + + +#define DISABLE_1_1_MASKING 1 + +/** + * Draw a screen-aligned quadrilateral. + * Coords are window coords with y=0=bottom. These coords will be transformed + * by the vertex shader and viewport transform. + */ +static void +draw_clear_quad(struct vg_context *st, + float x0, float y0, float x1, float y1, float z, + const VGfloat color[4]) +{ + struct pipe_context *pipe = st->pipe; + struct pipe_buffer *buf; + VGuint i; + + /* positions */ + st->clear.vertices[0][0][0] = x0; + st->clear.vertices[0][0][1] = y0; + + st->clear.vertices[1][0][0] = x1; + st->clear.vertices[1][0][1] = y0; + + st->clear.vertices[2][0][0] = x1; + st->clear.vertices[2][0][1] = y1; + + st->clear.vertices[3][0][0] = x0; + st->clear.vertices[3][0][1] = y1; + + /* same for all verts: */ + for (i = 0; i < 4; i++) { + st->clear.vertices[i][0][2] = z; + st->clear.vertices[i][0][3] = 1.0; + st->clear.vertices[i][1][0] = color[0]; + st->clear.vertices[i][1][1] = color[1]; + st->clear.vertices[i][1][2] = color[2]; + st->clear.vertices[i][1][3] = color[3]; + } + + + /* put vertex data into vbuf */ + buf = pipe_user_buffer_create(pipe->screen, + st->clear.vertices, + sizeof(st->clear.vertices)); + + + /* draw */ + if (buf) { + util_draw_vertex_buffer(pipe, buf, 0, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ + + pipe_buffer_reference(&buf, NULL); + } +} + +/** + * Do vgClear by drawing a quadrilateral. + */ +static void +clear_with_quad(struct vg_context *st, float x0, float y0, + float width, float height, const VGfloat clear_color[4]) +{ + VGfloat x1, y1; + + vg_validate_state(st); + + x1 = x0 + width; + y1 = y0 + height; + + /* + printf("%s %f,%f %f,%f\n", __FUNCTION__, + x0, y0, + x1, y1); + */ + + if (st->pipe->winsys && st->pipe->winsys->update_buffer) + st->pipe->winsys->update_buffer( st->pipe->winsys, + st->pipe->priv ); + + cso_save_blend(st->cso_context); + cso_save_rasterizer(st->cso_context); + cso_save_fragment_shader(st->cso_context); + cso_save_vertex_shader(st->cso_context); + + /* blend state: RGBA masking */ + { + struct pipe_blend_state blend; + memset(&blend, 0, sizeof(blend)); + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.colormask |= PIPE_MASK_R; + blend.colormask |= PIPE_MASK_G; + blend.colormask |= PIPE_MASK_B; + blend.colormask |= PIPE_MASK_A; + cso_set_blend(st->cso_context, &blend); + } + + cso_set_rasterizer(st->cso_context, &st->clear.raster); + + cso_set_fragment_shader_handle(st->cso_context, st->clear.fs); + cso_set_vertex_shader_handle(st->cso_context, vg_clear_vs(st)); + + /* draw quad matching scissor rect (XXX verify coord round-off) */ + draw_clear_quad(st, x0, y0, x1, y1, 0, clear_color); + + /* Restore pipe state */ + cso_restore_blend(st->cso_context); + cso_restore_rasterizer(st->cso_context); + cso_restore_fragment_shader(st->cso_context); + cso_restore_vertex_shader(st->cso_context); +} + + +void vgMask(VGHandle mask, VGMaskOperation operation, + VGint x, VGint y, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + + if (width <=0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (operation < VG_CLEAR_MASK || operation > VG_SUBTRACT_MASK) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + + vg_validate_state(ctx); + + if (operation == VG_CLEAR_MASK) { + mask_fill(x, y, width, height, 0.f); + } else if (operation == VG_FILL_MASK) { + mask_fill(x, y, width, height, 1.f); + } else if (vg_object_is_valid((void*)mask, VG_OBJECT_IMAGE)) { + struct vg_image *image = (struct vg_image *)mask; + mask_using_image(image, operation, x, y, width, height); + } else if (vg_object_is_valid((void*)mask, VG_OBJECT_MASK)) { +#if DISABLE_1_1_MASKING + return; +#else + struct vg_mask_layer *layer = (struct vg_mask_layer *)mask; + mask_using_layer(layer, operation, x, y, width, height); +#endif + } else { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + } +} + +void vgClear(VGint x, VGint y, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_framebuffer_state *fb; + + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + vg_validate_state(ctx); +#if 0 + debug_printf("Clear [%d, %d, %d, %d] with [%f, %f, %f, %f]\n", + x, y, width, height, + ctx->state.vg.clear_color[0], + ctx->state.vg.clear_color[1], + ctx->state.vg.clear_color[2], + ctx->state.vg.clear_color[3]); +#endif + + fb = &ctx->state.g3d.fb; + /* check for a whole surface clear */ + if (!ctx->state.vg.scissoring && + (x == 0 && y == 0 && width == fb->width && height == fb->height)) { + ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_COLOR | PIPE_CLEAR_DEPTHSTENCIL, + ctx->state.vg.clear_color, 1., 0); + } else { + clear_with_quad(ctx, x, y, width, height, ctx->state.vg.clear_color); + } +} + + +#ifdef OPENVG_VERSION_1_1 + + +void vgRenderToMask(VGPath path, + VGbitfield paintModes, + VGMaskOperation operation) +{ + struct vg_context *ctx = vg_current_context(); + + if (path == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (!paintModes || (paintModes&(~(VG_STROKE_PATH|VG_FILL_PATH)))) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (operation < VG_CLEAR_MASK || + operation > VG_SUBTRACT_MASK) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (!vg_object_is_valid((void*)path, VG_OBJECT_PATH)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + +#if DISABLE_1_1_MASKING + return; +#endif + + vg_validate_state(ctx); + + mask_render_to((struct path *)path, paintModes, operation); +} + +VGMaskLayer vgCreateMaskLayer(VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + + if (width <= 0 || height <= 0 || + width > vgGeti(VG_MAX_IMAGE_WIDTH) || + height > vgGeti(VG_MAX_IMAGE_HEIGHT)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + + return (VGMaskLayer)mask_layer_create(width, height); +} + +void vgDestroyMaskLayer(VGMaskLayer maskLayer) +{ + struct vg_mask_layer *mask = 0; + struct vg_context *ctx = vg_current_context(); + + if (maskLayer == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (!vg_object_is_valid((void*)maskLayer, VG_OBJECT_MASK)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + mask = (struct vg_mask_layer *)maskLayer; + mask_layer_destroy(mask); +} + +void vgFillMaskLayer(VGMaskLayer maskLayer, + VGint x, VGint y, + VGint width, VGint height, + VGfloat value) +{ + struct vg_mask_layer *mask = 0; + struct vg_context *ctx = vg_current_context(); + + if (maskLayer == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (value < 0 || value > 1) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (x < 0 || y < 0 || (x + width) < 0 || (y + height) < 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (!vg_object_is_valid((void*)maskLayer, VG_OBJECT_MASK)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + mask = (struct vg_mask_layer*)maskLayer; + + if (x + width > mask_layer_width(mask) || + y + height > mask_layer_height(mask)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + +#if DISABLE_1_1_MASKING + return; +#endif + mask_layer_fill(mask, x, y, width, height, value); +} + +void vgCopyMask(VGMaskLayer maskLayer, + VGint sx, VGint sy, + VGint dx, VGint dy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_mask_layer *mask = 0; + + if (maskLayer == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (!vg_object_is_valid((void*)maskLayer, VG_OBJECT_MASK)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + +#if DISABLE_1_1_MASKING + return; +#endif + + mask = (struct vg_mask_layer*)maskLayer; + mask_copy(mask, sx, sy, dx, dy, width, height); +} + +#endif diff --git a/src/gallium/state_trackers/vega/api_misc.c b/src/gallium/state_trackers/vega/api_misc.c new file mode 100644 index 0000000000..78ba0bc110 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_misc.c @@ -0,0 +1,83 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "VG/openvg.h" + +#include "vg_context.h" + +/* Hardware Queries */ +VGHardwareQueryResult vgHardwareQuery(VGHardwareQueryType key, + VGint setting) +{ + struct vg_context *ctx = vg_current_context(); + + if (key < VG_IMAGE_FORMAT_QUERY || + key > VG_PATH_DATATYPE_QUERY) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_HARDWARE_UNACCELERATED; + } + + if (key == VG_IMAGE_FORMAT_QUERY) { + if (setting < VG_sRGBX_8888 || + setting > VG_lABGR_8888_PRE) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_HARDWARE_UNACCELERATED; + } + } else if (key == VG_PATH_DATATYPE_QUERY) { + if (setting < VG_PATH_DATATYPE_S_8 || + setting > VG_PATH_DATATYPE_F) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_HARDWARE_UNACCELERATED; + } + } + /* we're supposed to accelerate everything */ + return VG_HARDWARE_ACCELERATED; +} + +/* Renderer and Extension Information */ +const VGubyte *vgGetString(VGStringID name) +{ + struct vg_context *ctx = vg_current_context(); + static const VGubyte *vendor = (VGubyte *)"Tungsten Graphics, Inc"; + static const VGubyte *renderer = (VGubyte *)"Vega OpenVG 1.0"; + static const VGubyte *version = (VGubyte *)"1.0"; + + if (!ctx) + return NULL; + + switch(name) { + case VG_VENDOR: + return vendor; + case VG_RENDERER: + return renderer; + case VG_VERSION: + return version; + case VG_EXTENSIONS: + return NULL; + default: + return NULL; + } +} diff --git a/src/gallium/state_trackers/vega/api_paint.c b/src/gallium/state_trackers/vega/api_paint.c new file mode 100644 index 0000000000..dd3ac5bdb0 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_paint.c @@ -0,0 +1,166 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "VG/openvg.h" + +#include "vg_context.h" +#include "paint.h" +#include "image.h" + +VGPaint vgCreatePaint(void) +{ + return (VGPaint) paint_create(vg_current_context()); +} + +void vgDestroyPaint(VGPaint p) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_paint *paint; + + if (p == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + paint = (struct vg_paint *)p; + paint_destroy(paint); +} + +void vgSetPaint(VGPaint paint, VGbitfield paintModes) +{ + struct vg_context *ctx = vg_current_context(); + + if (paint == VG_INVALID_HANDLE) { + /* restore the default */ + paint = (VGPaint)ctx->default_paint; + } else if (!vg_object_is_valid((void*)paint, VG_OBJECT_PAINT)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (!(paintModes & ((VG_FILL_PATH|VG_STROKE_PATH)))) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (paintModes & VG_FILL_PATH) { + ctx->state.vg.fill_paint = (struct vg_paint *)paint; + } + if (paintModes & VG_STROKE_PATH) { + ctx->state.vg.stroke_paint = (struct vg_paint *)paint; + } +} + +VGPaint vgGetPaint(VGPaintMode paintMode) +{ + struct vg_context *ctx = vg_current_context(); + VGPaint paint = VG_INVALID_HANDLE; + + if (paintMode < VG_STROKE_PATH || paintMode > VG_FILL_PATH) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + + if (paintMode == VG_FILL_PATH) + paint = (VGPaint)ctx->state.vg.fill_paint; + else if (paintMode == VG_STROKE_PATH) + paint = (VGPaint)ctx->state.vg.stroke_paint; + + if (paint == (VGPaint)ctx->default_paint) + paint = VG_INVALID_HANDLE; + + return paint; +} + +void vgSetColor(VGPaint paint, VGuint rgba) +{ + struct vg_context *ctx = vg_current_context(); + + if (paint == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (!vg_object_is_valid((void*)paint, VG_OBJECT_PAINT)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + { + struct vg_paint *p = (struct vg_paint *)paint; + paint_set_colori(p, rgba); + } +} + +VGuint vgGetColor(VGPaint paint) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_paint *p; + VGuint rgba = 0; + + if (paint == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return rgba; + } + + if (!vg_object_is_valid((void*)paint, VG_OBJECT_PAINT)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return rgba; + } + p = (struct vg_paint *)paint; + + return paint_colori(p); +} + +void vgPaintPattern(VGPaint paint, VGImage pattern) +{ + struct vg_context *ctx = vg_current_context(); + + if (paint == VG_INVALID_HANDLE || + !vg_context_is_object_valid(ctx, VG_OBJECT_PAINT, (void *)paint)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (pattern == VG_INVALID_HANDLE) { + paint_set_type((struct vg_paint*)paint, VG_PAINT_TYPE_COLOR); + return; + } + + if (!vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, (void *)pattern)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + + if (!vg_object_is_valid((void*)paint, VG_OBJECT_PAINT) || + !vg_object_is_valid((void*)pattern, VG_OBJECT_IMAGE)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + paint_set_pattern((struct vg_paint*)paint, + (struct vg_image*)pattern); +} + diff --git a/src/gallium/state_trackers/vega/api_params.c b/src/gallium/state_trackers/vega/api_params.c new file mode 100644 index 0000000000..db77fd9cb0 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_params.c @@ -0,0 +1,1673 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "VG/openvg.h" + +#include "vg_context.h" +#include "paint.h" +#include "path.h" +#include "image.h" +#include "matrix.h" +#include "api_consts.h" + +#include "pipe/p_compiler.h" +#include "util/u_pointer.h" +#include "util/u_math.h" + +#include <math.h> + +static INLINE struct vg_state *current_state() +{ + struct vg_context *ctx = vg_current_context(); + if (!ctx) + return 0; + else + return &ctx->state.vg; +} + +static INLINE VGboolean count_in_bounds(VGParamType type, VGint count) +{ + if (count < 0) + return VG_FALSE; + + if (type == VG_SCISSOR_RECTS) + return (!(count % 4) && (count >= 0 || count <= VEGA_MAX_SCISSOR_RECTS * 4)); + else if (type == VG_STROKE_DASH_PATTERN) { + return count <= VEGA_MAX_DASH_COUNT; + } else { + VGint real_count = vgGetVectorSize(type); + return count == real_count; + } +} + +void vgSetf (VGParamType type, VGfloat value) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_state *state = current_state(); + VGErrorCode error = VG_NO_ERROR; + + switch(type) { + case VG_MATRIX_MODE: + case VG_FILL_RULE: + case VG_IMAGE_QUALITY: + case VG_RENDERING_QUALITY: + case VG_BLEND_MODE: + case VG_IMAGE_MODE: +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM: +#endif + case VG_STROKE_CAP_STYLE: + case VG_STROKE_JOIN_STYLE: + case VG_STROKE_DASH_PHASE_RESET: + case VG_MASKING: + case VG_SCISSORING: + case VG_PIXEL_LAYOUT: + case VG_SCREEN_LAYOUT: + case VG_FILTER_FORMAT_LINEAR: + case VG_FILTER_FORMAT_PREMULTIPLIED: + case VG_FILTER_CHANNEL_MASK: + + case VG_MAX_SCISSOR_RECTS: + case VG_MAX_DASH_COUNT: + case VG_MAX_KERNEL_SIZE: + case VG_MAX_SEPARABLE_KERNEL_SIZE: + case VG_MAX_COLOR_RAMP_STOPS: + case VG_MAX_IMAGE_WIDTH: + case VG_MAX_IMAGE_HEIGHT: + case VG_MAX_IMAGE_PIXELS: + case VG_MAX_IMAGE_BYTES: + case VG_MAX_GAUSSIAN_STD_DEVIATION: + case VG_MAX_FLOAT: + vgSeti(type, floor(value)); + return; + break; + case VG_STROKE_LINE_WIDTH: + state->stroke.line_width.f = value; + state->stroke.line_width.i = float_to_int_floor(*((VGuint*)(&value))); + break; + case VG_STROKE_MITER_LIMIT: + state->stroke.miter_limit.f = value; + state->stroke.miter_limit.i = float_to_int_floor(*((VGuint*)(&value))); + break; + case VG_STROKE_DASH_PHASE: + state->stroke.dash_phase.f = value; + state->stroke.dash_phase.i = float_to_int_floor(*((VGuint*)(&value))); + break; + default: + error = VG_ILLEGAL_ARGUMENT_ERROR; + break; + } + vg_set_error(ctx, error); +} + +void vgSeti (VGParamType type, VGint value) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_state *state = current_state(); + VGErrorCode error = VG_NO_ERROR; + + switch(type) { + case VG_MATRIX_MODE: + if (value < VG_MATRIX_PATH_USER_TO_SURFACE || +#ifdef OPENVG_VERSION_1_1 + value > VG_MATRIX_GLYPH_USER_TO_SURFACE) +#else + value > VG_MATRIX_STROKE_PAINT_TO_USER) +#endif + error = VG_ILLEGAL_ARGUMENT_ERROR; + else + state->matrix_mode = value; + break; + case VG_FILL_RULE: + if (value < VG_EVEN_ODD || + value > VG_NON_ZERO) + error = VG_ILLEGAL_ARGUMENT_ERROR; + else + state->fill_rule = value; + break; + case VG_IMAGE_QUALITY: + state->image_quality = value; + break; + case VG_RENDERING_QUALITY: + if (value < VG_RENDERING_QUALITY_NONANTIALIASED || + value > VG_RENDERING_QUALITY_BETTER) + error = VG_ILLEGAL_ARGUMENT_ERROR; + else + state->rendering_quality = value; + break; + case VG_BLEND_MODE: + if (value < VG_BLEND_SRC || + value > VG_BLEND_ADDITIVE) + error = VG_ILLEGAL_ARGUMENT_ERROR; + else { + ctx->state.dirty |= BLEND_DIRTY; + state->blend_mode = value; + } + break; + case VG_IMAGE_MODE: + if (value < VG_DRAW_IMAGE_NORMAL || + value > VG_DRAW_IMAGE_STENCIL) + error = VG_ILLEGAL_ARGUMENT_ERROR; + else + state->image_mode = value; +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM: + state->color_transform = value; +#endif + break; + case VG_STROKE_LINE_WIDTH: + state->stroke.line_width.f = value; + state->stroke.line_width.i = value; + break; + case VG_STROKE_CAP_STYLE: + if (value < VG_CAP_BUTT || + value > VG_CAP_SQUARE) + error = VG_ILLEGAL_ARGUMENT_ERROR; + else + state->stroke.cap_style = value; + break; + case VG_STROKE_JOIN_STYLE: + if (value < VG_JOIN_MITER || + value > VG_JOIN_BEVEL) + error = VG_ILLEGAL_ARGUMENT_ERROR; + else + state->stroke.join_style = value; + break; + case VG_STROKE_MITER_LIMIT: + state->stroke.miter_limit.f = value; + state->stroke.miter_limit.i = value; + break; + case VG_STROKE_DASH_PHASE: + state->stroke.dash_phase.f = value; + state->stroke.dash_phase.i = value; + break; + case VG_STROKE_DASH_PHASE_RESET: + state->stroke.dash_phase_reset = value; + break; + case VG_MASKING: + state->masking = value; + break; + case VG_SCISSORING: + state->scissoring = value; + ctx->state.dirty |= DEPTH_STENCIL_DIRTY; + break; + case VG_PIXEL_LAYOUT: + if (value < VG_PIXEL_LAYOUT_UNKNOWN || + value > VG_PIXEL_LAYOUT_BGR_HORIZONTAL) + error = VG_ILLEGAL_ARGUMENT_ERROR; + else + state->pixel_layout = value; + break; + case VG_SCREEN_LAYOUT: + /* read only ignore */ + break; + case VG_FILTER_FORMAT_LINEAR: + state->filter_format_linear = value; + break; + case VG_FILTER_FORMAT_PREMULTIPLIED: + state->filter_format_premultiplied = value; + break; + case VG_FILTER_CHANNEL_MASK: + state->filter_channel_mask = value; + break; + + case VG_MAX_SCISSOR_RECTS: + case VG_MAX_DASH_COUNT: + case VG_MAX_KERNEL_SIZE: + case VG_MAX_SEPARABLE_KERNEL_SIZE: + case VG_MAX_COLOR_RAMP_STOPS: + case VG_MAX_IMAGE_WIDTH: + case VG_MAX_IMAGE_HEIGHT: + case VG_MAX_IMAGE_PIXELS: + case VG_MAX_IMAGE_BYTES: + case VG_MAX_GAUSSIAN_STD_DEVIATION: + case VG_MAX_FLOAT: + /* read only ignore */ + break; + default: + error = VG_ILLEGAL_ARGUMENT_ERROR; + break; + } + vg_set_error(ctx, error); +} + +void vgSetfv(VGParamType type, VGint count, + const VGfloat * values) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_state *state = current_state(); + VGErrorCode error = VG_NO_ERROR; + + if ((count && !values) || !count_in_bounds(type, count) || !is_aligned(values)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + switch(type) { + case VG_MATRIX_MODE: + case VG_FILL_RULE: + case VG_IMAGE_QUALITY: + case VG_RENDERING_QUALITY: + case VG_BLEND_MODE: + case VG_IMAGE_MODE: +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM: +#endif + case VG_STROKE_CAP_STYLE: + case VG_STROKE_JOIN_STYLE: + case VG_STROKE_DASH_PHASE_RESET: + case VG_MASKING: + case VG_SCISSORING: + case VG_PIXEL_LAYOUT: + case VG_SCREEN_LAYOUT: + case VG_FILTER_FORMAT_LINEAR: + case VG_FILTER_FORMAT_PREMULTIPLIED: + case VG_FILTER_CHANNEL_MASK: + vgSeti(type, floor(values[0])); + return; + break; + case VG_SCISSOR_RECTS: { + VGint i; + VGuint *x = (VGuint*)values; + for (i = 0; i < count; ++i) { + state->scissor_rects[i].f = values[i]; + state->scissor_rects[i].i = float_to_int_floor(x[i]); + } + state->scissor_rects_num = count / 4; + ctx->state.dirty |= DEPTH_STENCIL_DIRTY; + } + break; +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM_VALUES: { + VGint i; + for (i = 0; i < count; ++i) { + state->color_transform_values[i] = values[i]; + } + } + break; +#endif + case VG_STROKE_LINE_WIDTH: + state->stroke.line_width.f = values[0]; + state->stroke.line_width.i = float_to_int_floor(*((VGuint*)(values))); + break; + case VG_STROKE_MITER_LIMIT: + state->stroke.miter_limit.f = values[0]; + state->stroke.miter_limit.i = float_to_int_floor(*((VGuint*)(values))); + break; + case VG_STROKE_DASH_PATTERN: { + int i; + for (i = 0; i < count; ++i) { + state->stroke.dash_pattern[i].f = values[i]; + state->stroke.dash_pattern[i].i = + float_to_int_floor(*((VGuint*)(values + i))); + } + state->stroke.dash_pattern_num = count; + } + break; + case VG_STROKE_DASH_PHASE: + state->stroke.dash_phase.f = values[0]; + state->stroke.dash_phase.i = float_to_int_floor(*((VGuint*)(values))); + break; + case VG_TILE_FILL_COLOR: + state->tile_fill_color[0] = values[0]; + state->tile_fill_color[1] = values[1]; + state->tile_fill_color[2] = values[2]; + state->tile_fill_color[3] = values[3]; + + state->tile_fill_colori[0] = float_to_int_floor(*((VGuint*)(values + 0))); + state->tile_fill_colori[1] = float_to_int_floor(*((VGuint*)(values + 1))); + state->tile_fill_colori[2] = float_to_int_floor(*((VGuint*)(values + 2))); + state->tile_fill_colori[3] = float_to_int_floor(*((VGuint*)(values + 3))); + break; + case VG_CLEAR_COLOR: + state->clear_color[0] = values[0]; + state->clear_color[1] = values[1]; + state->clear_color[2] = values[2]; + state->clear_color[3] = values[3]; + + state->clear_colori[0] = float_to_int_floor(*((VGuint*)(values + 0))); + state->clear_colori[1] = float_to_int_floor(*((VGuint*)(values + 1))); + state->clear_colori[2] = float_to_int_floor(*((VGuint*)(values + 2))); + state->clear_colori[3] = float_to_int_floor(*((VGuint*)(values + 3))); + break; +#ifdef OPENVG_VERSION_1_1 + case VG_GLYPH_ORIGIN: + state->glyph_origin[0].f = values[0]; + state->glyph_origin[1].f = values[1]; + + state->glyph_origin[0].i = float_to_int_floor(*((VGuint*)(values + 0))); + state->glyph_origin[1].i = float_to_int_floor(*((VGuint*)(values + 1))); + break; +#endif + + case VG_MAX_SCISSOR_RECTS: + case VG_MAX_DASH_COUNT: + case VG_MAX_KERNEL_SIZE: + case VG_MAX_SEPARABLE_KERNEL_SIZE: + case VG_MAX_COLOR_RAMP_STOPS: + case VG_MAX_IMAGE_WIDTH: + case VG_MAX_IMAGE_HEIGHT: + case VG_MAX_IMAGE_PIXELS: + case VG_MAX_IMAGE_BYTES: + case VG_MAX_GAUSSIAN_STD_DEVIATION: + case VG_MAX_FLOAT: + break; + default: + error = VG_ILLEGAL_ARGUMENT_ERROR; + break; + } + vg_set_error(ctx, error); +} + +void vgSetiv(VGParamType type, VGint count, + const VGint * values) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_state *state = current_state(); + + if ((count && !values) || !count_in_bounds(type, count) || !is_aligned(values)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + switch(type) { + case VG_MATRIX_MODE: + case VG_FILL_RULE: + case VG_IMAGE_QUALITY: + case VG_RENDERING_QUALITY: + case VG_BLEND_MODE: + case VG_IMAGE_MODE: +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM: +#endif + case VG_STROKE_CAP_STYLE: + case VG_STROKE_JOIN_STYLE: + case VG_STROKE_DASH_PHASE_RESET: + case VG_MASKING: + case VG_SCISSORING: + case VG_PIXEL_LAYOUT: + case VG_SCREEN_LAYOUT: + case VG_FILTER_FORMAT_LINEAR: + case VG_FILTER_FORMAT_PREMULTIPLIED: + case VG_FILTER_CHANNEL_MASK: + vgSeti(type, values[0]); + return; + break; + case VG_SCISSOR_RECTS: { + VGint i; + for (i = 0; i < count; ++i) { + state->scissor_rects[i].i = values[i]; + state->scissor_rects[i].f = values[i]; + } + state->scissor_rects_num = count / 4; + ctx->state.dirty |= DEPTH_STENCIL_DIRTY; + } + break; +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM_VALUES: { + VGint i; + for (i = 0; i < count; ++i) { + state->color_transform_values[i] = values[i]; + } + } + break; +#endif + case VG_STROKE_LINE_WIDTH: + state->stroke.line_width.f = values[0]; + state->stroke.line_width.i = values[0]; + break; + case VG_STROKE_MITER_LIMIT: + state->stroke.miter_limit.f = values[0]; + state->stroke.miter_limit.i = values[0]; + break; + case VG_STROKE_DASH_PATTERN: { + int i; + for (i = 0; i < count; ++i) { + state->stroke.dash_pattern[i].f = values[i]; + state->stroke.dash_pattern[i].i = values[i]; + } + state->stroke.dash_pattern_num = count; + } + break; + case VG_STROKE_DASH_PHASE: + state->stroke.dash_phase.f = values[0]; + state->stroke.dash_phase.i = values[0]; + break; + case VG_TILE_FILL_COLOR: + state->tile_fill_color[0] = values[0]; + state->tile_fill_color[1] = values[1]; + state->tile_fill_color[2] = values[2]; + state->tile_fill_color[3] = values[3]; + + state->tile_fill_colori[0] = values[0]; + state->tile_fill_colori[1] = values[1]; + state->tile_fill_colori[2] = values[2]; + state->tile_fill_colori[3] = values[3]; + break; + case VG_CLEAR_COLOR: + state->clear_color[0] = values[0]; + state->clear_color[1] = values[1]; + state->clear_color[2] = values[2]; + state->clear_color[3] = values[3]; + + state->clear_colori[0] = values[0]; + state->clear_colori[1] = values[1]; + state->clear_colori[2] = values[2]; + state->clear_colori[3] = values[3]; + break; +#ifdef OPENVG_VERSION_1_1 + case VG_GLYPH_ORIGIN: + state->glyph_origin[0].f = values[0]; + state->glyph_origin[1].f = values[1]; + state->glyph_origin[0].i = values[0]; + state->glyph_origin[1].i = values[1]; + break; +#endif + + case VG_MAX_SCISSOR_RECTS: + case VG_MAX_DASH_COUNT: + case VG_MAX_KERNEL_SIZE: + case VG_MAX_SEPARABLE_KERNEL_SIZE: + case VG_MAX_COLOR_RAMP_STOPS: + case VG_MAX_IMAGE_WIDTH: + case VG_MAX_IMAGE_HEIGHT: + case VG_MAX_IMAGE_PIXELS: + case VG_MAX_IMAGE_BYTES: + case VG_MAX_GAUSSIAN_STD_DEVIATION: + case VG_MAX_FLOAT: + break; + + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + } +} + +VGfloat vgGetf(VGParamType type) +{ + struct vg_context *ctx = vg_current_context(); + const struct vg_state *state = current_state(); + VGErrorCode error = VG_NO_ERROR; + VGfloat value = 0.0f; + + switch(type) { + case VG_MATRIX_MODE: + case VG_FILL_RULE: + case VG_IMAGE_QUALITY: + case VG_RENDERING_QUALITY: + case VG_BLEND_MODE: + case VG_IMAGE_MODE: +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM: +#endif + case VG_STROKE_CAP_STYLE: + case VG_STROKE_JOIN_STYLE: + case VG_STROKE_DASH_PHASE_RESET: + case VG_MASKING: + case VG_SCISSORING: + case VG_PIXEL_LAYOUT: + case VG_SCREEN_LAYOUT: + case VG_FILTER_FORMAT_LINEAR: + case VG_FILTER_FORMAT_PREMULTIPLIED: + case VG_FILTER_CHANNEL_MASK: + return vgGeti(type); + break; + case VG_STROKE_LINE_WIDTH: + value = state->stroke.line_width.f; + break; + case VG_STROKE_MITER_LIMIT: + value = state->stroke.miter_limit.f; + break; + case VG_STROKE_DASH_PHASE: + value = state->stroke.dash_phase.f; + break; + + case VG_MAX_SCISSOR_RECTS: + case VG_MAX_DASH_COUNT: + case VG_MAX_KERNEL_SIZE: + case VG_MAX_SEPARABLE_KERNEL_SIZE: + case VG_MAX_COLOR_RAMP_STOPS: + case VG_MAX_IMAGE_WIDTH: + case VG_MAX_IMAGE_HEIGHT: + case VG_MAX_IMAGE_PIXELS: + case VG_MAX_IMAGE_BYTES: + case VG_MAX_GAUSSIAN_STD_DEVIATION: + return vgGeti(type); + break; + case VG_MAX_FLOAT: + value = 1e+10;/*must be at least 1e+10*/ + break; + default: + error = VG_ILLEGAL_ARGUMENT_ERROR; + break; + } + vg_set_error(ctx, error); + return value; +} + +VGint vgGeti(VGParamType type) +{ + const struct vg_state *state = current_state(); + struct vg_context *ctx = vg_current_context(); + VGErrorCode error = VG_NO_ERROR; + VGint value = 0; + + switch(type) { + case VG_MATRIX_MODE: + value = state->matrix_mode; + break; + case VG_FILL_RULE: + value = state->fill_rule; + break; + case VG_IMAGE_QUALITY: + value = state->image_quality; + break; + case VG_RENDERING_QUALITY: + value = state->rendering_quality; + break; + case VG_BLEND_MODE: + value = state->blend_mode; + break; + case VG_IMAGE_MODE: + value = state->image_mode; + break; +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM: + value = state->color_transform; + break; +#endif + case VG_STROKE_LINE_WIDTH: + value = state->stroke.line_width.i; + break; + case VG_STROKE_CAP_STYLE: + value = state->stroke.cap_style; + break; + case VG_STROKE_JOIN_STYLE: + value = state->stroke.join_style; + break; + case VG_STROKE_MITER_LIMIT: + value = state->stroke.miter_limit.i; + break; + case VG_STROKE_DASH_PHASE: + value = state->stroke.dash_phase.i; + break; + case VG_STROKE_DASH_PHASE_RESET: + value = state->stroke.dash_phase_reset; + break; + case VG_MASKING: + value = state->masking; + break; + case VG_SCISSORING: + value = state->scissoring; + break; + case VG_PIXEL_LAYOUT: + value = state->pixel_layout; + break; + case VG_SCREEN_LAYOUT: + value = state->screen_layout; + break; + case VG_FILTER_FORMAT_LINEAR: + value = state->filter_format_linear; + break; + case VG_FILTER_FORMAT_PREMULTIPLIED: + value = state->filter_format_premultiplied; + break; + case VG_FILTER_CHANNEL_MASK: + value = state->filter_channel_mask; + break; + + case VG_MAX_SCISSOR_RECTS: + value = 32; /*must be at least 32*/ + break; + case VG_MAX_DASH_COUNT: + value = 16; /*must be at least 16*/ + break; + case VG_MAX_KERNEL_SIZE: + value = 7; /*must be at least 7*/ + break; + case VG_MAX_SEPARABLE_KERNEL_SIZE: + value = 15; /*must be at least 15*/ + break; + case VG_MAX_COLOR_RAMP_STOPS: + value = 256; /*must be at least 32*/ + break; + case VG_MAX_IMAGE_WIDTH: + value = 2048; + break; + case VG_MAX_IMAGE_HEIGHT: + value = 2048; + break; + case VG_MAX_IMAGE_PIXELS: + value = 2048*2048; + break; + case VG_MAX_IMAGE_BYTES: + value = 2048*2048 * 4; + break; + case VG_MAX_GAUSSIAN_STD_DEVIATION: + value = 128; /*must be at least 128*/ + break; + + case VG_MAX_FLOAT: { + VGfloat val = vgGetf(type); + value = float_to_int_floor(*((VGuint*)&val)); + } + break; + default: + error = VG_ILLEGAL_ARGUMENT_ERROR; + break; + } + vg_set_error(ctx, error); + return value; +} + +VGint vgGetVectorSize(VGParamType type) +{ + struct vg_context *ctx = vg_current_context(); + const struct vg_state *state = current_state(); + switch(type) { + case VG_MATRIX_MODE: + case VG_FILL_RULE: + case VG_IMAGE_QUALITY: + case VG_RENDERING_QUALITY: + case VG_BLEND_MODE: + case VG_IMAGE_MODE: + return 1; + case VG_SCISSOR_RECTS: + return state->scissor_rects_num * 4; +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM: + return 1; + case VG_COLOR_TRANSFORM_VALUES: + return 8; +#endif + case VG_STROKE_LINE_WIDTH: + case VG_STROKE_CAP_STYLE: + case VG_STROKE_JOIN_STYLE: + case VG_STROKE_MITER_LIMIT: + return 1; + case VG_STROKE_DASH_PATTERN: + return state->stroke.dash_pattern_num; + case VG_STROKE_DASH_PHASE: + return 1; + case VG_STROKE_DASH_PHASE_RESET: + return 1; + case VG_TILE_FILL_COLOR: + return 4; + case VG_CLEAR_COLOR: + return 4; +#ifdef OPENVG_VERSION_1_1 + case VG_GLYPH_ORIGIN: + return 2; +#endif + case VG_MASKING: + return 1; + case VG_SCISSORING: + return 1; + case VG_PIXEL_LAYOUT: + return 1; + case VG_SCREEN_LAYOUT: + return 1; + case VG_FILTER_FORMAT_LINEAR: + return 1; + case VG_FILTER_FORMAT_PREMULTIPLIED: + return 1; + case VG_FILTER_CHANNEL_MASK: + return 1; + + case VG_MAX_COLOR_RAMP_STOPS: + return 1; + case VG_MAX_SCISSOR_RECTS: + case VG_MAX_DASH_COUNT: + case VG_MAX_KERNEL_SIZE: + case VG_MAX_SEPARABLE_KERNEL_SIZE: + case VG_MAX_IMAGE_WIDTH: + case VG_MAX_IMAGE_HEIGHT: + case VG_MAX_IMAGE_PIXELS: + case VG_MAX_IMAGE_BYTES: + case VG_MAX_FLOAT: + case VG_MAX_GAUSSIAN_STD_DEVIATION: + return 1; + default: + if (ctx) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return 0; + } +} + +void vgGetfv(VGParamType type, VGint count, + VGfloat * values) +{ + const struct vg_state *state = current_state(); + struct vg_context *ctx = vg_current_context(); + VGint real_count = vgGetVectorSize(type); + + if (!values || count <= 0 || count > real_count || !is_aligned(values)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + switch(type) { + case VG_MATRIX_MODE: + case VG_FILL_RULE: + case VG_IMAGE_QUALITY: + case VG_RENDERING_QUALITY: + case VG_BLEND_MODE: + case VG_IMAGE_MODE: +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM: +#endif + case VG_STROKE_CAP_STYLE: + case VG_STROKE_JOIN_STYLE: + case VG_STROKE_DASH_PHASE_RESET: + case VG_MASKING: + case VG_SCISSORING: + case VG_PIXEL_LAYOUT: + case VG_SCREEN_LAYOUT: + case VG_FILTER_FORMAT_LINEAR: + case VG_FILTER_FORMAT_PREMULTIPLIED: + case VG_FILTER_CHANNEL_MASK: + case VG_MAX_SCISSOR_RECTS: + case VG_MAX_DASH_COUNT: + case VG_MAX_KERNEL_SIZE: + case VG_MAX_SEPARABLE_KERNEL_SIZE: + case VG_MAX_COLOR_RAMP_STOPS: + case VG_MAX_IMAGE_WIDTH: + case VG_MAX_IMAGE_HEIGHT: + case VG_MAX_IMAGE_PIXELS: + case VG_MAX_IMAGE_BYTES: + case VG_MAX_GAUSSIAN_STD_DEVIATION: + values[0] = vgGeti(type); + break; + case VG_MAX_FLOAT: + values[0] = vgGetf(type); + break; + case VG_SCISSOR_RECTS: { + VGint i; + for (i = 0; i < count; ++i) { + values[i] = state->scissor_rects[i].f; + } + } + break; +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM_VALUES: { + memcpy(values, state->color_transform_values, + sizeof(VGfloat) * count); + } + break; +#endif + case VG_STROKE_LINE_WIDTH: + values[0] = state->stroke.line_width.f; + break; + case VG_STROKE_MITER_LIMIT: + values[0] = state->stroke.miter_limit.f; + break; + case VG_STROKE_DASH_PATTERN: { + VGint i; + for (i = 0; i < count; ++i) { + values[i] = state->stroke.dash_pattern[i].f; + } + } + break; + case VG_STROKE_DASH_PHASE: + values[0] = state->stroke.dash_phase.f; + break; + case VG_TILE_FILL_COLOR: + values[0] = state->tile_fill_color[0]; + values[1] = state->tile_fill_color[1]; + values[2] = state->tile_fill_color[2]; + values[3] = state->tile_fill_color[3]; + break; + case VG_CLEAR_COLOR: + values[0] = state->clear_color[0]; + values[1] = state->clear_color[1]; + values[2] = state->clear_color[2]; + values[3] = state->clear_color[3]; + break; +#ifdef OPENVG_VERSION_1_1 + case VG_GLYPH_ORIGIN: + values[0] = state->glyph_origin[0].f; + values[1] = state->glyph_origin[1].f; + break; +#endif + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + } +} + +void vgGetiv(VGParamType type, VGint count, + VGint * values) +{ + const struct vg_state *state = current_state(); + struct vg_context *ctx = vg_current_context(); + VGint real_count = vgGetVectorSize(type); + + if (!values || count <= 0 || count > real_count || !is_aligned(values)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + switch(type) { + case VG_MATRIX_MODE: + case VG_FILL_RULE: + case VG_IMAGE_QUALITY: + case VG_RENDERING_QUALITY: + case VG_BLEND_MODE: + case VG_IMAGE_MODE: +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM: +#endif + case VG_STROKE_CAP_STYLE: + case VG_STROKE_JOIN_STYLE: + case VG_STROKE_DASH_PHASE_RESET: + case VG_MASKING: + case VG_SCISSORING: + case VG_PIXEL_LAYOUT: + case VG_SCREEN_LAYOUT: + case VG_FILTER_FORMAT_LINEAR: + case VG_FILTER_FORMAT_PREMULTIPLIED: + case VG_FILTER_CHANNEL_MASK: + case VG_MAX_SCISSOR_RECTS: + case VG_MAX_DASH_COUNT: + case VG_MAX_KERNEL_SIZE: + case VG_MAX_SEPARABLE_KERNEL_SIZE: + case VG_MAX_COLOR_RAMP_STOPS: + case VG_MAX_IMAGE_WIDTH: + case VG_MAX_IMAGE_HEIGHT: + case VG_MAX_IMAGE_PIXELS: + case VG_MAX_IMAGE_BYTES: + case VG_MAX_GAUSSIAN_STD_DEVIATION: + values[0] = vgGeti(type); + break; + case VG_MAX_FLOAT: { + VGfloat val = vgGetf(type); + values[0] = float_to_int_floor(*((VGuint*)&val)); + } + break; + case VG_SCISSOR_RECTS: { + VGint i; + for (i = 0; i < count; ++i) { + values[i] = state->scissor_rects[i].i; + } + } + break; +#ifdef OPENVG_VERSION_1_1 + case VG_COLOR_TRANSFORM_VALUES: { + VGint i; + VGuint *x = (VGuint*)state->color_transform_values; + for (i = 0; i < count; ++i) { + values[i] = float_to_int_floor(x[i]); + } + } + break; +#endif + case VG_STROKE_LINE_WIDTH: + values[0] = state->stroke.line_width.i; + break; + case VG_STROKE_MITER_LIMIT: + values[0] = state->stroke.miter_limit.i; + break; + case VG_STROKE_DASH_PATTERN: { + VGint i; + for (i = 0; i < count; ++i) { + values[i] = state->stroke.dash_pattern[i].i; + } + } + break; + case VG_STROKE_DASH_PHASE: + values[0] = state->stroke.dash_phase.i; + break; + case VG_TILE_FILL_COLOR: + values[0] = state->tile_fill_colori[0]; + values[1] = state->tile_fill_colori[1]; + values[2] = state->tile_fill_colori[2]; + values[3] = state->tile_fill_colori[3]; + break; + case VG_CLEAR_COLOR: + values[0] = state->clear_colori[0]; + values[1] = state->clear_colori[1]; + values[2] = state->clear_colori[2]; + values[3] = state->clear_colori[3]; + break; +#ifdef OPENVG_VERSION_1_1 + case VG_GLYPH_ORIGIN: + values[0] = state->glyph_origin[0].i; + values[1] = state->glyph_origin[1].i; + break; +#endif + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + } +} + +void vgSetParameterf(VGHandle object, + VGint paramType, + VGfloat value) +{ + struct vg_context *ctx = vg_current_context(); + void *ptr = (void*)object; + + if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + switch(paramType) { + case VG_PAINT_TYPE: + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + case VG_PAINT_PATTERN_TILING_MODE: + vgSetParameteri(object, paramType, floor(value)); + return; + break; + case VG_PAINT_COLOR: + case VG_PAINT_COLOR_RAMP_STOPS: + case VG_PAINT_LINEAR_GRADIENT: + case VG_PAINT_RADIAL_GRADIENT: + /* it's an error if paramType refers to a vector parameter */ + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: { + struct vg_paint *p = (struct vg_paint *)object; + paint_set_color_ramp_premultiplied(p, value); + } + break; + + case VG_PATH_DATATYPE: + case VG_PATH_FORMAT: + case VG_PATH_SCALE: + case VG_PATH_BIAS: + case VG_PATH_NUM_SEGMENTS: + case VG_PATH_NUM_COORDS: + + case VG_IMAGE_FORMAT: + case VG_IMAGE_WIDTH: + case VG_IMAGE_HEIGHT: + +#ifdef OPENVG_VERSION_1_1 + case VG_FONT_NUM_GLYPHS: + /* read only don't produce an error */ + break; +#endif + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + } +} + +void vgSetParameteri(VGHandle object, + VGint paramType, + VGint value) +{ + struct vg_context *ctx = vg_current_context(); + void *ptr = (void*)object; + + if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + switch(paramType) { + case VG_PAINT_TYPE: + if (value < VG_PAINT_TYPE_COLOR || + value > VG_PAINT_TYPE_PATTERN) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + struct vg_paint *paint = (struct vg_paint *)ptr; + paint_set_type(paint, value); + } + break; + case VG_PAINT_COLOR: + case VG_PAINT_COLOR_RAMP_STOPS: + case VG_PAINT_LINEAR_GRADIENT: + case VG_PAINT_RADIAL_GRADIENT: + /* it's an error if paramType refers to a vector parameter */ + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + if (value < VG_COLOR_RAMP_SPREAD_PAD || + value > VG_COLOR_RAMP_SPREAD_REFLECT) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + struct vg_paint *paint = (struct vg_paint *)ptr; + paint_set_spread_mode(paint, value); + } + break; + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: { + struct vg_paint *p = (struct vg_paint *)object; + paint_set_color_ramp_premultiplied(p, value); + } + break; + case VG_PAINT_PATTERN_TILING_MODE: + if (value < VG_TILE_FILL || + value > VG_TILE_REFLECT) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + struct vg_paint *paint = (struct vg_paint *)ptr; + paint_set_pattern_tiling(paint, value); + } + break; + + case VG_PATH_DATATYPE: + case VG_PATH_FORMAT: + case VG_PATH_SCALE: + case VG_PATH_BIAS: + case VG_PATH_NUM_SEGMENTS: + case VG_PATH_NUM_COORDS: + + case VG_IMAGE_FORMAT: + case VG_IMAGE_WIDTH: + case VG_IMAGE_HEIGHT: + +#ifdef OPENVG_VERSION_1_1 + case VG_FONT_NUM_GLYPHS: + /* read only don't produce an error */ + break; +#endif + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } +} + +void vgSetParameterfv(VGHandle object, + VGint paramType, + VGint count, + const VGfloat * values) +{ + struct vg_context *ctx = vg_current_context(); + void *ptr = (void*)object; + VGint real_count = vgGetParameterVectorSize(object, paramType); + + if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (count < 0 || count < real_count || + (values == NULL && count != 0) || + !is_aligned(values)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + switch(paramType) { + case VG_PAINT_TYPE: + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: + case VG_PAINT_PATTERN_TILING_MODE: + if (count != 1) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else + vgSetParameterf(object, paramType, values[0]); + return; + break; + case VG_PAINT_COLOR: { + if (count != 4) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + struct vg_paint *paint = (struct vg_paint *)object; + paint_set_color(paint, values); + } + } + break; + case VG_PAINT_COLOR_RAMP_STOPS: { + if (count && count < 4) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + struct vg_paint *paint = (struct vg_paint *)object; + count = MIN2(count, VEGA_MAX_COLOR_RAMP_STOPS); + paint_set_ramp_stops(paint, values, count); + { + VGint stopsi[VEGA_MAX_COLOR_RAMP_STOPS]; + int i = 0; + for (i = 0; i < count; ++i) { + stopsi[i] = float_to_int_floor(*((VGuint*)(values + i))); + } + paint_set_ramp_stopsi(paint, stopsi, count); + } + } + } + break; + case VG_PAINT_LINEAR_GRADIENT: { + if (count != 4) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + struct vg_paint *paint = (struct vg_paint *)object; + paint_set_linear_gradient(paint, values); + { + VGint vals[4]; + vals[0] = FLT_TO_INT(values[0]); + vals[1] = FLT_TO_INT(values[1]); + vals[2] = FLT_TO_INT(values[2]); + vals[3] = FLT_TO_INT(values[3]); + paint_set_linear_gradienti(paint, vals); + } + } + } + break; + case VG_PAINT_RADIAL_GRADIENT: { + if (count != 5) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + struct vg_paint *paint = (struct vg_paint *)object; + paint_set_radial_gradient(paint, values); + { + VGint vals[5]; + vals[0] = FLT_TO_INT(values[0]); + vals[1] = FLT_TO_INT(values[1]); + vals[2] = FLT_TO_INT(values[2]); + vals[3] = FLT_TO_INT(values[3]); + vals[4] = FLT_TO_INT(values[4]); + paint_set_radial_gradienti(paint, vals); + } + } + } + break; + + case VG_PATH_DATATYPE: + case VG_PATH_FORMAT: + case VG_PATH_SCALE: + case VG_PATH_BIAS: + case VG_PATH_NUM_SEGMENTS: + case VG_PATH_NUM_COORDS: + +#ifdef OPENVG_VERSION_1_1 + case VG_FONT_NUM_GLYPHS: + /* read only don't produce an error */ + break; +#endif + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } +} + +void vgSetParameteriv(VGHandle object, + VGint paramType, + VGint count, + const VGint * values) +{ + struct vg_context *ctx = vg_current_context(); + void *ptr = (void*)object; + VGint real_count = vgGetParameterVectorSize(object, paramType); + + if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (count < 0 || count < real_count || + (values == NULL && count != 0) || + !is_aligned(values)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + switch(paramType) { + case VG_PAINT_TYPE: + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: + case VG_PAINT_PATTERN_TILING_MODE: + if (count != 1) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else + vgSetParameteri(object, paramType, values[0]); + return; + break; + case VG_PAINT_COLOR: { + if (count != 4) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + struct vg_paint *paint = (struct vg_paint *)object; + paint_set_coloriv(paint, values); + } + } + break; + case VG_PAINT_COLOR_RAMP_STOPS: { + if ((count % 5)) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + VGfloat *vals = 0; + int i; + struct vg_paint *paint = (struct vg_paint *)object; + if (count) { + vals = malloc(sizeof(VGfloat)*count); + for (i = 0; i < count; ++i) + vals[i] = values[i]; + } + + paint_set_ramp_stopsi(paint, values, count); + paint_set_ramp_stops(paint, vals, count); + free(vals); + } + } + break; + case VG_PAINT_LINEAR_GRADIENT: { + if (count != 4) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + VGfloat vals[4]; + struct vg_paint *paint = (struct vg_paint *)object; + vals[0] = values[0]; + vals[1] = values[1]; + vals[2] = values[2]; + vals[3] = values[3]; + paint_set_linear_gradient(paint, vals); + paint_set_linear_gradienti(paint, values); + } + } + break; + case VG_PAINT_RADIAL_GRADIENT: { + if (count != 5) + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + else { + VGfloat vals[5]; + struct vg_paint *paint = (struct vg_paint *)object; + vals[0] = values[0]; + vals[1] = values[1]; + vals[2] = values[2]; + vals[3] = values[3]; + vals[4] = values[4]; + paint_set_radial_gradient(paint, vals); + paint_set_radial_gradienti(paint, values); + } + } + break; + case VG_PATH_DATATYPE: + case VG_PATH_FORMAT: + case VG_PATH_SCALE: + case VG_PATH_BIAS: + case VG_PATH_NUM_SEGMENTS: + case VG_PATH_NUM_COORDS: + /* read only don't produce an error */ + break; + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } +} + +VGint vgGetParameterVectorSize(VGHandle object, + VGint paramType) +{ + struct vg_context *ctx = vg_current_context(); + void *ptr = (void*)object; + + if (!ptr || object == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return 0; + } + + switch(paramType) { + case VG_PAINT_TYPE: + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: + case VG_PAINT_PATTERN_TILING_MODE: + return 1; + case VG_PAINT_COLOR: + return 4; + case VG_PAINT_COLOR_RAMP_STOPS: { + struct vg_paint *p = (struct vg_paint *)object; + return paint_num_ramp_stops(p); + } + break; + case VG_PAINT_LINEAR_GRADIENT: + return 4; + case VG_PAINT_RADIAL_GRADIENT: + return 5; + + + case VG_PATH_FORMAT: + case VG_PATH_DATATYPE: + case VG_PATH_SCALE: + case VG_PATH_BIAS: + case VG_PATH_NUM_SEGMENTS: + case VG_PATH_NUM_COORDS: + return 1; + + case VG_IMAGE_FORMAT: + case VG_IMAGE_WIDTH: + case VG_IMAGE_HEIGHT: + return 1; + +#ifdef OPENVG_VERSION_1_1 + case VG_FONT_NUM_GLYPHS: + return 1; +#endif + + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + } + return 0; +} + + +VGfloat vgGetParameterf(VGHandle object, + VGint paramType) +{ + struct vg_context *ctx = vg_current_context(); + void *ptr = (void*)object; + + if (!ptr || object == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return 0; + } + + switch(paramType) { + case VG_PAINT_TYPE: + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: + case VG_PAINT_PATTERN_TILING_MODE: + return vgGetParameteri(object, paramType); + break; + case VG_PAINT_COLOR: + case VG_PAINT_COLOR_RAMP_STOPS: + case VG_PAINT_LINEAR_GRADIENT: + case VG_PAINT_RADIAL_GRADIENT: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + + case VG_PATH_FORMAT: + return VG_PATH_FORMAT_STANDARD; + case VG_PATH_SCALE: { + struct path *p = (struct path*)object; + return path_scale(p); + } + case VG_PATH_BIAS: { + struct path *p = (struct path*)object; + return path_bias(p); + } + case VG_PATH_DATATYPE: + case VG_PATH_NUM_SEGMENTS: + case VG_PATH_NUM_COORDS: + return vgGetParameteri(object, paramType); + break; + + case VG_IMAGE_FORMAT: + case VG_IMAGE_WIDTH: + case VG_IMAGE_HEIGHT: +#ifdef OPENVG_VERSION_1_1 + case VG_FONT_NUM_GLYPHS: + return vgGetParameteri(object, paramType); + break; +#endif + + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + } + return 0; +} + +VGint vgGetParameteri(VGHandle object, + VGint paramType) +{ + struct vg_context *ctx = vg_current_context(); + void *ptr = (void*)object; + + if (!ptr || object == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return 0; + } + + switch(paramType) { + case VG_PAINT_TYPE: { + struct vg_paint *paint = (struct vg_paint *)ptr; + return paint_type(paint); + } + break; + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: { + struct vg_paint *p = (struct vg_paint *)object; + return paint_spread_mode(p); + } + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: { + struct vg_paint *p = (struct vg_paint *)object; + return paint_color_ramp_premultiplied(p); + } + break; + case VG_PAINT_PATTERN_TILING_MODE: { + struct vg_paint *p = (struct vg_paint *)object; + return paint_pattern_tiling(p); + } + break; + case VG_PAINT_COLOR: + case VG_PAINT_COLOR_RAMP_STOPS: + case VG_PAINT_LINEAR_GRADIENT: + case VG_PAINT_RADIAL_GRADIENT: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + + case VG_PATH_FORMAT: + return VG_PATH_FORMAT_STANDARD; + case VG_PATH_SCALE: + case VG_PATH_BIAS: + return vgGetParameterf(object, paramType); + case VG_PATH_DATATYPE: { + struct path *p = (struct path*)object; + return path_datatype(p); + } + case VG_PATH_NUM_SEGMENTS: { + struct path *p = (struct path*)object; + return path_num_segments(p); + } + case VG_PATH_NUM_COORDS: { + struct path *p = (struct path*)object; + return path_num_coords(p); + } + break; + + case VG_IMAGE_FORMAT: { + struct vg_image *img = (struct vg_image*)object; + return img->format; + } + break; + case VG_IMAGE_WIDTH: { + struct vg_image *img = (struct vg_image*)object; + return img->width; + } + break; + case VG_IMAGE_HEIGHT: { + struct vg_image *img = (struct vg_image*)object; + return img->height; + } + break; + +#ifdef OPENVG_VERSION_1_1 + case VG_FONT_NUM_GLYPHS: { + return 1; + } + break; +#endif + + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + } + return 0; +} + +void vgGetParameterfv(VGHandle object, + VGint paramType, + VGint count, + VGfloat * values) +{ + struct vg_context *ctx = vg_current_context(); + void *ptr = (void*)object; + VGint real_count = vgGetParameterVectorSize(object, paramType); + + if (!ptr || object == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (!values || count <= 0 || count > real_count || + !is_aligned(values)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + switch(paramType) { + case VG_PAINT_TYPE: { + struct vg_paint *p = (struct vg_paint *)object; + values[0] = paint_type(p); + } + break; + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: { + struct vg_paint *p = (struct vg_paint *)object; + values[0] = paint_spread_mode(p); + } + break; + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: { + struct vg_paint *p = (struct vg_paint *)object; + values[0] = paint_color_ramp_premultiplied(p); + } + break; + case VG_PAINT_PATTERN_TILING_MODE: { + values[0] = vgGetParameterf(object, paramType); + } + break; + case VG_PAINT_COLOR: { + struct vg_paint *paint = (struct vg_paint *)object; + paint_get_color(paint, values); + } + break; + case VG_PAINT_COLOR_RAMP_STOPS: { + struct vg_paint *paint = (struct vg_paint *)object; + paint_ramp_stops(paint, values, count); + } + break; + case VG_PAINT_LINEAR_GRADIENT: { + struct vg_paint *paint = (struct vg_paint *)object; + paint_linear_gradient(paint, values); + } + break; + case VG_PAINT_RADIAL_GRADIENT: { + struct vg_paint *paint = (struct vg_paint *)object; + paint_radial_gradient(paint, values); + } + break; + + case VG_PATH_FORMAT: + case VG_PATH_DATATYPE: + case VG_PATH_NUM_SEGMENTS: + case VG_PATH_NUM_COORDS: + values[0] = vgGetParameteri(object, paramType); + break; + case VG_PATH_SCALE: + case VG_PATH_BIAS: + values[0] = vgGetParameterf(object, paramType); + break; + + case VG_IMAGE_FORMAT: + case VG_IMAGE_WIDTH: + case VG_IMAGE_HEIGHT: +#ifdef OPENVG_VERSION_1_1 + case VG_FONT_NUM_GLYPHS: + values[0] = vgGetParameteri(object, paramType); + break; +#endif + + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + } +} + +void vgGetParameteriv(VGHandle object, + VGint paramType, + VGint count, + VGint * values) +{ + struct vg_context *ctx = vg_current_context(); + void *ptr = (void*)object; + VGint real_count = vgGetParameterVectorSize(object, paramType); + + if (!ptr || object == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (!values || count <= 0 || count > real_count || + !is_aligned(values)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + switch(paramType) { + case VG_PAINT_TYPE: + case VG_PAINT_COLOR_RAMP_SPREAD_MODE: + case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: + case VG_PAINT_PATTERN_TILING_MODE: +#ifdef OPENVG_VERSION_1_1 + case VG_FONT_NUM_GLYPHS: + values[0] = vgGetParameteri(object, paramType); + break; +#endif + case VG_PAINT_COLOR: { + struct vg_paint *paint = (struct vg_paint *)object; + paint_get_coloriv(paint, values); + } + break; + case VG_PAINT_COLOR_RAMP_STOPS: { + struct vg_paint *paint = (struct vg_paint *)object; + paint_ramp_stopsi(paint, values, count); + } + break; + case VG_PAINT_LINEAR_GRADIENT: { + struct vg_paint *paint = (struct vg_paint *)object; + paint_linear_gradienti(paint, values); + } + break; + case VG_PAINT_RADIAL_GRADIENT: { + struct vg_paint *paint = (struct vg_paint *)object; + paint_radial_gradienti(paint, values); + } + break; + + case VG_PATH_SCALE: + case VG_PATH_BIAS: + values[0] = vgGetParameterf(object, paramType); + break; + case VG_PATH_FORMAT: + case VG_PATH_DATATYPE: + case VG_PATH_NUM_SEGMENTS: + case VG_PATH_NUM_COORDS: + values[0] = vgGetParameteri(object, paramType); + break; + + case VG_IMAGE_FORMAT: + case VG_IMAGE_WIDTH: + case VG_IMAGE_HEIGHT: + values[0] = vgGetParameteri(object, paramType); + break; + + default: + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + break; + } +} diff --git a/src/gallium/state_trackers/vega/api_path.c b/src/gallium/state_trackers/vega/api_path.c new file mode 100644 index 0000000000..a6b7a2bb93 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_path.c @@ -0,0 +1,488 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "VG/openvg.h" + +#include "vg_context.h" +#include "path.h" +#include "polygon.h" +#include "paint.h" + +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "util/u_draw_quad.h" + +VGPath vgCreatePath(VGint pathFormat, + VGPathDatatype datatype, + VGfloat scale, VGfloat bias, + VGint segmentCapacityHint, + VGint coordCapacityHint, + VGbitfield capabilities) +{ + struct vg_context *ctx = vg_current_context(); + + if (pathFormat != VG_PATH_FORMAT_STANDARD) { + vg_set_error(ctx, VG_UNSUPPORTED_PATH_FORMAT_ERROR); + return VG_INVALID_HANDLE; + } + if (datatype < VG_PATH_DATATYPE_S_8 || + datatype > VG_PATH_DATATYPE_F) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + if (!scale) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + + return (VGPath)path_create(datatype, scale, bias, + segmentCapacityHint, coordCapacityHint, + capabilities); +} + +void vgClearPath(VGPath path, VGbitfield capabilities) +{ + struct vg_context *ctx = vg_current_context(); + struct path *p = 0; + + if (path == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + p = (struct path *)path; + path_clear(p, capabilities); +} + +void vgDestroyPath(VGPath p) +{ + struct path *path = 0; + struct vg_context *ctx = vg_current_context(); + + if (p == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + path = (struct path *)p; + path_destroy(path); +} + +void vgRemovePathCapabilities(VGPath path, + VGbitfield capabilities) +{ + struct vg_context *ctx = vg_current_context(); + VGbitfield current; + struct path *p; + + if (path == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + p = (struct path*)path; + current = path_capabilities(p); + path_set_capabilities(p, (current & + (~(capabilities & VG_PATH_CAPABILITY_ALL)))); +} + +VGbitfield vgGetPathCapabilities(VGPath path) +{ + struct vg_context *ctx = vg_current_context(); + struct path *p = 0; + + if (path == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return 0; + } + p = (struct path*)path; + return path_capabilities(p); +} + +void vgAppendPath(VGPath dstPath, VGPath srcPath) +{ + struct vg_context *ctx = vg_current_context(); + struct path *src, *dst; + + if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + src = (struct path *)srcPath; + dst = (struct path *)dstPath; + + if (!(path_capabilities(src) & VG_PATH_CAPABILITY_APPEND_FROM) || + !(path_capabilities(dst) & VG_PATH_CAPABILITY_APPEND_TO)) { + vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); + return; + } + path_append_path(dst, src); +} + +void vgAppendPathData(VGPath dstPath, + VGint numSegments, + const VGubyte * pathSegments, + const void * pathData) +{ + struct vg_context *ctx = vg_current_context(); + struct path *p = 0; + VGint i; + + if (dstPath == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (!pathSegments) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (numSegments <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + for (i = 0; i < numSegments; ++i) { + if (pathSegments[i] < VG_CLOSE_PATH || + pathSegments[i] > VG_LCWARC_TO_REL) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + } + + p = (struct path*)dstPath; + + if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (!(path_capabilities(p)&VG_PATH_CAPABILITY_APPEND_TO)) { + vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); + return; + } + + path_append_data(p, numSegments, pathSegments, pathData); +} + +void vgModifyPathCoords(VGPath dstPath, + VGint startIndex, + VGint numSegments, + const void * pathData) +{ + struct vg_context *ctx = vg_current_context(); + struct path *p = 0; + + if (dstPath == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (startIndex < 0 || numSegments <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + p = (struct path *)dstPath; + + if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (startIndex + numSegments > path_num_segments(p)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (!(path_capabilities(p)&VG_PATH_CAPABILITY_MODIFY)) { + vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); + return; + } + path_modify_coords(p, startIndex, numSegments, pathData); +} + +void vgTransformPath(VGPath dstPath, VGPath srcPath) +{ + struct vg_context *ctx = vg_current_context(); + struct path *src = 0, *dst = 0; + + if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + src = (struct path *)srcPath; + dst = (struct path *)dstPath; + + if (!(path_capabilities(src) & VG_PATH_CAPABILITY_TRANSFORM_FROM) || + !(path_capabilities(dst) & VG_PATH_CAPABILITY_TRANSFORM_TO)) { + vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); + return; + } + path_transform(dst, src); +} + +VGboolean vgInterpolatePath(VGPath dstPath, + VGPath startPath, + VGPath endPath, + VGfloat amount) +{ + struct vg_context *ctx = vg_current_context(); + struct path *start = 0, *dst = 0, *end = 0; + + if (dstPath == VG_INVALID_HANDLE || + startPath == VG_INVALID_HANDLE || + endPath == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return VG_FALSE; + } + dst = (struct path *)dstPath; + start = (struct path *)startPath; + end = (struct path *)endPath; + + if (!(path_capabilities(dst) & VG_PATH_CAPABILITY_INTERPOLATE_TO) || + !(path_capabilities(start) & VG_PATH_CAPABILITY_INTERPOLATE_FROM) || + !(path_capabilities(end) & VG_PATH_CAPABILITY_INTERPOLATE_FROM)) { + vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); + return VG_FALSE; + } + + return path_interpolate(dst, + start, end, amount); +} + +VGfloat vgPathLength(VGPath path, + VGint startSegment, + VGint numSegments) +{ + struct vg_context *ctx = vg_current_context(); + struct path *p = 0; + + if (path == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return -1; + } + if (startSegment < 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return -1; + } + if (numSegments <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return -1; + } + p = (struct path*)path; + + if (!(path_capabilities(p) & VG_PATH_CAPABILITY_PATH_LENGTH)) { + vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); + return -1; + } + if (startSegment + numSegments > path_num_segments(p)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return -1; + } + + return path_length(p, startSegment, numSegments); +} + +void vgPointAlongPath(VGPath path, + VGint startSegment, + VGint numSegments, + VGfloat distance, + VGfloat * x, VGfloat * y, + VGfloat * tangentX, + VGfloat * tangentY) +{ + struct vg_context *ctx = vg_current_context(); + struct path *p = 0; + VGbitfield caps; + + if (path == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (startSegment < 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (numSegments <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (!is_aligned(x) || !is_aligned(y) || + !is_aligned(tangentX) || !is_aligned(tangentY)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + p = (struct path*)path; + + caps = path_capabilities(p); + if (!(caps & VG_PATH_CAPABILITY_POINT_ALONG_PATH) || + !(caps & VG_PATH_CAPABILITY_TANGENT_ALONG_PATH)) { + vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); + return; + } + + if (startSegment + numSegments > path_num_segments(p)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + { + VGfloat point[2], normal[2]; + path_point(p, startSegment, numSegments, distance, + point, normal); + if (x) + *x = point[0]; + if (y) + *y = point[1]; + if (tangentX) + *tangentX = -normal[1]; + if (tangentY) + *tangentY = normal[0]; + } +} + +void vgPathBounds(VGPath path, + VGfloat * minX, + VGfloat * minY, + VGfloat * width, + VGfloat * height) +{ + struct vg_context *ctx = vg_current_context(); + struct path *p = 0; + VGbitfield caps; + + if (path == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (!minX || !minY || !width || !height) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (!is_aligned(minX) || !is_aligned(minY) || + !is_aligned(width) || !is_aligned(height)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + p = (struct path*)path; + + caps = path_capabilities(p); + if (!(caps & VG_PATH_CAPABILITY_PATH_BOUNDS)) { + vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); + return; + } + + path_bounding_rect(p, minX, minY, width, height); +} + +void vgPathTransformedBounds(VGPath path, + VGfloat * minX, + VGfloat * minY, + VGfloat * width, + VGfloat * height) +{ + struct vg_context *ctx = vg_current_context(); + struct path *p = 0; + VGbitfield caps; + + if (path == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (!minX || !minY || !width || !height) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (!is_aligned(minX) || !is_aligned(minY) || + !is_aligned(width) || !is_aligned(height)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + p = (struct path*)path; + + caps = path_capabilities(p); + if (!(caps & VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS)) { + vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); + return; + } + +#if 0 + /* faster, but seems to have precision problems... */ + path_bounding_rect(p, minX, minY, width, height); + if (*width > 0 && *height > 0) { + VGfloat pts[] = {*minX, *minY, + *minX + *width, *minY, + *minX + *width, *minY + *height, + *minX, *minY + *height}; + struct matrix *matrix = &ctx->state.vg.path_user_to_surface_matrix; + VGfloat maxX, maxY; + matrix_map_point(matrix, pts[0], pts[1], pts + 0, pts + 1); + matrix_map_point(matrix, pts[2], pts[3], pts + 2, pts + 3); + matrix_map_point(matrix, pts[4], pts[5], pts + 4, pts + 5); + matrix_map_point(matrix, pts[6], pts[7], pts + 6, pts + 7); + *minX = MIN2(pts[0], MIN2(pts[2], MIN2(pts[4], pts[6]))); + *minY = MIN2(pts[1], MIN2(pts[3], MIN2(pts[5], pts[7]))); + maxX = MAX2(pts[0], MAX2(pts[2], MAX2(pts[4], pts[6]))); + maxY = MAX2(pts[1], MAX2(pts[3], MAX2(pts[5], pts[7]))); + *width = maxX - *minX; + *height = maxY - *minY; + } +#else + { + struct path *dst = path_create(VG_PATH_DATATYPE_F, 1.0, 0, + 0, 0, VG_PATH_CAPABILITY_ALL); + path_transform(dst, p); + path_bounding_rect(dst, minX, minY, width, height); + path_destroy(dst); + } +#endif +} + + +void vgDrawPath(VGPath path, VGbitfield paintModes) +{ + struct vg_context *ctx = vg_current_context(); + + if (path == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + if (!(paintModes & (VG_STROKE_PATH | VG_FILL_PATH))) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (path_is_empty((struct path*)path)) + return; + path_render((struct path*)path, paintModes); +} + diff --git a/src/gallium/state_trackers/vega/api_text.c b/src/gallium/state_trackers/vega/api_text.c new file mode 100644 index 0000000000..d8411cf3e8 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_text.c @@ -0,0 +1,258 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "VG/openvg.h" + +#include "vg_context.h" + +#include "util/u_memory.h" + +#ifdef OPENVG_VERSION_1_1 + +struct vg_font { + struct vg_object base; + + VGint glyph_indices[200]; + VGint num_glyphs; +}; + +VGFont vgCreateFont(VGint glyphCapacityHint) +{ + struct vg_font *font = 0; + struct vg_context *ctx = vg_current_context(); + + if (glyphCapacityHint < 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return VG_INVALID_HANDLE; + } + + font = CALLOC_STRUCT(vg_font); + vg_init_object(&font->base, ctx, VG_OBJECT_FONT); + vg_context_add_object(ctx, VG_OBJECT_FONT, font); + return (VGFont)font; +} + +void vgDestroyFont(VGFont f) +{ + struct vg_font *font = (struct vg_font *)f; + struct vg_context *ctx = vg_current_context(); + + if (f == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + vg_context_remove_object(ctx, VG_OBJECT_FONT, font); + /*free(font);*/ +} + +void vgSetGlyphToPath(VGFont font, + VGuint glyphIndex, + VGPath path, + VGboolean isHinted, + VGfloat glyphOrigin [2], + VGfloat escapement[2]) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_object *pathObj; + struct vg_font *f; + + if (font == VG_INVALID_HANDLE || + !vg_context_is_object_valid(ctx, VG_OBJECT_FONT, (void *)font)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (!glyphOrigin || !escapement || + !is_aligned(glyphOrigin) || !is_aligned(escapement)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (path != VG_INVALID_HANDLE && + !vg_context_is_object_valid(ctx, VG_OBJECT_PATH, (void *)path)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + pathObj = (struct vg_object*)path; + if (pathObj && pathObj->type != VG_OBJECT_PATH) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + + f = (struct vg_font*)font; + f->glyph_indices[f->num_glyphs] = glyphIndex; + ++f->num_glyphs; +} + +void vgSetGlyphToImage(VGFont font, + VGuint glyphIndex, + VGImage image, + VGfloat glyphOrigin [2], + VGfloat escapement[2]) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_object *img_obj; + struct vg_font *f; + + if (font == VG_INVALID_HANDLE || + !vg_context_is_object_valid(ctx, VG_OBJECT_FONT, (void *)font)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (!glyphOrigin || !escapement || + !is_aligned(glyphOrigin) || !is_aligned(escapement)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (image != VG_INVALID_HANDLE && + !vg_context_is_object_valid(ctx, VG_OBJECT_IMAGE, (void *)image)) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + img_obj = (struct vg_object*)image; + if (img_obj && img_obj->type != VG_OBJECT_IMAGE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + f = (struct vg_font*)font; + f->glyph_indices[f->num_glyphs] = glyphIndex; + ++f->num_glyphs; +} + +static INLINE VGboolean font_contains_glyph(struct vg_font *font, + VGuint glyph_index) +{ + VGint i; + for (i = 0; i < font->num_glyphs; ++i) { + if (font->glyph_indices[i] == glyph_index) { + return VG_TRUE; + } + } + return VG_FALSE; +} + +void vgClearGlyph(VGFont font, + VGuint glyphIndex) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_font *f; + VGint i; + + if (font == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (glyphIndex <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + f = (struct vg_font*)font; + if (!font_contains_glyph(f, glyphIndex)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + for (i = 0; i < f->num_glyphs; ++i) { + if (f->glyph_indices[i] == glyphIndex) { + /*FIXME*/ + f->glyph_indices[f->num_glyphs] = 0; + --f->num_glyphs; + return; + } + } +} + +void vgDrawGlyph(VGFont font, + VGuint glyphIndex, + VGbitfield paintModes, + VGboolean allowAutoHinting) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_font *f; + + if (font == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (glyphIndex <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (paintModes & (~(VG_STROKE_PATH|VG_FILL_PATH))) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + f = (struct vg_font*)font; + if (!font_contains_glyph(f, glyphIndex)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } +} + +void vgDrawGlyphs(VGFont font, + VGint glyphCount, + VGuint *glyphIndices, + VGfloat *adjustments_x, + VGfloat *adjustments_y, + VGbitfield paintModes, + VGboolean allowAutoHinting) +{ + struct vg_context *ctx = vg_current_context(); + VGint i; + struct vg_font *f; + + if (font == VG_INVALID_HANDLE) { + vg_set_error(ctx, VG_BAD_HANDLE_ERROR); + return; + } + if (glyphCount <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (!glyphIndices || !is_aligned(glyphIndices)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (!adjustments_x || !is_aligned(adjustments_x) || + !adjustments_y || !is_aligned(adjustments_y)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + if (paintModes & (~(VG_STROKE_PATH|VG_FILL_PATH))) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + f = (struct vg_font*)font; + for (i = 0; i < glyphCount; ++i) { + VGuint glyph_index = glyphIndices[i]; + if (!font_contains_glyph(f, glyph_index)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + } +} + +#endif diff --git a/src/gallium/state_trackers/vega/api_transform.c b/src/gallium/state_trackers/vega/api_transform.c new file mode 100644 index 0000000000..763a5ec415 --- /dev/null +++ b/src/gallium/state_trackers/vega/api_transform.c @@ -0,0 +1,128 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "VG/openvg.h" + +#include "vg_context.h" + +#include "matrix.h" + +void vgLoadIdentity(void) +{ + struct vg_context *ctx = vg_current_context(); + struct matrix *mat = vg_state_matrix(&ctx->state.vg); + matrix_load_identity(mat); +} + +void vgLoadMatrix(const VGfloat * m) +{ + struct vg_context *ctx = vg_current_context(); + struct matrix *mat; + + if (!ctx) + return; + + if (!m || !is_aligned(m)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + mat = vg_state_matrix(&ctx->state.vg); + matrix_init(mat, m); + if (!matrix_is_affine(mat)) { + if (ctx->state.vg.matrix_mode != VG_MATRIX_IMAGE_USER_TO_SURFACE) { + matrix_make_affine(mat); + } + } +} + +void vgGetMatrix(VGfloat * m) +{ + struct vg_context *ctx = vg_current_context(); + struct matrix *mat; + + if (!ctx) + return; + + if (!m || !is_aligned(m)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + mat = vg_state_matrix(&ctx->state.vg); + memcpy(m, mat->m, sizeof(VGfloat)*9); +} + +void vgMultMatrix(const VGfloat * m) +{ + struct vg_context *ctx = vg_current_context(); + struct matrix *dst, src; + + if (!ctx) + return; + + if (!m || !is_aligned(m)) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + matrix_init(&src, m); + dst = vg_state_matrix(&ctx->state.vg); + if (!matrix_is_affine(&src)) { + if (ctx->state.vg.matrix_mode != VG_MATRIX_IMAGE_USER_TO_SURFACE) { + matrix_make_affine(&src); + } + } + matrix_mult(dst, &src); + +} + +void vgTranslate(VGfloat tx, VGfloat ty) +{ + struct vg_context *ctx = vg_current_context(); + struct matrix *dst = vg_state_matrix(&ctx->state.vg); + matrix_translate(dst, tx, ty); +} + +void vgScale(VGfloat sx, VGfloat sy) +{ + struct vg_context *ctx = vg_current_context(); + struct matrix *dst = vg_state_matrix(&ctx->state.vg); + matrix_scale(dst, sx, sy); +} + +void vgShear(VGfloat shx, VGfloat shy) +{ + struct vg_context *ctx = vg_current_context(); + struct matrix *dst = vg_state_matrix(&ctx->state.vg); + matrix_shear(dst, shx, shy); +} + +void vgRotate(VGfloat angle) +{ + struct vg_context *ctx = vg_current_context(); + struct matrix *dst = vg_state_matrix(&ctx->state.vg); + matrix_rotate(dst, angle); +} diff --git a/src/gallium/state_trackers/vega/arc.c b/src/gallium/state_trackers/vega/arc.c new file mode 100644 index 0000000000..e74c7f0334 --- /dev/null +++ b/src/gallium/state_trackers/vega/arc.c @@ -0,0 +1,708 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "arc.h" + +#include "matrix.h" +#include "bezier.h" +#include "polygon.h" +#include "stroker.h" +#include "path.h" + +#include "util/u_debug.h" + +#include <math.h> + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define DEBUG_ARCS 0 + +static const VGfloat two_pi = M_PI * 2; + + +static const double coeffs3Low[2][4][4] = { + { + { 3.85268, -21.229, -0.330434, 0.0127842 }, + { -1.61486, 0.706564, 0.225945, 0.263682 }, + { -0.910164, 0.388383, 0.00551445, 0.00671814 }, + { -0.630184, 0.192402, 0.0098871, 0.0102527 } + }, + { + { -0.162211, 9.94329, 0.13723, 0.0124084 }, + { -0.253135, 0.00187735, 0.0230286, 0.01264 }, + { -0.0695069, -0.0437594, 0.0120636, 0.0163087 }, + { -0.0328856, -0.00926032, -0.00173573, 0.00527385 } + } +}; + +/* coefficients for error estimation + while using cubic Bézier curves for approximation + 1/4 <= b/a <= 1 */ +static const double coeffs3High[2][4][4] = { + { + { 0.0899116, -19.2349, -4.11711, 0.183362 }, + { 0.138148, -1.45804, 1.32044, 1.38474 }, + { 0.230903, -0.450262, 0.219963, 0.414038 }, + { 0.0590565, -0.101062, 0.0430592, 0.0204699 } + }, + { + { 0.0164649, 9.89394, 0.0919496, 0.00760802 }, + { 0.0191603, -0.0322058, 0.0134667, -0.0825018 }, + { 0.0156192, -0.017535, 0.00326508, -0.228157 }, + { -0.0236752, 0.0405821, -0.0173086, 0.176187 } + } +}; + +/* safety factor to convert the "best" error approximation + into a "max bound" error */ +static const double safety3[] = { + 0.001, 4.98, 0.207, 0.0067 +}; + +/* The code below is from the OpenVG 1.1 Spec + * Section 18.4 */ + +/* Given: Points (x0, y0) and (x1, y1) + * Return: TRUE if a solution exists, FALSE otherwise + * Circle centers are written to (cx0, cy0) and (cx1, cy1) + */ +static VGboolean +find_unit_circles(double x0, double y0, double x1, double y1, + double *cx0, double *cy0, + double *cx1, double *cy1) +{ + /* Compute differences and averages */ + double dx = x0 - x1; + double dy = y0 - y1; + double xm = (x0 + x1)/2; + double ym = (y0 + y1)/2; + double dsq, disc, s, sdx, sdy; + + /* Solve for intersecting unit circles */ + dsq = dx*dx + dy*dy; + if (dsq == 0.0) return VG_FALSE; /* Points are coincident */ + disc = 1.0/dsq - 1.0/4.0; + + /* the precision we care about here is around float so if we're + * around the float defined zero then make it official to avoid + * precision problems later on */ + if (floatIsZero(disc)) + disc = 0.0; + + if (disc < 0.0) return VG_FALSE; /* Points are too far apart */ + s = sqrt(disc); + sdx = s*dx; + sdy = s*dy; + *cx0 = xm + sdy; + *cy0 = ym - sdx; + *cx1 = xm - sdy; + *cy1 = ym + sdx; + return VG_TRUE; +} + + +/* Given: Ellipse parameters rh, rv, rot (in degrees), + * endpoints (x0, y0) and (x1, y1) + * Return: TRUE if a solution exists, FALSE otherwise + * Ellipse centers are written to (cx0, cy0) and (cx1, cy1) + */ +static VGboolean +find_ellipses(double rh, double rv, double rot, + double x0, double y0, double x1, double y1, + double *cx0, double *cy0, double *cx1, double *cy1) +{ + double COS, SIN, x0p, y0p, x1p, y1p, pcx0, pcy0, pcx1, pcy1; + /* Convert rotation angle from degrees to radians */ + rot *= M_PI/180.0; + /* Pre-compute rotation matrix entries */ + COS = cos(rot); SIN = sin(rot); + /* Transform (x0, y0) and (x1, y1) into unit space */ + /* using (inverse) rotate, followed by (inverse) scale */ + x0p = (x0*COS + y0*SIN)/rh; + y0p = (-x0*SIN + y0*COS)/rv; + x1p = (x1*COS + y1*SIN)/rh; + y1p = (-x1*SIN + y1*COS)/rv; + if (!find_unit_circles(x0p, y0p, x1p, y1p, + &pcx0, &pcy0, &pcx1, &pcy1)) { + return VG_FALSE; + } + /* Transform back to original coordinate space */ + /* using (forward) scale followed by (forward) rotate */ + pcx0 *= rh; pcy0 *= rv; + pcx1 *= rh; pcy1 *= rv; + *cx0 = pcx0*COS - pcy0*SIN; + *cy0 = pcx0*SIN + pcy0*COS; + *cx1 = pcx1*COS - pcy1*SIN; + *cy1 = pcx1*SIN + pcy1*COS; + return VG_TRUE; +} + +static INLINE VGboolean +try_to_fix_radii(struct arc *arc) +{ + double COS, SIN, rot, x0p, y0p, x1p, y1p; + double dx, dy, dsq, scale; + + /* Convert rotation angle from degrees to radians */ + rot = DEGREES_TO_RADIANS(arc->theta); + + /* Pre-compute rotation matrix entries */ + COS = cos(rot); SIN = sin(rot); + + /* Transform (x0, y0) and (x1, y1) into unit space */ + /* using (inverse) rotate, followed by (inverse) scale */ + x0p = (arc->x1*COS + arc->y1*SIN)/arc->a; + y0p = (-arc->x1*SIN + arc->y1*COS)/arc->b; + x1p = (arc->x2*COS + arc->y2*SIN)/arc->a; + y1p = (-arc->x2*SIN + arc->y2*COS)/arc->b; + /* Compute differences and averages */ + dx = x0p - x1p; + dy = y0p - y1p; + + dsq = dx*dx + dy*dy; +#if 0 + if (dsq <= 0.001) { + debug_printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaa\n"); + } +#endif + scale = 1/(2/sqrt(dsq)); + arc->a *= scale; + arc->b *= scale; + return VG_TRUE; +} + +static INLINE double vector_normalize(double *v) +{ + double sq = v[0] * v[0] + v[1] * v[1]; + return sqrt(sq); +} +static INLINE double vector_orientation(double *v) +{ + double norm = vector_normalize(v); + double cosa = v[0] / norm; + double sina = v[1] / norm; + return (sina>=0 ? acos(cosa) : 2*M_PI - acos(cosa)); +} +static INLINE double vector_dot(double *v0, + double *v1) +{ + return v0[0] * v1[0] + v0[1] * v1[1]; +} + +static INLINE double vector_angles(double *v0, + double *v1) +{ + double dot = vector_dot(v0, v1); + double norm0 = vector_normalize(v0); + double norm1 = vector_normalize(v1); + + return acos(dot / (norm0 * norm1)); +} + +static VGboolean find_angles(struct arc *arc) +{ + double vec0[2], vec1[2]; + double lambda1, lambda2; + double angle; + struct matrix matrix; + + if (floatIsZero(arc->a) || floatIsZero(arc->b)) { + return VG_FALSE; + } + /* map the points to an identity circle */ + matrix_load_identity(&matrix); + matrix_scale(&matrix, 1.f, arc->a/arc->b); + matrix_rotate(&matrix, -arc->theta); + matrix_map_point(&matrix, + arc->x1, arc->y1, + &arc->x1, &arc->y1); + matrix_map_point(&matrix, + arc->x2, arc->y2, + &arc->x2, &arc->y2); + matrix_map_point(&matrix, + arc->cx, arc->cy, + &arc->cx, &arc->cy); + +#if DEBUG_ARCS + debug_printf("Matrix 3 [%f, %f, %f| %f, %f, %f| %f, %f, %f]\n", + matrix.m[0], matrix.m[1], matrix.m[2], + matrix.m[3], matrix.m[4], matrix.m[5], + matrix.m[6], matrix.m[7], matrix.m[8]); + debug_printf("Endpoints [%f, %f], [%f, %f]\n", + arc->x1, arc->y1, arc->x2, arc->y2); +#endif + + vec0[0] = arc->x1 - arc->cx; + vec0[1] = arc->y1 - arc->cy; + vec1[0] = arc->x2 - arc->cx; + vec1[1] = arc->y2 - arc->cy; + +#if DEBUG_ARCS + debug_printf("Vec is [%f, %f], [%f, %f], [%f, %f]\n", + vec0[0], vec0[1], vec1[0], vec1[1], arc->cx, arc->cy); +#endif + + lambda1 = vector_orientation(vec0); + + if (isnan(lambda1)) + lambda1 = 0.f; + + if (arc->type == VG_SCWARC_TO || + arc->type == VG_SCCWARC_TO) + angle = vector_angles(vec0, vec1); + else if (arc->type == VG_LCWARC_TO || + arc->type == VG_LCCWARC_TO) { + angle = 2*M_PI - vector_angles(vec0, vec1); + } else + abort(); + + if (isnan(angle)) + angle = M_PI; + + + if (arc->type == VG_SCWARC_TO || + arc->type == VG_LCWARC_TO) + lambda2 = lambda1 - angle; + else + lambda2 = lambda1 + angle; + +#if DEBUG_ARCS + debug_printf("Angle is %f and (%f, %f)\n", angle, lambda1, lambda2); +#endif + +#if 0 + arc->eta1 = atan2(sin(lambda1) / arc->b, + cos(lambda1) / arc->a); + arc->eta2 = atan2(sin(lambda2) / arc->b, + cos(lambda2) / arc->a); + + /* make sure we have eta1 <= eta2 <= eta1 + 2 PI */ + arc->eta2 -= two_pi * floor((arc->eta2 - arc->eta1) / two_pi); + + /* the preceding correction fails if we have exactly et2 - eta1 = 2 PI + it reduces the interval to zero length */ + if ((lambda2 - lambda1 > M_PI) && (arc->eta2 - arc->eta1 < M_PI)) { + arc->eta2 += 2 * M_PI; + } +#else + arc->eta1 = lambda1; + arc->eta2 = lambda2; +#endif + + return VG_TRUE; +} + +#if DEBUG_ARCS +static void check_endpoints(struct arc *arc) +{ + double x1, y1, x2, y2; + + double a_cos_eta1 = arc->a * cos(arc->eta1); + double b_sin_eta1 = arc->b * sin(arc->eta1); + x1 = arc->cx + a_cos_eta1 * arc->cos_theta - + b_sin_eta1 * arc->sin_theta; + y1 = arc->cy + a_cos_eta1 * arc->sin_theta + + b_sin_eta1 * arc->cos_theta; + + double a_cos_eta2 = arc->a * cos(arc->eta2); + double b_sin_eta2 = arc->b * sin(arc->eta2); + x2 = arc->cx + a_cos_eta2 * arc->cos_theta - + b_sin_eta2 * arc->sin_theta; + y2 = arc->cy + a_cos_eta2 * arc->sin_theta + + b_sin_eta2 * arc->cos_theta; + + debug_printf("Computed (%f, %f), (%f, %f)\n", + x1, y1, x2, y2); + debug_printf("Real (%f, %f), (%f, %f)\n", + arc->x1, arc->y1, + arc->x2, arc->y2); +} +#endif + +void arc_init(struct arc *arc, + VGPathSegment type, + VGfloat x1, VGfloat y1, + VGfloat x2, VGfloat y2, + VGfloat rh, VGfloat rv, + VGfloat rot) +{ + assert(type == VG_SCCWARC_TO || + type == VG_SCWARC_TO || + type == VG_LCCWARC_TO || + type == VG_LCWARC_TO); + arc->type = type; + arc->x1 = x1; + arc->y1 = y1; + arc->x2 = x2; + arc->y2 = y2; + arc->a = rh; + arc->b = rv; + arc->theta = rot; + arc->cos_theta = cos(arc->theta); + arc->sin_theta = sin(arc->theta); + { + double cx0, cy0, cx1, cy1; + double cx, cy; + arc->is_valid = find_ellipses(rh, rv, rot, x1, y1, x2, y2, + &cx0, &cy0, &cx1, &cy1); + + if (!arc->is_valid && try_to_fix_radii(arc)) { + rh = arc->a; + rv = arc->b; + arc->is_valid = + find_ellipses(rh, rv, rot, x1, y1, x2, y2, + &cx0, &cy0, &cx1, &cy1); + } + + if (type == VG_SCWARC_TO || + type == VG_LCCWARC_TO) { + cx = cx1; + cy = cy1; + } else { + cx = cx0; + cy = cy0; + } +#if DEBUG_ARCS + debug_printf("Centers are : (%f, %f) , (%f, %f). Real (%f, %f)\n", + cx0, cy0, cx1, cy1, cx, cy); +#endif + arc->cx = cx; + arc->cy = cy; + if (arc->is_valid) { + arc->is_valid = find_angles(arc); +#if DEBUG_ARCS + check_endpoints(arc); +#endif + /* remap a few points. find_angles requires + * rot in angles, the rest of the code + * will need them in radians. and find_angles + * modifies the center to match an identity + * circle so lets reset it */ + arc->theta = DEGREES_TO_RADIANS(rot); + arc->cos_theta = cos(arc->theta); + arc->sin_theta = sin(arc->theta); + arc->cx = cx; + arc->cy = cy; + } + } +} + +static INLINE double rational_function(double x, const double *c) +{ + return (x * (x * c[0] + c[1]) + c[2]) / (x + c[3]); +} + +static double estimate_error(struct arc *arc, + double etaA, double etaB) +{ + double eta = 0.5 * (etaA + etaB); + + double x = arc->b / arc->a; + double dEta = etaB - etaA; + double cos2 = cos(2 * eta); + double cos4 = cos(4 * eta); + double cos6 = cos(6 * eta); + double c0, c1; + + /* select the right coeficients set according to degree and b/a */ + const double (*coeffs)[4][4]; + const double *safety; + coeffs = (x < 0.25) ? coeffs3Low : coeffs3High; + safety = safety3; + + c0 = rational_function(x, coeffs[0][0]) + + cos2 * rational_function(x, coeffs[0][1]) + + cos4 * rational_function(x, coeffs[0][2]) + + cos6 * rational_function(x, coeffs[0][3]); + + c1 = rational_function(x, coeffs[1][0]) + + cos2 * rational_function(x, coeffs[1][1]) + + cos4 * rational_function(x, coeffs[1][2]) + + cos6 * rational_function(x, coeffs[1][3]); + + return rational_function(x, safety) * arc->a * exp(c0 + c1 * dEta); +} + +struct arc_cb { + void (*move)(struct arc_cb *cb, VGfloat x, VGfloat y); + void (*point)(struct arc_cb *cb, VGfloat x, VGfloat y); + void (*bezier)(struct arc_cb *cb, struct bezier *bezier); + + void *user_data; +}; + +static void cb_null_move(struct arc_cb *cb, VGfloat x, VGfloat y) +{ +} + +static void polygon_point(struct arc_cb *cb, VGfloat x, VGfloat y) +{ + struct polygon *poly = (struct polygon*)cb->user_data; + polygon_vertex_append(poly, x, y); +} + +static void polygon_bezier(struct arc_cb *cb, struct bezier *bezier) +{ + struct polygon *poly = (struct polygon*)cb->user_data; + bezier_add_to_polygon(bezier, poly); +} + +static void stroke_point(struct arc_cb *cb, VGfloat x, VGfloat y) +{ + struct stroker *stroker = (struct stroker*)cb->user_data; + stroker_line_to(stroker, x, y); +} + +static void stroke_curve(struct arc_cb *cb, struct bezier *bezier) +{ + struct stroker *stroker = (struct stroker*)cb->user_data; + stroker_curve_to(stroker, + bezier->x2, bezier->y2, + bezier->x3, bezier->y3, + bezier->x4, bezier->y4); +} + +static void stroke_emit_point(struct arc_cb *cb, VGfloat x, VGfloat y) +{ + struct stroker *stroker = (struct stroker*)cb->user_data; + stroker_emit_line_to(stroker, x, y); +} + +static void stroke_emit_curve(struct arc_cb *cb, struct bezier *bezier) +{ + struct stroker *stroker = (struct stroker*)cb->user_data; + stroker_emit_curve_to(stroker, + bezier->x2, bezier->y2, + bezier->x3, bezier->y3, + bezier->x4, bezier->y4); +} + +static void arc_path_move(struct arc_cb *cb, VGfloat x, VGfloat y) +{ + struct path *path = (struct path*)cb->user_data; + path_move_to(path, x, y); +} + +static void arc_path_point(struct arc_cb *cb, VGfloat x, VGfloat y) +{ + struct path *path = (struct path*)cb->user_data; + path_line_to(path, x, y); +} + +static void arc_path_bezier(struct arc_cb *cb, struct bezier *bezier) +{ + struct path *path = (struct path*)cb->user_data; + path_cubic_to(path, + bezier->x2, bezier->y2, + bezier->x3, bezier->y3, + bezier->x4, bezier->y4); +} + +static INLINE int num_beziers_needed(struct arc *arc) +{ + double threshold = 0.05; + VGboolean found = VG_FALSE; + int n = 1; + double min_eta, max_eta; + + min_eta = MIN2(arc->eta1, arc->eta2); + max_eta = MAX2(arc->eta1, arc->eta2); + + while ((! found) && (n < 1024)) { + double d_eta = (max_eta - min_eta) / n; + if (d_eta <= 0.5 * M_PI) { + double eta_b = min_eta; + found = VG_TRUE; + for (int i = 0; found && (i < n); ++i) { + double etaA = eta_b; + eta_b += d_eta; + found = (estimate_error(arc, etaA, eta_b) <= threshold); + } + } + n = n << 1; + } + + return n; +} + +static void arc_to_beziers(struct arc *arc, + struct arc_cb cb, + struct matrix *matrix) +{ + int n = 1; + double d_eta, eta_b, cos_eta_b, + sin_eta_b, a_cos_eta_b, b_sin_eta_b, a_sin_eta_b, + b_cos_eta_b, x_b, y_b, x_b_dot, y_b_dot, lx, ly; + double t, alpha; + + { /* always move to the start of the arc */ + VGfloat x = arc->x1; + VGfloat y = arc->y1; + matrix_map_point(matrix, x, y, &x, &y); + cb.move(&cb, x, y); + } + + if (!arc->is_valid) { + VGfloat x = arc->x2; + VGfloat y = arc->y2; + matrix_map_point(matrix, x, y, &x, &y); + cb.point(&cb, x, y); + return; + } + + /* find the number of Bézier curves needed */ + n = num_beziers_needed(arc); + + d_eta = (arc->eta2 - arc->eta1) / n; + eta_b = arc->eta1; + + cos_eta_b = cos(eta_b); + sin_eta_b = sin(eta_b); + a_cos_eta_b = arc->a * cos_eta_b; + b_sin_eta_b = arc->b * sin_eta_b; + a_sin_eta_b = arc->a * sin_eta_b; + b_cos_eta_b = arc->b * cos_eta_b; + x_b = arc->cx + a_cos_eta_b * arc->cos_theta - + b_sin_eta_b * arc->sin_theta; + y_b = arc->cy + a_cos_eta_b * arc->sin_theta + + b_sin_eta_b * arc->cos_theta; + x_b_dot = -a_sin_eta_b * arc->cos_theta - + b_cos_eta_b * arc->sin_theta; + y_b_dot = -a_sin_eta_b * arc->sin_theta + + b_cos_eta_b * arc->cos_theta; + + { + VGfloat x = x_b, y = y_b; + matrix_map_point(matrix, x, y, &x, &y); + cb.point(&cb, x, y); + } + lx = x_b; + ly = y_b; + + t = tan(0.5 * d_eta); + alpha = sin(d_eta) * (sqrt(4 + 3 * t * t) - 1) / 3; + + for (int i = 0; i < n; ++i) { + struct bezier bezier; + double xA = x_b; + double yA = y_b; + double xADot = x_b_dot; + double yADot = y_b_dot; + + eta_b += d_eta; + cos_eta_b = cos(eta_b); + sin_eta_b = sin(eta_b); + a_cos_eta_b = arc->a * cos_eta_b; + b_sin_eta_b = arc->b * sin_eta_b; + a_sin_eta_b = arc->a * sin_eta_b; + b_cos_eta_b = arc->b * cos_eta_b; + x_b = arc->cx + a_cos_eta_b * arc->cos_theta - + b_sin_eta_b * arc->sin_theta; + y_b = arc->cy + a_cos_eta_b * arc->sin_theta + + b_sin_eta_b * arc->cos_theta; + x_b_dot = -a_sin_eta_b * arc->cos_theta - + b_cos_eta_b * arc->sin_theta; + y_b_dot = -a_sin_eta_b * arc->sin_theta + + b_cos_eta_b * arc->cos_theta; + + bezier_init(&bezier, + lx, ly, + (float) (xA + alpha * xADot), (float) (yA + alpha * yADot), + (float) (x_b - alpha * x_b_dot), (float) (y_b - alpha * y_b_dot), + (float) x_b, (float) y_b); +#if 0 + debug_printf("%d) Bezier (%f, %f), (%f, %f), (%f, %f), (%f, %f)\n", + i, + bezier.x1, bezier.y1, + bezier.x2, bezier.y2, + bezier.x3, bezier.y3, + bezier.x4, bezier.y4); +#endif + bezier_transform(&bezier, matrix); + cb.bezier(&cb, &bezier); + lx = x_b; + ly = y_b; + } +} + + +void arc_add_to_polygon(struct arc *arc, + struct polygon *poly, + struct matrix *matrix) +{ + struct arc_cb cb; + + cb.move = cb_null_move; + cb.point = polygon_point; + cb.bezier = polygon_bezier; + cb.user_data = poly; + + arc_to_beziers(arc, cb, matrix); +} + +void arc_stroke_cb(struct arc *arc, + struct stroker *stroke, + struct matrix *matrix) +{ + struct arc_cb cb; + + cb.move = cb_null_move; + cb.point = stroke_point; + cb.bezier = stroke_curve; + cb.user_data = stroke; + + arc_to_beziers(arc, cb, matrix); +} + +void arc_stroker_emit(struct arc *arc, + struct stroker *stroker, + struct matrix *matrix) +{ + struct arc_cb cb; + + cb.move = cb_null_move; + cb.point = stroke_emit_point; + cb.bezier = stroke_emit_curve; + cb.user_data = stroker; + + arc_to_beziers(arc, cb, matrix); +} + +void arc_to_path(struct arc *arc, + struct path *path, + struct matrix *matrix) +{ + struct arc_cb cb; + + cb.move = arc_path_move; + cb.point = arc_path_point; + cb.bezier = arc_path_bezier; + cb.user_data = path; + + arc_to_beziers(arc, cb, matrix); +} diff --git a/src/gallium/state_trackers/vega/arc.h b/src/gallium/state_trackers/vega/arc.h new file mode 100644 index 0000000000..3205cd5021 --- /dev/null +++ b/src/gallium/state_trackers/vega/arc.h @@ -0,0 +1,80 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ARC_H +#define ARC_H + +#include "VG/openvg.h" + +struct polygon; +struct matrix; +struct stroker; +struct path; + +struct arc { + VGPathSegment type; + + VGfloat cx, cy; + + VGfloat a, b; + + VGfloat theta; + VGfloat cos_theta, sin_theta; + + VGfloat eta1; + VGfloat eta2; + + VGfloat x1, y1, x2, y2; + + VGboolean is_valid; +}; + +void arc_init(struct arc *arc, + VGPathSegment type, + VGfloat x1, VGfloat y1, + VGfloat x2, VGfloat y2, + VGfloat rh, VGfloat rv, + VGfloat rot); + +void arc_add_to_polygon(struct arc *arc, + struct polygon *poly, + struct matrix *matrix); + + +void arc_to_path(struct arc *arc, + struct path *p, + struct matrix *matrix); + +void arc_stroke_cb(struct arc *arc, + struct stroker *stroke, + struct matrix *matrix); + +void arc_stroker_emit(struct arc *arc, + struct stroker *stroke, + struct matrix *matrix); + + +#endif diff --git a/src/gallium/state_trackers/vega/asm_fill.h b/src/gallium/state_trackers/vega/asm_fill.h new file mode 100644 index 0000000000..2f394ad6c5 --- /dev/null +++ b/src/gallium/state_trackers/vega/asm_fill.h @@ -0,0 +1,246 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ASM_FILL_H +#define ASM_FILL_H + +static const char solid_fill_asm[] = + "MOV %s, CONST[0]\n"; + + +static const char linear_grad_asm[] = + "MOV TEMP[0].xy, IN[0]\n" + "MOV TEMP[0].z, CONST[1].yyyy\n" + "DP3 TEMP[1], CONST[2], TEMP[0]\n" + "DP3 TEMP[2], CONST[3], TEMP[0]\n" + "DP3 TEMP[3], CONST[4], TEMP[0]\n" + "RCP TEMP[3], TEMP[3]\n" + "MUL TEMP[1], TEMP[1], TEMP[3]\n" + "MUL TEMP[2], TEMP[2], TEMP[3]\n" + "MOV TEMP[4].x, TEMP[1]\n" + "MOV TEMP[4].y, TEMP[2]\n" + "MUL TEMP[0], CONST[0].yyyy, TEMP[4].yyyy\n" + "MAD TEMP[1], CONST[0].xxxx, TEMP[4].xxxx, TEMP[0]\n" + "MUL TEMP[2], TEMP[1], CONST[0].zzzz\n" + "TEX %s, TEMP[2], SAMP[0], 1D\n"; + +static const char radial_grad_asm[] = + "MOV TEMP[0].xy, IN[0]\n" + "MOV TEMP[0].z, CONST[1].yyyy\n" + "DP3 TEMP[1], CONST[2], TEMP[0]\n" + "DP3 TEMP[2], CONST[3], TEMP[0]\n" + "DP3 TEMP[3], CONST[4], TEMP[0]\n" + "RCP TEMP[3], TEMP[3]\n" + "MUL TEMP[1], TEMP[1], TEMP[3]\n" + "MUL TEMP[2], TEMP[2], TEMP[3]\n" + "MOV TEMP[5].x, TEMP[1]\n" + "MOV TEMP[5].y, TEMP[2]\n" + "MUL TEMP[0], CONST[0].yyyy, TEMP[5].yyyy\n" + "MAD TEMP[1], CONST[0].xxxx, TEMP[5].xxxx, TEMP[0]\n" + "ADD TEMP[1], TEMP[1], TEMP[1]\n" + "MUL TEMP[3], TEMP[5].yyyy, TEMP[5].yyyy\n" + "MAD TEMP[4], TEMP[5].xxxx, TEMP[5].xxxx, TEMP[3]\n" + "MOV TEMP[4], -TEMP[4]\n" + "MUL TEMP[2], CONST[0].zzzz, TEMP[4]\n" + "MUL TEMP[0], CONST[1].wwww, TEMP[2]\n" + "MUL TEMP[3], TEMP[1], TEMP[1]\n" + "SUB TEMP[2], TEMP[3], TEMP[0]\n" + "RSQ TEMP[2], |TEMP[2]|\n" + "RCP TEMP[2], TEMP[2]\n" + "SUB TEMP[1], TEMP[2], TEMP[1]\n" + "ADD TEMP[0], CONST[0].zzzz, CONST[0].zzzz\n" + "RCP TEMP[0], TEMP[0]\n" + "MUL TEMP[2], TEMP[1], TEMP[0]\n" + "TEX %s, TEMP[2], SAMP[0], 1D\n"; + +static const char pattern_asm[] = + "MOV TEMP[0].xy, IN[0]\n" + "MOV TEMP[0].z, CONST[1].yyyy\n" + "DP3 TEMP[1], CONST[2], TEMP[0]\n" + "DP3 TEMP[2], CONST[3], TEMP[0]\n" + "DP3 TEMP[3], CONST[4], TEMP[0]\n" + "RCP TEMP[3], TEMP[3]\n" + "MUL TEMP[1], TEMP[1], TEMP[3]\n" + "MUL TEMP[2], TEMP[2], TEMP[3]\n" + "MOV TEMP[4].x, TEMP[1]\n" + "MOV TEMP[4].y, TEMP[2]\n" + "RCP TEMP[0], CONST[1].zwzw\n" + "MOV TEMP[1], TEMP[4]\n" + "MUL TEMP[1].x, TEMP[1], TEMP[0]\n" + "MUL TEMP[1].y, TEMP[1], TEMP[0]\n" + "TEX %s, TEMP[1], SAMP[0], 2D\n"; + + +static const char mask_asm[] = + "TEX TEMP[1], IN[0], SAMP[1], 2D\n" + "MUL TEMP[0].w, TEMP[0].wwww, TEMP[1].wwww\n" + "MOV %s, TEMP[0]\n"; + + +static const char image_normal_asm[] = + "TEX %s, IN[1], SAMP[3], 2D\n"; + +static const char image_multiply_asm[] = + "TEX TEMP[1], IN[1], SAMP[3], 2D\n" + "MUL %s, TEMP[0], TEMP[1]\n"; + +static const char image_stencil_asm[] = + "TEX TEMP[1], IN[1], SAMP[3], 2D\n" + "MUL %s, TEMP[0], TEMP[1]\n"; + + +#define EXTENDED_BLEND_OVER \ + "SUB TEMP[3], CONST[1].yyyy, TEMP[1].wwww\n" \ + "SUB TEMP[4], CONST[1].yyyy, TEMP[0].wwww\n" \ + "MUL TEMP[3], TEMP[0], TEMP[3]\n" \ + "MUL TEMP[4], TEMP[1], TEMP[4]\n" \ + "ADD TEMP[3], TEMP[3], TEMP[4]\n" + +static const char blend_multiply_asm[] = + "TEX TEMP[1], IN[0], SAMP[2], 2D\n" + EXTENDED_BLEND_OVER + "MUL TEMP[4], TEMP[0], TEMP[1]\n" + "ADD TEMP[1], TEMP[4], TEMP[3]\n"/*result.rgb*/ + "MUL TEMP[2], TEMP[0].wwww, TEMP[1].wwww\n" + "ADD TEMP[3], TEMP[0].wwww, TEMP[1].wwww\n" + "SUB TEMP[1].w, TEMP[3], TEMP[2]\n" + "MOV %s, TEMP[1]\n"; +#if 1 +static const char blend_screen_asm[] = + "TEX TEMP[1], IN[0], SAMP[2], 2D\n" + "ADD TEMP[3], TEMP[0], TEMP[1]\n" + "MUL TEMP[2], TEMP[0], TEMP[1]\n" + "SUB %s, TEMP[3], TEMP[2]\n"; +#else +static const char blend_screen_asm[] = + "TEX TEMP[1], IN[0], SAMP[2], 2D\n" + "MOV %s, TEMP[1]\n"; +#endif + +static const char blend_darken_asm[] = + "TEX TEMP[1], IN[0], SAMP[2], 2D\n" + EXTENDED_BLEND_OVER + "MUL TEMP[4], TEMP[0], TEMP[1].wwww\n" + "MUL TEMP[5], TEMP[1], TEMP[0].wwww\n" + "MIN TEMP[4], TEMP[4], TEMP[5]\n" + "ADD TEMP[1], TEMP[3], TEMP[4]\n" + "MUL TEMP[2], TEMP[0].wwww, TEMP[1].wwww\n" + "ADD TEMP[3], TEMP[0].wwww, TEMP[1].wwww\n" + "SUB TEMP[1].w, TEMP[3], TEMP[2]\n" + "MOV %s, TEMP[1]\n"; + +static const char blend_lighten_asm[] = + "TEX TEMP[1], IN[0], SAMP[2], 2D\n" + EXTENDED_BLEND_OVER + "MUL TEMP[4], TEMP[0], TEMP[1].wwww\n" + "MUL TEMP[5], TEMP[1], TEMP[0].wwww\n" + "MAX TEMP[4], TEMP[4], TEMP[5]\n" + "ADD TEMP[1], TEMP[3], TEMP[4]\n" + "MUL TEMP[2], TEMP[0].wwww, TEMP[1].wwww\n" + "ADD TEMP[3], TEMP[0].wwww, TEMP[1].wwww\n" + "SUB TEMP[1].w, TEMP[3], TEMP[2]\n" + "MOV %s, TEMP[1]\n"; + + +static const char premultiply_asm[] = + "MUL TEMP[0].xyz, TEMP[0], TEMP[0].wwww\n"; + +static const char unpremultiply_asm[] = + "TEX TEMP[0], IN[0], SAMP[1], 2D\n"; + + +static const char color_bw_asm[] = + "ADD TEMP[1], CONST[1].yyyy, CONST[1].yyyy\n" + "RCP TEMP[2], TEMP[1]\n" + "ADD TEMP[1], CONST[1].yyyy, TEMP[2]\n" + "ADD TEMP[2].x, TEMP[0].xxxx, TEMP[0].yyyy\n" + "ADD TEMP[2].x, TEMP[0].zzzz, TEMP[0].xxxx\n" + "SGE TEMP[0].xyz, TEMP[2].xxxx, TEMP[1]\n" + "SGE TEMP[0].w, TEMP[0].wwww, TEMP[2].yyyy\n" + "MOV %s, TEMP[0]\n"; + + +struct shader_asm_info { + VGint id; + VGint num_tokens; + const char * txt; + + VGboolean needs_position; + + VGint start_const; + VGint num_consts; + + VGint start_sampler; + VGint num_samplers; + + VGint start_temp; + VGint num_temps; +}; + + +static const struct shader_asm_info shaders_asm[] = { + /* fills */ + {VEGA_SOLID_FILL_SHADER, 40, solid_fill_asm, + VG_FALSE, 0, 1, 0, 0, 0, 0}, + {VEGA_LINEAR_GRADIENT_SHADER, 200, linear_grad_asm, + VG_TRUE, 0, 5, 0, 1, 0, 5}, + {VEGA_RADIAL_GRADIENT_SHADER, 200, radial_grad_asm, + VG_TRUE, 0, 5, 0, 1, 0, 6}, + {VEGA_PATTERN_SHADER, 100, pattern_asm, + VG_TRUE, 1, 4, 0, 1, 0, 5}, + + /* image draw modes */ + {VEGA_IMAGE_NORMAL_SHADER, 200, image_normal_asm, + VG_TRUE, 0, 0, 3, 1, 0, 0}, + {VEGA_IMAGE_MULTIPLY_SHADER, 200, image_multiply_asm, + VG_TRUE, 0, 0, 3, 1, 0, 2}, + {VEGA_IMAGE_STENCIL_SHADER, 200, image_stencil_asm, + VG_TRUE, 0, 0, 3, 1, 0, 2}, + + {VEGA_MASK_SHADER, 100, mask_asm, + VG_TRUE, 0, 0, 1, 1, 0, 2}, + + /* extra blend modes */ + {VEGA_BLEND_MULTIPLY_SHADER, 200, blend_multiply_asm, + VG_TRUE, 1, 1, 2, 1, 0, 5}, + {VEGA_BLEND_SCREEN_SHADER, 200, blend_screen_asm, + VG_TRUE, 0, 0, 2, 1, 0, 4}, + {VEGA_BLEND_DARKEN_SHADER, 200, blend_darken_asm, + VG_TRUE, 1, 1, 2, 1, 0, 6}, + {VEGA_BLEND_LIGHTEN_SHADER, 200, blend_lighten_asm, + VG_TRUE, 1, 1, 2, 1, 0, 6}, + + /* premultiply */ + {VEGA_PREMULTIPLY_SHADER, 100, premultiply_asm, + VG_FALSE, 0, 0, 0, 0, 0, 1}, + {VEGA_UNPREMULTIPLY_SHADER, 100, unpremultiply_asm, + VG_FALSE, 0, 0, 0, 0, 0, 1}, + + /* color transform to black and white */ + {VEGA_BW_SHADER, 150, color_bw_asm, + VG_FALSE, 1, 1, 0, 0, 0, 3}, +}; +#endif diff --git a/src/gallium/state_trackers/vega/asm_filters.h b/src/gallium/state_trackers/vega/asm_filters.h new file mode 100644 index 0000000000..9a49f2e12d --- /dev/null +++ b/src/gallium/state_trackers/vega/asm_filters.h @@ -0,0 +1,117 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ASM_FILTERS_H +#define ASM_FILTERS_H + +static const char color_matrix_asm[] = + "FRAG1.1\n" + "DCL IN[0], GENERIC[0], PERSPECTIVE\n" + "DCL OUT[0], COLOR, CONSTANT\n" + "DCL CONST[0..4], CONSTANT\n" + "DCL TEMP[0..4], CONSTANT\n" + "DCL SAMP[0], CONSTANT\n" + "TEX TEMP[0], IN[0], SAMP[0], 2D\n" + "MOV TEMP[1], TEMP[0].xxxx\n" + "MOV TEMP[2], TEMP[0].yyyy\n" + "MOV TEMP[3], TEMP[0].zzzz\n" + "MOV TEMP[4], TEMP[0].wwww\n" + "MUL TEMP[1], TEMP[1], CONST[0]\n" + "MUL TEMP[2], TEMP[2], CONST[1]\n" + "MUL TEMP[3], TEMP[3], CONST[2]\n" + "MUL TEMP[4], TEMP[4], CONST[3]\n" + "ADD TEMP[0], TEMP[1], CONST[4]\n" + "ADD TEMP[0], TEMP[0], TEMP[2]\n" + "ADD TEMP[0], TEMP[0], TEMP[3]\n" + "ADD TEMP[0], TEMP[0], TEMP[4]\n" + "MOV OUT[0], TEMP[0]\n" + "END\n"; + +static const char convolution_asm[] = + "FRAG1.1\n" + "DCL IN[0], GENERIC[0], PERSPECTIVE\n" + "DCL OUT[0], COLOR, CONSTANT\n" + "DCL TEMP[0..4], CONSTANT\n" + "DCL ADDR[0], CONSTANT\n" + "DCL CONST[0..%d], CONSTANT\n" + "DCL SAMP[0], CONSTANT\n" + "0: MOV TEMP[0], CONST[0].xxxx\n" + "1: MOV TEMP[1], CONST[0].xxxx\n" + "2: BGNLOOP :14\n" + "3: SGE TEMP[0].z, TEMP[0].yyyy, CONST[1].xxxx\n" + "4: IF TEMP[0].zzzz :7\n" + "5: BRK\n" + "6: ENDIF\n" + "7: ARL ADDR[0].x, TEMP[0].yyyy\n" + "8: MOV TEMP[3], CONST[ADDR[0]+2]\n" + "9: ADD TEMP[4].xy, IN[0], TEMP[3]\n" + "10: TEX TEMP[2], TEMP[4], SAMP[0], 2D\n" + "11: MOV TEMP[3], CONST[ADDR[0]+%d]\n" + "12: MAD TEMP[1], TEMP[2], TEMP[3], TEMP[1]\n" + "13: ADD TEMP[0].y, TEMP[0].yyyy, CONST[0].yyyy\n" + "14: ENDLOOP :2\n" + "15: MAD OUT[0], TEMP[1], CONST[1].yyyy, CONST[1].zzzz\n" + "16: END\n"; + + +static const char lookup_asm[] = + "FRAG1.1\n" + "DCL IN[0], GENERIC[0], PERSPECTIVE\n" + "DCL OUT[0], COLOR, CONSTANT\n" + "DCL TEMP[0..2], CONSTANT\n" + "DCL CONST[0], CONSTANT\n" + "DCL SAMP[0..1], CONSTANT\n" + "TEX TEMP[0], IN[0], SAMP[0], 2D\n" + "MOV TEMP[1], TEMP[0]\n" + /* do red */ + "TEX TEMP[2], TEMP[1].xxxx, SAMP[1], 1D\n" + "MOV TEMP[0].x, TEMP[2].xxxx\n" + /* do blue */ + "TEX TEMP[2], TEMP[1].yyyy, SAMP[1], 1D\n" + "MOV TEMP[0].y, TEMP[2].yyyy\n" + /* do green */ + "TEX TEMP[2], TEMP[1].zzzz, SAMP[1], 1D\n" + "MOV TEMP[0].z, TEMP[2].zzzz\n" + /* do alpha */ + "TEX TEMP[2], TEMP[1].wwww, SAMP[1], 1D\n" + "MOV TEMP[0].w, TEMP[2].wwww\n" + "MOV OUT[0], TEMP[0]\n" + "END\n"; + + +static const char lookup_single_asm[] = + "FRAG1.1\n" + "DCL IN[0], GENERIC[0], PERSPECTIVE\n" + "DCL OUT[0], COLOR, CONSTANT\n" + "DCL TEMP[0..2], CONSTANT\n" + "DCL CONST[0], CONSTANT\n" + "DCL SAMP[0..1], CONSTANT\n" + "TEX TEMP[0], IN[0], SAMP[0], 2D\n" + "TEX TEMP[1], TEMP[0].%s, SAMP[1], 1D\n" + "MOV OUT[0], TEMP[1]\n" + "END\n"; + +#endif diff --git a/src/gallium/state_trackers/vega/asm_util.h b/src/gallium/state_trackers/vega/asm_util.h new file mode 100644 index 0000000000..218e1d166d --- /dev/null +++ b/src/gallium/state_trackers/vega/asm_util.h @@ -0,0 +1,136 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef ASM_UTIL_H +#define ASM_UTIL_H + + +static const char pass_through_depth_asm[] = + "FRAG1.1\n" + "DCL IN[0], POSITION, LINEAR\n" + "DCL OUT[0].z, POSITION, CONSTANT\n" + "0: MOV OUT[0].z, IN[0].zzzz\n" + "1: END\n"; + + + +/* μnew = μmask */ +static const char set_mask_asm[] = + "FRAG1.1\n" + "DCL IN[0], GENERIC[0], PERSPECTIVE\n" + "DCL SAMP[0], CONSTANT\n" + "DCL OUT[0], COLOR, CONSTANT\n" + "0: TEX OUT[0], IN[0], SAMP[0], 2D\n"/*umask*/ + "1: END\n"; + +/* μnew = 1 – (1 – μmask)*(1 – μprev) */ +static const char union_mask_asm[] = + "FRAG1.1\n" + "DCL IN[0], GENERIC[0], PERSPECTIVE\n" + "DCL IN[1], POSITION, LINEAR\n" + "DCL CONST[0], CONSTANT\n" + "DCL SAMP[0..1], CONSTANT\n" + "DCL TEMP[0..3], CONSTANT\n" + "DCL OUT[0], COLOR, CONSTANT\n" + "0: TEX TEMP[1], IN[0], SAMP[0], 2D\n"/*umask*/ + "1: TEX TEMP[0], IN[1], SAMP[1], 2D\n"/*uprev*/ + "2: SUB TEMP[2], CONST[0], TEMP[0]\n" + "3: SUB TEMP[3], CONST[0], TEMP[1]\n" + "4: MUL TEMP[0].w, TEMP[2].wwww, TEMP[3].wwww\n" + "5: SUB OUT[0], CONST[0], TEMP[0]\n" + "6: END\n"; + +/* μnew = μmask *μprev */ +static const char intersect_mask_asm[] = + "FRAG1.1\n" + "DCL IN[0], GENERIC[0], PERSPECTIVE\n" + "DCL IN[1], POSITION, LINEAR\n" + "DCL CONST[0], CONSTANT\n" + "DCL SAMP[0..1], CONSTANT\n" + "DCL TEMP[0..1], CONSTANT\n" + "DCL OUT[0], COLOR, CONSTANT\n" + "0: TEX TEMP[0], IN[1], SAMP[1], 2D\n"/*uprev*/ + "1: TEX TEMP[1], IN[0], SAMP[0], 2D\n"/*umask*/ + "2: MUL OUT[0], TEMP[0].wwww, TEMP[1].wwww\n" + "3: END\n"; + +/* μnew = μprev*(1 – μmask) */ +static const char subtract_mask_asm[] = + "FRAG1.1\n" + "DCL IN[0], GENERIC[0], PERSPECTIVE\n" + "DCL IN[1], POSITION, LINEAR\n" + "DCL CONST[0], CONSTANT\n" + "DCL SAMP[0..1], CONSTANT\n" + "DCL TEMP[0..2], CONSTANT\n" + "DCL OUT[0], COLOR, CONSTANT\n" + "0: TEX TEMP[1], IN[0], SAMP[0], 2D\n"/*umask*/ + "1: TEX TEMP[0], IN[1], SAMP[1], 2D\n"/*uprev*/ + "2: SUB TEMP[2], CONST[0], TEMP[1]\n" + "3: MUL OUT[0], TEMP[2].wwww, TEMP[0].wwww\n" + "4: END\n"; + + +static const char vs_plain_asm[] = + "VERT1.1\n" + "DCL IN[0]\n" + "DCL OUT[0], POSITION\n" + "DCL TEMP[0]\n" + "DCL CONST[0..1]\n" + "0: MUL TEMP[0], IN[0], CONST[0]\n" + "1: ADD TEMP[0], TEMP[0], CONST[1]\n" + "2: MOV OUT[0], TEMP[0]\n" + "3: END\n"; + +static const char vs_clear_asm[] = + "VERT1.1\n" + "DCL IN[0]\n" + "DCL IN[1]\n" + "DCL OUT[0], POSITION\n" + "DCL OUT[1], COLOR\n" + "DCL TEMP[0]\n" + "DCL CONST[0..1]\n" + "0: MUL TEMP[0], IN[0], CONST[0]\n" + "1: ADD TEMP[0], TEMP[0], CONST[1]\n" + "2: MOV OUT[0], TEMP[0]\n" + "3: MOV OUT[1], IN[1]\n" + "4: END\n"; + + +static const char vs_texture_asm[] = + "VERT1.1\n" + "DCL IN[0]\n" + "DCL IN[1]\n" + "DCL OUT[0], POSITION\n" + "DCL OUT[1], GENERIC\n" + "DCL TEMP[0]\n" + "DCL CONST[0..1]\n" + "0: MUL TEMP[0], IN[0], CONST[0]\n" + "1: ADD TEMP[0], TEMP[0], CONST[1]\n" + "2: MOV OUT[0], TEMP[0]\n" + "3: MOV OUT[1], IN[1]\n" + "4: END\n"; + +#endif diff --git a/src/gallium/state_trackers/vega/bezier.c b/src/gallium/state_trackers/vega/bezier.c new file mode 100644 index 0000000000..39a7ade016 --- /dev/null +++ b/src/gallium/state_trackers/vega/bezier.c @@ -0,0 +1,704 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "bezier.h" + +#include "matrix.h" +#include "polygon.h" + +#include "pipe/p_compiler.h" +#include "util/u_debug.h" + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <math.h> + +static const float flatness = 0.5; + + +static INLINE void split_left(struct bezier *bez, VGfloat t, struct bezier* left) +{ + left->x1 = bez->x1; + left->y1 = bez->y1; + + left->x2 = bez->x1 + t * (bez->x2 - bez->x1); + left->y2 = bez->y1 + t * (bez->y2 - bez->y1); + + left->x3 = bez->x2 + t * (bez->x3 - bez->x2); + left->y3 = bez->y2 + t * (bez->y3 - bez->y2); + + bez->x3 = bez->x3 + t * (bez->x4 - bez->x3); + bez->y3 = bez->y3 + t * (bez->y4 - bez->y3); + + bez->x2 = left->x3 + t * (bez->x3 - left->x3); + bez->y2 = left->y3 + t * (bez->y3 - left->y3); + + left->x3 = left->x2 + t * (left->x3 - left->x2); + left->y3 = left->y2 + t * (left->y3 - left->y2); + + left->x4 = bez->x1 = left->x3 + t * (bez->x2 - left->x3); + left->y4 = bez->y1 = left->y3 + t * (bez->y2 - left->y3); +} + +static INLINE void split(struct bezier *bez, + struct bezier *first_half, + struct bezier *second_half) +{ + double c = (bez->x2 + bez->x3) * 0.5; + first_half->x2 = (bez->x1 + bez->x2) * 0.5; + second_half->x3 = (bez->x3 + bez->x4) * 0.5; + first_half->x1 = bez->x1; + second_half->x4 = bez->x4; + first_half->x3 = (first_half->x2 + c) * 0.5; + second_half->x2 = (second_half->x3 + c) * 0.5; + first_half->x4 = second_half->x1 = + (first_half->x3 + second_half->x2) * 0.5; + + c = (bez->y2 + bez->y3) / 2; + first_half->y2 = (bez->y1 + bez->y2) * 0.5; + second_half->y3 = (bez->y3 + bez->y4) * 0.5; + first_half->y1 = bez->y1; + second_half->y4 = bez->y4; + first_half->y3 = (first_half->y2 + c) * 0.5; + second_half->y2 = (second_half->y3 + c) * 0.5; + first_half->y4 = second_half->y1 = + (first_half->y3 + second_half->y2) * 0.5; +} + +struct polygon * bezier_to_polygon(struct bezier *bez) +{ + struct polygon *poly = polygon_create(64); + polygon_vertex_append(poly, bez->x1, bez->y1); + bezier_add_to_polygon(bez, poly); + return poly; +} + +void bezier_add_to_polygon(const struct bezier *bez, + struct polygon *poly) +{ + struct bezier beziers[32]; + struct bezier *b; + + beziers[0] = *bez; + b = beziers; + + while (b >= beziers) { + double y4y1 = b->y4 - b->y1; + double x4x1 = b->x4 - b->x1; + double l = ABS(x4x1) + ABS(y4y1); + double d; + if (l > 1.f) { + d = ABS((x4x1)*(b->y1 - b->y2) - (y4y1)*(b->x1 - b->x2)) + + ABS((x4x1)*(b->y1 - b->y3) - (y4y1)*(b->x1 - b->x3)); + } else { + d = ABS(b->x1 - b->x2) + ABS(b->y1 - b->y2) + + ABS(b->x1 - b->x3) + ABS(b->y1 - b->y3); + l = 1.; + } + if (d < flatness*l || b == beziers + 31) { + /* good enough, we pop it off and add the endpoint */ + polygon_vertex_append(poly, b->x4, b->y4); + --b; + } else { + /* split, second half of the bezier goes lower into the stack */ + split(b, b+1, b); + ++b; + } + } +} + +static void add_if_close(struct bezier *bez, VGfloat *length, VGfloat error) +{ + struct bezier left, right; /* bez poly splits */ + VGfloat len = 0.0; /* arc length */ + VGfloat chord; /* chord length */ + + len = len + line_length(bez->x1, bez->y1, bez->x2, bez->y2); + len = len + line_length(bez->x2, bez->y2, bez->x3, bez->y3); + len = len + line_length(bez->x3, bez->y3, bez->x4, bez->y4); + + chord = line_length(bez->x1, bez->y1, bez->x4, bez->y4); + + if ((len-chord) > error) { + split(bez, &left, &right); /* split in two */ + add_if_close(&left, length, error); /* try left side */ + add_if_close(&right, length, error); /* try right side */ + return; + } + + *length = *length + len; + + return; +} + +float bezier_length(struct bezier *bez, float error) +{ + VGfloat length = 0.f; + + add_if_close(bez, &length, error); + return length; +} + +void bezier_init(struct bezier *bez, + float x1, float y1, + float x2, float y2, + float x3, float y3, + float x4, float y4) +{ + bez->x1 = x1; + bez->y1 = y1; + bez->x2 = x2; + bez->y2 = y2; + bez->x3 = x3; + bez->y3 = y3; + bez->x4 = x4; + bez->y4 = y4; +#if 0 + debug_printf("bezier in [%f, %f, %f, %f, %f, %f]\n", + x1, y1, x2, y2, x3, y3, x4, y4); +#endif +} + + +static INLINE void bezier_init2v(struct bezier *bez, + float *pt1, + float *pt2, + float *pt3, + float *pt4) +{ + bez->x1 = pt1[0]; + bez->y1 = pt1[1]; + + bez->x2 = pt2[0]; + bez->y2 = pt2[1]; + + bez->x3 = pt3[0]; + bez->y3 = pt3[1]; + + bez->x4 = pt4[0]; + bez->y4 = pt4[1]; +} + + +void bezier_transform(struct bezier *bez, + struct matrix *matrix) +{ + assert(matrix_is_affine(matrix)); + matrix_map_point(matrix, bez->x1, bez->y1, &bez->x1, &bez->y1); + matrix_map_point(matrix, bez->x2, bez->y2, &bez->x2, &bez->y2); + matrix_map_point(matrix, bez->x3, bez->y3, &bez->x3, &bez->y3); + matrix_map_point(matrix, bez->x4, bez->y4, &bez->x4, &bez->y4); +} + +static INLINE void bezier_point_at(const struct bezier *bez, float t, float *pt) +{ + float a, b, c, d; + float m_t; + m_t = 1. - t; + b = m_t * m_t; + c = t * t; + d = c * t; + a = b * m_t; + b *= 3. * t; + c *= 3. * m_t; + pt[0] = a*bez->x1 + b*bez->x2 + c*bez->x3 + d*bez->x4; + pt[1] = a*bez->y1 + b*bez->y2 + c*bez->y3 + d*bez->y4; +} + +static INLINE void bezier_normal_at(const struct bezier *bez, float t, float *norm) +{ + float m_t = 1. - t; + float a = m_t * m_t; + float b = t * m_t; + float c = t * t; + + norm[0] = (bez->y2-bez->y1) * a + (bez->y3-bez->y2) * b + (bez->y4-bez->y3) * c; + norm[1] = -(bez->x2-bez->x1) * a - (bez->x3-bez->x2) * b - (bez->x4-bez->x3) * c; +} + +enum shift_result { + Ok, + Discard, + Split, + Circle +}; + +static enum shift_result good_offset(const struct bezier *b1, + const struct bezier *b2, + float offset, float threshold) +{ + const float o2 = offset*offset; + const float max_dist_line = threshold*offset*offset; + const float max_dist_normal = threshold*offset; + const float spacing = 0.25; + for (float i = spacing; i < 0.99; i += spacing) { + float p1[2],p2[2], d, l; + float normal[2]; + bezier_point_at(b1, i, p1); + bezier_point_at(b2, i, p2); + d = (p1[0] - p2[0])*(p1[0] - p2[0]) + (p1[1] - p2[1])*(p1[1] - p2[1]); + if (ABS(d - o2) > max_dist_line) + return Split; + + bezier_normal_at(b1, i, normal); + l = ABS(normal[0]) + ABS(normal[1]); + if (l != 0.) { + d = ABS(normal[0]*(p1[1] - p2[1]) - normal[1]*(p1[0] - p2[0]) ) / l; + if (d > max_dist_normal) + return Split; + } + } + return Ok; +} + +static INLINE void shift_line_by_normal(float *l, float offset) +{ + float norm[4]; + float tx, ty; + + line_normal(l, norm); + line_normalize(norm); + + tx = (norm[2] - norm[0]) * offset; + ty = (norm[3] - norm[1]) * offset; + l[0] += tx; l[1] += ty; + l[2] += tx; l[3] += ty; +} + +static INLINE VGboolean is_bezier_line(float (*points)[2], int count) +{ + float dx13 = points[2][0] - points[0][0]; + float dy13 = points[2][1] - points[0][1]; + + float dx12 = points[1][0] - points[0][0]; + float dy12 = points[1][1] - points[0][1]; + + debug_assert(count > 2); + + if (count == 3) { + return floatsEqual(dx12 * dy13, dx13 * dy12); + } else if (count == 4) { + float dx14 = points[3][0] - points[0][0]; + float dy14 = points[3][1] - points[0][1]; + + return (floatsEqual(dx12 * dy13, dx13 * dy12) && + floatsEqual(dx12 * dy14, dx14 * dy12)); + } + + return VG_FALSE; +} + +static INLINE void compute_pt_normal(float *pt1, float *pt2, float *res) +{ + float line[4]; + float normal[4]; + line[0] = 0.f; line[1] = 0.f; + line[2] = pt2[0] - pt1[0]; + line[3] = pt2[1] - pt1[1]; + line_normal(line, normal); + line_normalize(normal); + + res[0] = normal[2]; + res[1] = normal[3]; +} + +static enum shift_result shift(const struct bezier *orig, + struct bezier *shifted, + float offset, float threshold) +{ + int map[4]; + VGboolean p1_p2_equal = (orig->x1 == orig->x2 && orig->y1 == orig->y2); + VGboolean p2_p3_equal = (orig->x2 == orig->x3 && orig->y2 == orig->y3); + VGboolean p3_p4_equal = (orig->x3 == orig->x4 && orig->y3 == orig->y4); + + float points[4][2]; + int np = 0; + float bounds[4]; + float points_shifted[4][2]; + float prev_normal[2]; + + points[np][0] = orig->x1; + points[np][1] = orig->y1; + map[0] = 0; + ++np; + if (!p1_p2_equal) { + points[np][0] = orig->x2; + points[np][1] = orig->y2; + ++np; + } + map[1] = np - 1; + if (!p2_p3_equal) { + points[np][0] = orig->x3; + points[np][1] = orig->y3; + ++np; + } + map[2] = np - 1; + if (!p3_p4_equal) { + points[np][0] = orig->x4; + points[np][1] = orig->y4; + ++np; + } + map[3] = np - 1; + if (np == 1) + return Discard; + + /* We need to specialcase lines of 3 or 4 points due to numerical + instability in intersection code below */ + if (np > 2 && is_bezier_line(points, np)) { + float l[4] = { points[0][0], points[0][1], + points[np-1][0], points[np-1][1] }; + float ctrl1[2], ctrl2[2]; + if (floatsEqual(points[0][0], points[np-1][0]) && + floatsEqual(points[0][1], points[np-1][1])) + return Discard; + + shift_line_by_normal(l, offset); + line_point_at(l, 0.33, ctrl1); + line_point_at(l, 0.66, ctrl2); + bezier_init(shifted, l[0], l[1], + ctrl1[0], ctrl1[1], ctrl2[0], ctrl2[1], + l[2], l[3]); + return Ok; + } + + bezier_bounds(orig, bounds); + if (np == 4 && bounds[2] < .1*offset && bounds[3] < .1*offset) { + float l = (orig->x1 - orig->x2)*(orig->x1 - orig->x2) + + (orig->y1 - orig->y2)*(orig->y1 - orig->y1) * + (orig->x3 - orig->x4)*(orig->x3 - orig->x4) + + (orig->y3 - orig->y4)*(orig->y3 - orig->y4); + float dot = (orig->x1 - orig->x2)*(orig->x3 - orig->x4) + + (orig->y1 - orig->y2)*(orig->y3 - orig->y4); + if (dot < 0 && dot*dot < 0.8*l) + /* the points are close and reverse dirction. Approximate the whole + thing by a semi circle */ + return Circle; + } + + compute_pt_normal(points[0], points[1], prev_normal); + + points_shifted[0][0] = points[0][0] + offset * prev_normal[0]; + points_shifted[0][1] = points[0][1] + offset * prev_normal[1]; + + for (int i = 1; i < np - 1; ++i) { + float normal_sum[2], r; + float next_normal[2]; + compute_pt_normal(points[i], points[i + 1], next_normal); + + normal_sum[0] = prev_normal[0] + next_normal[0]; + normal_sum[1] = prev_normal[1] + next_normal[1]; + + r = 1.0 + prev_normal[0] * next_normal[0] + + prev_normal[1] * next_normal[1]; + + if (floatsEqual(r + 1, 1)) { + points_shifted[i][0] = points[i][0] + offset * prev_normal[0]; + points_shifted[i][1] = points[i][1] + offset * prev_normal[1]; + } else { + float k = offset / r; + points_shifted[i][0] = points[i][0] + k * normal_sum[0]; + points_shifted[i][1] = points[i][1] + k * normal_sum[1]; + } + + prev_normal[0] = next_normal[0]; + prev_normal[1] = next_normal[1]; + } + + points_shifted[np - 1][0] = points[np - 1][0] + offset * prev_normal[0]; + points_shifted[np - 1][1] = points[np - 1][1] + offset * prev_normal[1]; + + bezier_init2v(shifted, + points_shifted[map[0]], points_shifted[map[1]], + points_shifted[map[2]], points_shifted[map[3]]); + + return good_offset(orig, shifted, offset, threshold); +} + +static VGboolean make_circle(const struct bezier *b, float offset, struct bezier *o) +{ + float normals[3][2]; + float dist; + float angles[2]; + float sign = 1.f; + int i; + float circle[3][2]; + + normals[0][0] = b->y2 - b->y1; + normals[0][1] = b->x1 - b->x2; + dist = sqrt(normals[0][0]*normals[0][0] + normals[0][1]*normals[0][1]); + if (floatsEqual(dist + 1, 1.f)) + return VG_FALSE; + normals[0][0] /= dist; + normals[0][1] /= dist; + + normals[2][0] = b->y4 - b->y3; + normals[2][1] = b->x3 - b->x4; + dist = sqrt(normals[2][0]*normals[2][0] + normals[2][1]*normals[2][1]); + if (floatsEqual(dist + 1, 1.f)) + return VG_FALSE; + normals[2][0] /= dist; + normals[2][1] /= dist; + + normals[1][0] = b->x1 - b->x2 - b->x3 + b->x4; + normals[1][1] = b->y1 - b->y2 - b->y3 + b->y4; + dist = -1*sqrt(normals[1][0]*normals[1][0] + normals[1][1]*normals[1][1]); + normals[1][0] /= dist; + normals[1][1] /= dist; + + for (i = 0; i < 2; ++i) { + float cos_a = normals[i][0]*normals[i+1][0] + normals[i][1]*normals[i+1][1]; + if (cos_a > 1.) + cos_a = 1.; + if (cos_a < -1.) + cos_a = -1; + angles[i] = acos(cos_a)/M_PI; + } + + if (angles[0] + angles[1] > 1.) { + /* more than 180 degrees */ + normals[1][0] = -normals[1][0]; + normals[1][1] = -normals[1][1]; + angles[0] = 1. - angles[0]; + angles[1] = 1. - angles[1]; + sign = -1.; + } + + circle[0][0] = b->x1 + normals[0][0]*offset; + circle[0][1] = b->y1 + normals[0][1]*offset; + + circle[1][0] = 0.5*(b->x1 + b->x4) + normals[1][0]*offset; + circle[1][1] = 0.5*(b->y1 + b->y4) + normals[1][1]*offset; + + circle[2][0] = b->x4 + normals[2][0]*offset; + circle[2][1] = b->y4 + normals[2][1]*offset; + + for (i = 0; i < 2; ++i) { + float kappa = 2.*KAPPA * sign * offset * angles[i]; + + o->x1 = circle[i][0]; + o->y1 = circle[i][1]; + o->x2 = circle[i][0] - normals[i][1]*kappa; + o->y2 = circle[i][1] + normals[i][0]*kappa; + o->x3 = circle[i+1][0] + normals[i+1][1]*kappa; + o->y3 = circle[i+1][1] - normals[i+1][0]*kappa; + o->x4 = circle[i+1][0]; + o->y4 = circle[i+1][1]; + + ++o; + } + return VG_TRUE; +} + +int bezier_translate_by_normal(struct bezier *bez, + struct bezier *curves, + int max_curves, + float normal_len, + float threshold) +{ + struct bezier beziers[10]; + struct bezier *b, *o; + + /* fixme: this should really be floatsEqual */ + if (bez->x1 == bez->x2 && bez->x1 == bez->x3 && bez->x1 == bez->x4 && + bez->y1 == bez->y2 && bez->y1 == bez->y3 && bez->y1 == bez->y4) + return 0; + + --max_curves; +redo: + beziers[0] = *bez; + b = beziers; + o = curves; + + while (b >= beziers) { + int stack_segments = b - beziers + 1; + enum shift_result res; + if ((stack_segments == 10) || (o - curves == max_curves - stack_segments)) { + threshold *= 1.5; + if (threshold > 2.) + goto give_up; + goto redo; + } + res = shift(b, o, normal_len, threshold); + if (res == Discard) { + --b; + } else if (res == Ok) { + ++o; + --b; + continue; + } else if (res == Circle && max_curves - (o - curves) >= 2) { + /* add semi circle */ + if (make_circle(b, normal_len, o)) + o += 2; + --b; + } else { + split(b, b+1, b); + ++b; + } + } + +give_up: + while (b >= beziers) { + enum shift_result res = shift(b, o, normal_len, threshold); + + /* if res isn't Ok or Split then *o is undefined */ + if (res == Ok || res == Split) + ++o; + + --b; + } + + debug_assert(o - curves <= max_curves); + return o - curves; +} + +void bezier_bounds(const struct bezier *bez, + float *bounds/*x/y/width/height*/) +{ + float xmin = bez->x1; + float xmax = bez->x1; + float ymin = bez->y1; + float ymax = bez->y1; + + if (bez->x2 < xmin) + xmin = bez->x2; + else if (bez->x2 > xmax) + xmax = bez->x2; + if (bez->x3 < xmin) + xmin = bez->x3; + else if (bez->x3 > xmax) + xmax = bez->x3; + if (bez->x4 < xmin) + xmin = bez->x4; + else if (bez->x4 > xmax) + xmax = bez->x4; + + if (bez->y2 < ymin) + ymin = bez->y2; + else if (bez->y2 > ymax) + ymax = bez->y2; + if (bez->y3 < ymin) + ymin = bez->y3; + else if (bez->y3 > ymax) + ymax = bez->y3; + if (bez->y4 < ymin) + ymin = bez->y4; + else if (bez->y4 > ymax) + ymax = bez->y4; + + bounds[0] = xmin; /* x */ + bounds[1] = ymin; /* y */ + bounds[2] = xmax - xmin; /* width */ + bounds[3] = ymax - ymin; /* height */ +} + +void bezier_start_tangent(const struct bezier *bez, + float *tangent) +{ + tangent[0] = bez->x1; + tangent[1] = bez->y1; + tangent[2] = bez->x2; + tangent[3] = bez->y2; + + if (null_line(tangent)) { + tangent[0] = bez->x1; + tangent[1] = bez->y1; + tangent[2] = bez->x3; + tangent[3] = bez->y3; + } + if (null_line(tangent)) { + tangent[0] = bez->x1; + tangent[1] = bez->y1; + tangent[2] = bez->x4; + tangent[3] = bez->y4; + } +} + + +static INLINE VGfloat bezier_t_at_length(struct bezier *bez, + VGfloat at_length, + VGfloat error) +{ + VGfloat len = bezier_length(bez, error); + VGfloat t = 1.0; + VGfloat last_bigger = 1.; + + if (at_length > len || floatsEqual(at_length, len)) + return t; + + if (floatIsZero(at_length)) + return 0.f; + + t *= 0.5; + while (1) { + struct bezier right = *bez; + struct bezier left; + VGfloat tmp_len; + split_left(&right, t, &left); + tmp_len = bezier_length(&left, error); + if (ABS(tmp_len - at_length) < error) + break; + + if (tmp_len < at_length) { + t += (last_bigger - t)*.5; + } else { + last_bigger = t; + t -= t*.5; + } + } + return t; +} + +void bezier_point_at_length(struct bezier *bez, + float length, + float *point, + float *normal) +{ + /* ~0.000001 seems to be required to pass G2080x tests */ + VGfloat t = bezier_t_at_length(bez, length, 0.000001); + bezier_point_at(bez, t, point); + bezier_normal_at(bez, t, normal); + vector_unit(normal); +} + +void bezier_point_at_t(struct bezier *bez, float t, + float *point, float *normal) +{ + bezier_point_at(bez, t, point); + bezier_normal_at(bez, t, normal); + vector_unit(normal); +} + +void bezier_exact_bounds(const struct bezier *bez, + float *bounds/*x/y/width/height*/) +{ + struct polygon *poly = polygon_create(64); + polygon_vertex_append(poly, bez->x1, bez->y1); + bezier_add_to_polygon(bez, poly); + polygon_bounding_rect(poly, bounds); + polygon_destroy(poly); +} + diff --git a/src/gallium/state_trackers/vega/bezier.h b/src/gallium/state_trackers/vega/bezier.h new file mode 100644 index 0000000000..e06666051c --- /dev/null +++ b/src/gallium/state_trackers/vega/bezier.h @@ -0,0 +1,81 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef BEZIER_H +#define BEZIER_H + +struct polygon; +struct matrix; + +struct bezier { + float x1, y1; + float x2, y2; + float x3, y3; + float x4, y4; +}; + + +#define BEZIER_DEFAULT_ERROR 0.01 + +/* kappa as being l of a circle with r = 1, we can emulate any + * circle of radius r by using the formula + * l = r . kappa + * More at: + * http://www.whizkidtech.redprince.net/bezier/circle/ */ +#define KAPPA 0.5522847498 + +void bezier_init(struct bezier *bez, + float x1, float y1, + float x2, float y2, + float x3, float y3, + float x4, float y4); + +struct polygon *bezier_to_polygon(struct bezier *bez); +void bezier_add_to_polygon(const struct bezier *bez, + struct polygon *poly); +float bezier_length(struct bezier *bez, float error); +void bezier_transform(struct bezier *bez, + struct matrix *mat); + +int bezier_translate_by_normal(struct bezier *b, + struct bezier *curves, + int max_curves, + float normal_len, + float threshold); +void bezier_bounds(const struct bezier *bez, + float *bounds/*x/y/width/height*/); +void bezier_exact_bounds(const struct bezier *bez, + float *bounds/*x/y/width/height*/); + +void bezier_start_tangent(const struct bezier *bez, + float *tangent); + +void bezier_point_at_length(struct bezier *bez, float length, + float *point, float *normal); +void bezier_point_at_t(struct bezier *bez, float t, + float *point, float *normal); + +#endif diff --git a/src/gallium/state_trackers/vega/image.c b/src/gallium/state_trackers/vega/image.c new file mode 100644 index 0000000000..9a722980d5 --- /dev/null +++ b/src/gallium/state_trackers/vega/image.c @@ -0,0 +1,654 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "image.h" + +#include "vg_translate.h" +#include "vg_context.h" +#include "matrix.h" +#include "renderer.h" +#include "util_array.h" +#include "api_consts.h" +#include "shaders_cache.h" +#include "shader.h" + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_inlines.h" +#include "util/u_blit.h" +#include "util/u_tile.h" +#include "util/u_memory.h" +#include "util/u_math.h" + +static enum pipe_format vg_format_to_pipe(VGImageFormat format) +{ + switch(format) { + case VG_sRGB_565: + return PIPE_FORMAT_R5G6B5_UNORM; + case VG_sRGBA_5551: + return PIPE_FORMAT_A1R5G5B5_UNORM; + case VG_sRGBA_4444: + return PIPE_FORMAT_A4R4G4B4_UNORM; + case VG_sL_8: + case VG_lL_8: + return PIPE_FORMAT_L8_UNORM; + case VG_BW_1: + return PIPE_FORMAT_A8R8G8B8_UNORM; + case VG_A_8: + return PIPE_FORMAT_A8_UNORM; +#ifdef OPENVG_VERSION_1_1 + case VG_A_1: + case VG_A_4: + return PIPE_FORMAT_A8_UNORM; +#endif + default: + return PIPE_FORMAT_A8R8G8B8_UNORM; + } +} + +static INLINE void vg_sync_size(VGfloat *src_loc, VGfloat *dst_loc) +{ + src_loc[2] = MIN2(src_loc[2], dst_loc[2]); + src_loc[3] = MIN2(src_loc[3], dst_loc[3]); + dst_loc[2] = src_loc[2]; + dst_loc[3] = src_loc[3]; +} + + +static void vg_copy_texture(struct vg_context *ctx, + struct pipe_texture *dst, VGint dx, VGint dy, + struct pipe_texture *src, VGint sx, VGint sy, + VGint width, VGint height) +{ + VGfloat dst_loc[4], src_loc[4]; + VGfloat dst_bounds[4], src_bounds[4]; + VGfloat src_shift[4], dst_shift[4], shift[4]; + + dst_loc[0] = dx; + dst_loc[1] = dy; + dst_loc[2] = width; + dst_loc[3] = height; + dst_bounds[0] = 0.f; + dst_bounds[1] = 0.f; + dst_bounds[2] = dst->width[0]; + dst_bounds[3] = dst->height[0]; + + src_loc[0] = sx; + src_loc[1] = sy; + src_loc[2] = width; + src_loc[3] = height; + src_bounds[0] = 0.f; + src_bounds[1] = 0.f; + src_bounds[2] = src->width[0]; + src_bounds[3] = src->height[0]; + + vg_bound_rect(src_loc, src_bounds, src_shift); + vg_bound_rect(dst_loc, dst_bounds, dst_shift); + shift[0] = src_shift[0] - dst_shift[0]; + shift[1] = src_shift[1] - dst_shift[1]; + + if (shift[0] < 0) + vg_shift_rectx(src_loc, src_bounds, -shift[0]); + else + vg_shift_rectx(dst_loc, dst_bounds, shift[0]); + + if (shift[1] < 0) + vg_shift_recty(src_loc, src_bounds, -shift[1]); + else + vg_shift_recty(dst_loc, dst_bounds, shift[1]); + + vg_sync_size(src_loc, dst_loc); + + if (src_loc[2] >= 0 && src_loc[3] >= 0 && + dst_loc[2] >= 0 && dst_loc[3] >= 0) { + renderer_copy_texture(ctx->renderer, + src, + src_loc[0], + src_loc[1] + src_loc[3], + src_loc[0] + src_loc[2], + src_loc[1], + dst, + dst_loc[0], + dst_loc[1] + dst_loc[3], + dst_loc[0] + dst_loc[2], + dst_loc[1]); + } + +} + +void vg_copy_surface(struct vg_context *ctx, + struct pipe_surface *dst, VGint dx, VGint dy, + struct pipe_surface *src, VGint sx, VGint sy, + VGint width, VGint height) +{ + VGfloat dst_loc[4], src_loc[4]; + VGfloat dst_bounds[4], src_bounds[4]; + VGfloat src_shift[4], dst_shift[4], shift[4]; + + dst_loc[0] = dx; + dst_loc[1] = dy; + dst_loc[2] = width; + dst_loc[3] = height; + dst_bounds[0] = 0.f; + dst_bounds[1] = 0.f; + dst_bounds[2] = dst->width; + dst_bounds[3] = dst->height; + + src_loc[0] = sx; + src_loc[1] = sy; + src_loc[2] = width; + src_loc[3] = height; + src_bounds[0] = 0.f; + src_bounds[1] = 0.f; + src_bounds[2] = src->width; + src_bounds[3] = src->height; + + vg_bound_rect(src_loc, src_bounds, src_shift); + vg_bound_rect(dst_loc, dst_bounds, dst_shift); + shift[0] = src_shift[0] - dst_shift[0]; + shift[1] = src_shift[1] - dst_shift[1]; + + if (shift[0] < 0) + vg_shift_rectx(src_loc, src_bounds, -shift[0]); + else + vg_shift_rectx(dst_loc, dst_bounds, shift[0]); + + if (shift[1] < 0) + vg_shift_recty(src_loc, src_bounds, -shift[1]); + else + vg_shift_recty(dst_loc, dst_bounds, shift[1]); + + vg_sync_size(src_loc, dst_loc); + + if (src_loc[2] > 0 && src_loc[3] > 0 && + dst_loc[2] > 0 && dst_loc[3] > 0) { + if (src == dst) + renderer_copy_surface(ctx->renderer, + src, + src_loc[0], + src->height - (src_loc[1] + src_loc[3]), + src_loc[0] + src_loc[2], + src->height - src_loc[1], + dst, + dst_loc[0], + dst->height - (dst_loc[1] + dst_loc[3]), + dst_loc[0] + dst_loc[2], + dst->height - dst_loc[1], + 0, 0); + else + renderer_copy_surface(ctx->renderer, + src, + src_loc[0], + src->height - src_loc[1], + src_loc[0] + src_loc[2], + src->height - (src_loc[1] + src_loc[3]), + dst, + dst_loc[0], + dst->height - (dst_loc[1] + dst_loc[3]), + dst_loc[0] + dst_loc[2], + dst->height - dst_loc[1], + 0, 0); + } + +} + +static struct pipe_texture *image_texture(struct vg_image *img) +{ + struct pipe_texture *tex = img->texture; + return tex; +} + + +static void image_cleari(struct vg_image *img, VGint clear_colori, + VGint x, VGint y, VGint width, VGint height) +{ + VGint *clearbuf; + VGint i; + VGfloat dwidth, dheight; + + clearbuf = malloc(sizeof(VGint)*width*height); + for (i = 0; i < width*height; ++i) + clearbuf[i] = clear_colori; + + dwidth = MIN2(width, img->width); + dheight = MIN2(height, img->height); + + image_sub_data(img, clearbuf, width * sizeof(VGint), + VG_sRGBA_8888, + x, y, dwidth, dheight); + free(clearbuf); +} + +struct vg_image * image_create(VGImageFormat format, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *image = CALLOC_STRUCT(vg_image); + enum pipe_format pformat = vg_format_to_pipe(format); + struct pipe_texture pt, *newtex; + struct pipe_screen *screen = ctx->pipe->screen; + + vg_init_object(&image->base, ctx, VG_OBJECT_IMAGE); + + image->format = format; + image->width = width; + image->height = height; + + image->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + image->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + image->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + image->sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + image->sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + image->sampler.normalized_coords = 1; + + assert(screen->is_format_supported(screen, pformat, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)); + + memset(&pt, 0, sizeof(pt)); + pt.target = PIPE_TEXTURE_2D; + pt.format = pformat; + pf_get_block(pformat, &pt.block); + pt.last_level = 0; + pt.width[0] = width; + pt.height[0] = height; + pt.depth[0] = 1; + pt.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER; + + newtex = screen->texture_create(screen, &pt); + + debug_assert(newtex); + + image->texture = newtex; + + vg_context_add_object(ctx, VG_OBJECT_IMAGE, image); + + image_cleari(image, 0, 0, 0, image->width, image->height); + return image; +} + +void image_destroy(struct vg_image *img) +{ + struct vg_context *ctx = vg_current_context(); + vg_context_remove_object(ctx, VG_OBJECT_IMAGE, img); + + + if (img->parent) { + /* remove img from the parent child array */ + int idx; + struct vg_image **array = + (struct vg_image **)img->parent->children_array->data; + + for (idx = 0; idx < img->parent->children_array->num_elements; ++idx) { + struct vg_image *child = array[idx]; + if (child == img) { + break; + } + } + debug_assert(idx < img->parent->children_array->num_elements); + array_remove_element(img->parent->children_array, idx); + } + + if (img->children_array && img->children_array->num_elements) { + /* reparent the children */ + VGint i; + struct vg_image *parent = img->parent; + struct vg_image **children = + (struct vg_image **)img->children_array->data; + if (!parent) { + VGint min_x = children[0]->x; + parent = children[0]; + + for (i = 1; i < img->children_array->num_elements; ++i) { + struct vg_image *child = children[i]; + if (child->x < min_x) { + parent = child; + } + } + } + + for (i = 0; i < img->children_array->num_elements; ++i) { + struct vg_image *child = children[i]; + if (child != parent) { + child->parent = parent; + if (!parent->children_array) { + parent->children_array = array_create( + sizeof(struct vg_image*)); + } + array_append_data(parent->children_array, + &child, 1); + } else + child->parent = NULL; + } + array_destroy(img->children_array); + } + + pipe_texture_reference(&img->texture, NULL); + free(img); +} + +void image_clear(struct vg_image *img, + VGint x, VGint y, VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + VGfloat *clear_colorf = ctx->state.vg.clear_color; + VGubyte r, g, b ,a; + VGint clear_colori; + /* FIXME: this is very nasty */ + r = float_to_ubyte(clear_colorf[0]); + g = float_to_ubyte(clear_colorf[1]); + b = float_to_ubyte(clear_colorf[2]); + a = float_to_ubyte(clear_colorf[3]); + clear_colori = r << 24 | g << 16 | b << 8 | a; + image_cleari(img, clear_colori, x, y, width, height); +} + +void image_sub_data(struct vg_image *image, + const void * data, + VGint dataStride, + VGImageFormat dataFormat, + VGint x, VGint y, + VGint width, VGint height) +{ + const VGint yStep = 1; + VGubyte *src = (VGubyte *)data; + VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; + VGfloat *df = (VGfloat*)temp; + VGint i; + struct vg_context *ctx = vg_current_context(); + struct pipe_screen *screen = ctx->pipe->screen; + struct pipe_texture *texture = image_texture(image); + VGint xoffset = 0, yoffset = 0; + + if (x < 0) { + xoffset -= x; + width += x; + x = 0; + } + if (y < 0) { + yoffset -= y; + height += y; + y = 0; + } + + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (x > image->width || y > image->width) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + + if (x + width > image->width) { + width = image->width - x; + } + + if (y + height > image->height) { + height = image->height - y; + } + + { /* upload color_data */ + struct pipe_transfer *transfer = screen->get_tex_transfer( + screen, texture, 0, 0, 0, + PIPE_TRANSFER_WRITE, 0, 0, texture->width[0], texture->height[0]); + src += (dataStride * yoffset); + for (i = 0; i < height; i++) { + _vega_unpack_float_span_rgba(ctx, width, xoffset, src, dataFormat, temp); + pipe_put_tile_rgba(transfer, x+image->x, y+image->y, width, 1, df); + y += yStep; + src += dataStride; + } + screen->tex_transfer_destroy(transfer); + } +} + +void image_get_sub_data(struct vg_image * image, + void * data, + VGint dataStride, + VGImageFormat dataFormat, + VGint sx, VGint sy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_context *pipe = ctx->pipe; + struct pipe_screen *screen = pipe->screen; + VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; + VGfloat *df = (VGfloat*)temp; + VGint y = 0, yStep = 1; + VGint i; + VGubyte *dst = (VGubyte *)data; + + { + struct pipe_transfer *transfer = + screen->get_tex_transfer(screen, + image->texture, 0, 0, 0, + PIPE_TRANSFER_READ, + 0, 0, + image->x + image->width, + image->y + image->height); + /* Do a row at a time to flip image data vertically */ + for (i = 0; i < height; i++) { +#if 0 + debug_printf("%d-%d == %d\n", sy, height, y); +#endif + pipe_get_tile_rgba(transfer, sx+image->x, y, width, 1, df); + y += yStep; + _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, dst); + dst += dataStride; + } + + screen->tex_transfer_destroy(transfer); + } +} + +struct vg_image * image_child_image(struct vg_image *parent, + VGint x, VGint y, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_image *image = CALLOC_STRUCT(vg_image); + + vg_init_object(&image->base, ctx, VG_OBJECT_IMAGE); + + image->x = parent->x + x; + image->y = parent->y + y; + image->width = width; + image->height = height; + image->parent = parent; + image->texture = 0; + pipe_texture_reference(&image->texture, + parent->texture); + + image->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + image->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + image->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + image->sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + image->sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + image->sampler.normalized_coords = 1; + + if (!parent->children_array) + parent->children_array = array_create( + sizeof(struct vg_image*)); + + array_append_data(parent->children_array, + &image, 1); + + vg_context_add_object(ctx, VG_OBJECT_IMAGE, image); + + return image; +} + +void image_copy(struct vg_image *dst, VGint dx, VGint dy, + struct vg_image *src, VGint sx, VGint sy, + VGint width, VGint height, + VGboolean dither) +{ + struct vg_context *ctx = vg_current_context(); + + if (width <= 0 || height <= 0) { + vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); + return; + } + /* make sure rendering has completed */ + ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + vg_copy_texture(ctx, dst->texture, dst->x + dx, dst->y + dy, + src->texture, src->x + sx, src->y + sy, width, height); +} + +void image_draw(struct vg_image *img) +{ + struct vg_context *ctx = vg_current_context(); + VGfloat x1, y1; + VGfloat x2, y2; + VGfloat x3, y3; + VGfloat x4, y4; + struct matrix *matrix; + + x1 = 0; + y1 = 0; + x2 = img->width; + y2 = 0; + x3 = img->width; + y3 = img->height; + x4 = 0; + y4 = img->height; + + matrix = &ctx->state.vg.image_user_to_surface_matrix; + + matrix_map_point(matrix, x1, y1, &x1, &y1); + matrix_map_point(matrix, x2, y2, &x2, &y2); + matrix_map_point(matrix, x3, y3, &x3, &y3); + matrix_map_point(matrix, x4, y4, &x4, &y4); + + shader_set_drawing_image(ctx->shader, VG_TRUE); + shader_set_paint(ctx->shader, ctx->state.vg.fill_paint); + shader_set_image(ctx->shader, img); + shader_bind(ctx->shader); + + renderer_texture_quad(ctx->renderer, image_texture(img), + img->x, img->y, img->x + img->width, img->y + img->height, + x1, y1, x2, y2, x3, y3, x4, y4); +} + +void image_set_pixels(VGint dx, VGint dy, + struct vg_image *src, VGint sx, VGint sy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_context *pipe = ctx->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_surface *surf; + struct st_renderbuffer *strb = ctx->draw_buffer->strb; + + /* make sure rendering has completed */ + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + + surf = screen->get_tex_surface(screen, image_texture(src), 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_READ); + + vg_copy_surface(ctx, strb->surface, dx, dy, + surf, sx+src->x, sy+src->y, width, height); + + screen->tex_surface_destroy(surf); +} + +void image_get_pixels(struct vg_image *dst, VGint dx, VGint dy, + VGint sx, VGint sy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_context *pipe = ctx->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_surface *surf; + struct st_renderbuffer *strb = ctx->draw_buffer->strb; + + /* flip the y coordinates */ + /*dy = dst->height - dy - height;*/ + + /* make sure rendering has completed */ + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + + surf = screen->get_tex_surface(screen, image_texture(dst), 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE | + PIPE_BUFFER_USAGE_GPU_READ); + vg_copy_surface(ctx, surf, dst->x + dx, dst->y + dy, + strb->surface, sx, sy, width, height); + + pipe_surface_reference(&surf, NULL); +} + + +VGboolean vg_image_overlaps(struct vg_image *dst, + struct vg_image *src) +{ + if (dst == src || dst->parent == src || + dst == src->parent) + return VG_TRUE; + if (dst->parent && dst->parent == src->parent) { + VGfloat left1 = dst->x; + VGfloat left2 = src->x; + VGfloat right1 = dst->x + dst->width; + VGfloat right2 = src->x + src->width; + VGfloat bottom1 = dst->y; + VGfloat bottom2 = src->y; + VGfloat top1 = dst->y + dst->height; + VGfloat top2 = src->y + src->height; + + return !(left2 > right1 || right2 < left1 || + top2 > bottom1 || bottom2 < top1); + } + return VG_FALSE; +} + +VGint image_bind_samplers(struct vg_image *img, struct pipe_sampler_state **samplers, + struct pipe_texture **textures) +{ + img->sampler.min_img_filter = image_sampler_filter(img->base.ctx); + img->sampler.mag_img_filter = image_sampler_filter(img->base.ctx); + samplers[3] = &img->sampler; + textures[3] = img->texture; + return 1; +} + +VGint image_sampler_filter(struct vg_context *ctx) +{ + switch(ctx->state.vg.image_quality) { + case VG_IMAGE_QUALITY_NONANTIALIASED: + return PIPE_TEX_FILTER_NEAREST; + break; + case VG_IMAGE_QUALITY_FASTER: + return PIPE_TEX_FILTER_NEAREST; + break; + case VG_IMAGE_QUALITY_BETTER: + /*return PIPE_TEX_FILTER_ANISO;*/ + return PIPE_TEX_FILTER_LINEAR; + break; + default: + debug_printf("Unknown image quality"); + } + return PIPE_TEX_FILTER_NEAREST; +} diff --git a/src/gallium/state_trackers/vega/image.h b/src/gallium/state_trackers/vega/image.h new file mode 100644 index 0000000000..78e17cffa6 --- /dev/null +++ b/src/gallium/state_trackers/vega/image.h @@ -0,0 +1,104 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef IMAGES_H +#define IMAGES_H + +#include "vg_context.h" +#include "pipe/p_state.h" + +struct pipe_texture; +struct array; +struct vg_context; +struct pipe_surface; + +struct vg_image { + struct vg_object base; + VGImageFormat format; + VGint x, y; + VGint width, height; + + struct vg_image *parent; + + struct pipe_texture *texture; + struct pipe_sampler_state sampler; + + struct array *children_array; +}; + +struct vg_image *image_create(VGImageFormat format, + VGint width, VGint height); +void image_destroy(struct vg_image *img); + +void image_clear(struct vg_image *img, + VGint x, VGint y, VGint width, VGint height); + +void image_sub_data(struct vg_image *image, + const void * data, + VGint dataStride, + VGImageFormat dataFormat, + VGint x, VGint y, + VGint width, VGint height); + +void image_get_sub_data(struct vg_image * image, + void * data, + VGint dataStride, + VGImageFormat dataFormat, + VGint x, VGint y, + VGint width, VGint height); + +struct vg_image *image_child_image(struct vg_image *parent, + VGint x, VGint y, + VGint width, VGint height); + +void image_copy(struct vg_image *dst, VGint dx, VGint dy, + struct vg_image *src, VGint sx, VGint sy, + VGint width, VGint height, + VGboolean dither); + +void image_draw(struct vg_image *img); + +void image_set_pixels(VGint dx, VGint dy, + struct vg_image *src, VGint sx, VGint sy, + VGint width, VGint height); +void image_get_pixels(struct vg_image *dst, VGint dx, VGint dy, + VGint sx, VGint sy, + VGint width, VGint height); + +VGint image_bind_samplers(struct vg_image *dst, struct pipe_sampler_state **samplers, + struct pipe_texture **textures); + +VGboolean vg_image_overlaps(struct vg_image *dst, + struct vg_image *src); + +VGint image_sampler_filter(struct vg_context *ctx); + +void vg_copy_surface(struct vg_context *ctx, + struct pipe_surface *dst, VGint dx, VGint dy, + struct pipe_surface *src, VGint sx, VGint sy, + VGint width, VGint height); + +#endif diff --git a/src/gallium/state_trackers/vega/mask.c b/src/gallium/state_trackers/vega/mask.c new file mode 100644 index 0000000000..24650a37d5 --- /dev/null +++ b/src/gallium/state_trackers/vega/mask.c @@ -0,0 +1,690 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "mask.h" + +#include "path.h" +#include "image.h" +#include "shaders_cache.h" +#include "renderer.h" +#include "asm_util.h" +#include "st_inlines.h" + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_inlines.h" +#include "util/u_memory.h" + +struct vg_mask_layer { + struct vg_object base; + + VGint width; + VGint height; + + struct pipe_texture *texture; +}; + +static INLINE struct pipe_surface * +alpha_mask_surface(struct vg_context *ctx, int usage) +{ + struct pipe_screen *screen = ctx->pipe->screen; + struct st_framebuffer *stfb = ctx->draw_buffer; + return screen->get_tex_surface(screen, + stfb->alpha_mask, + 0, 0, 0, + usage); +} + +static INLINE VGboolean +intersect_rectangles(VGint dwidth, VGint dheight, + VGint swidth, VGint sheight, + VGint tx, VGint ty, + VGint twidth, VGint theight, + VGint *offsets, + VGint *location) +{ + if (tx + twidth <= 0 || tx >= dwidth) + return VG_FALSE; + if (ty + theight <= 0 || ty >= dheight) + return VG_FALSE; + + offsets[0] = 0; + offsets[1] = 0; + location[0] = tx; + location[1] = ty; + + if (tx < 0) { + offsets[0] -= tx; + location[0] = 0; + + location[2] = MIN2(tx + swidth, MIN2(dwidth, tx + twidth)); + offsets[2] = location[2]; + } else { + offsets[2] = MIN2(twidth, MIN2(dwidth - tx, swidth )); + location[2] = offsets[2]; + } + + if (ty < 0) { + offsets[1] -= ty; + location[1] = 0; + + location[3] = MIN2(ty + sheight, MIN2(dheight, ty + theight)); + offsets[3] = location[3]; + } else { + offsets[3] = MIN2(theight, MIN2(dheight - ty, sheight)); + location[3] = offsets[3]; + } + + return VG_TRUE; +} + +#if DEBUG_MASKS +static void read_alpha_mask(void * data, VGint dataStride, + VGImageFormat dataFormat, + VGint sx, VGint sy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_context *pipe = ctx->pipe; + struct pipe_screen *screen = pipe->screen; + + struct st_framebuffer *stfb = ctx->draw_buffer; + struct st_renderbuffer *strb = stfb->alpha_mask; + struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; + + VGfloat temp[VEGA_MAX_IMAGE_WIDTH][4]; + VGfloat *df = (VGfloat*)temp; + VGint y = (fb->height - sy) - 1, yStep = -1; + VGint i; + VGubyte *dst = (VGubyte *)data; + VGint xoffset = 0, yoffset = 0; + + /* make sure rendering has completed */ + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + if (sx < 0) { + xoffset = -sx; + xoffset *= _vega_size_for_format(dataFormat); + width += sx; + sx = 0; + } + if (sy < 0) { + yoffset = -sy; + height += sy; + sy = 0; + y = (fb->height - sy) - 1; + yoffset *= dataStride; + } + + { + struct pipe_surface *surf; + + surf = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + + /* Do a row at a time to flip image data vertically */ + for (i = 0; i < height; i++) { +#if 0 + debug_printf("%d-%d == %d\n", sy, height, y); +#endif + pipe_get_tile_rgba(surf, sx, y, width, 1, df); + y += yStep; + _vega_pack_rgba_span_float(ctx, width, temp, dataFormat, + dst + yoffset + xoffset); + dst += dataStride; + } + + pipe_surface_reference(&surf, NULL); + } +} + +void save_alpha_to_file(const char *filename) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; + VGint *data; + int i, j; + + data = malloc(sizeof(int) * fb->width * fb->height); + read_alpha_mask(data, fb->width * sizeof(int), + VG_sRGBA_8888, + 0, 0, fb->width, fb->height); + fprintf(stderr, "/*---------- start */\n"); + fprintf(stderr, "const int image_width = %d;\n", + fb->width); + fprintf(stderr, "const int image_height = %d;\n", + fb->height); + fprintf(stderr, "const int image_data = {\n"); + for (i = 0; i < fb->height; ++i) { + for (j = 0; j < fb->width; ++j) { + int rgba = data[i * fb->height + j]; + int argb = 0; + argb = (rgba >> 8); + argb |= ((rgba & 0xff) << 24); + fprintf(stderr, "0x%x, ", argb); + } + fprintf(stderr, "\n"); + } + fprintf(stderr, "};\n"); + fprintf(stderr, "/*---------- end */\n"); +} +#endif + +static void setup_mask_framebuffer(struct pipe_surface *surf, + VGint surf_width, VGint surf_height) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_framebuffer_state fb; + + memset(&fb, 0, sizeof(fb)); + fb.width = surf_width; + fb.height = surf_height; + fb.nr_cbufs = 1; + fb.cbufs[0] = surf; + { + VGint i; + for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) + fb.cbufs[i] = 0; + } + cso_set_framebuffer(ctx->cso_context, &fb); +} + + +/* setup shader constants */ +static void setup_mask_operation(VGMaskOperation operation) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_constant_buffer *cbuf = &ctx->mask.cbuf; + const VGint param_bytes = 4 * sizeof(VGfloat); + const VGfloat ones[4] = {1.f, 1.f, 1.f, 1.f}; + void *shader = 0; + + /* We always need to get a new buffer, to keep the drivers simple and + * avoid gratuitous rendering synchronization. + */ + pipe_buffer_reference(&cbuf->buffer, NULL); + + cbuf->buffer = pipe_buffer_create(ctx->pipe->screen, 1, + PIPE_BUFFER_USAGE_CONSTANT, + param_bytes); + if (cbuf->buffer) { + st_no_flush_pipe_buffer_write(ctx, cbuf->buffer, + 0, param_bytes, ones); + } + + ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf); + switch (operation) { + case VG_UNION_MASK: { + if (!ctx->mask.union_fs) { + ctx->mask.union_fs = shader_create_from_text(ctx->pipe, + union_mask_asm, + 200, + PIPE_SHADER_FRAGMENT); + } + shader = ctx->mask.union_fs->driver; + } + break; + case VG_INTERSECT_MASK: { + if (!ctx->mask.intersect_fs) { + ctx->mask.intersect_fs = shader_create_from_text(ctx->pipe, + intersect_mask_asm, + 200, + PIPE_SHADER_FRAGMENT); + } + shader = ctx->mask.intersect_fs->driver; + } + break; + case VG_SUBTRACT_MASK: { + if (!ctx->mask.subtract_fs) { + ctx->mask.subtract_fs = shader_create_from_text(ctx->pipe, + subtract_mask_asm, + 200, + PIPE_SHADER_FRAGMENT); + } + shader = ctx->mask.subtract_fs->driver; + } + break; + case VG_SET_MASK: { + if (!ctx->mask.set_fs) { + ctx->mask.set_fs = shader_create_from_text(ctx->pipe, + set_mask_asm, + 200, + PIPE_SHADER_FRAGMENT); + } + shader = ctx->mask.set_fs->driver; + } + break; + default: + assert(0); + break; + } + cso_set_fragment_shader_handle(ctx->cso_context, shader); +} + +static void setup_mask_samplers(struct pipe_texture *umask) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + struct pipe_texture *textures[PIPE_MAX_SAMPLERS]; + struct st_framebuffer *fb_buffers = ctx->draw_buffer; + struct pipe_texture *uprev = NULL; + struct pipe_sampler_state sampler; + + uprev = fb_buffers->blend_texture; + sampler = ctx->mask.sampler; + sampler.normalized_coords = 1; + + samplers[0] = NULL; + samplers[1] = NULL; + samplers[2] = NULL; + textures[0] = NULL; + textures[1] = NULL; + textures[2] = NULL; + + samplers[0] = &sampler; + samplers[1] = &ctx->mask.sampler; + + textures[0] = umask; + textures[1] = uprev; + + cso_set_samplers(ctx->cso_context, 2, + (const struct pipe_sampler_state **)samplers); + cso_set_sampler_textures(ctx->cso_context, 2, textures); +} + + +/* setup shader constants */ +static void setup_mask_fill(const VGfloat color[4]) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_constant_buffer *cbuf = &ctx->mask.cbuf; + const VGint param_bytes = 4 * sizeof(VGfloat); + + /* We always need to get a new buffer, to keep the drivers simple and + * avoid gratuitous rendering synchronization. + */ + pipe_buffer_reference(&cbuf->buffer, NULL); + + cbuf->buffer = pipe_buffer_create(ctx->pipe->screen, 1, + PIPE_BUFFER_USAGE_CONSTANT, + param_bytes); + if (cbuf->buffer) { + st_no_flush_pipe_buffer_write(ctx, cbuf->buffer, 0, param_bytes, color); + } + + ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf); + cso_set_fragment_shader_handle(ctx->cso_context, + shaders_cache_fill(ctx->sc, + VEGA_SOLID_FILL_SHADER)); +} + +static void setup_mask_viewport() +{ + struct vg_context *ctx = vg_current_context(); + vg_set_viewport(ctx, VEGA_Y0_TOP); +} + +static void setup_mask_blend() +{ + struct vg_context *ctx = vg_current_context(); + + struct pipe_blend_state blend; + + memset(&blend, 0, sizeof(struct pipe_blend_state)); + blend.blend_enable = 1; + blend.colormask |= PIPE_MASK_R; + blend.colormask |= PIPE_MASK_G; + blend.colormask |= PIPE_MASK_B; + blend.colormask |= PIPE_MASK_A; + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + + cso_set_blend(ctx->cso_context, &blend); +} + + +static void surface_fill(struct pipe_surface *surf, + int surf_width, int surf_height, + int x, int y, int width, int height, + const VGfloat color[4]) +{ + struct vg_context *ctx = vg_current_context(); + + if (x < 0) { + width += x; + x = 0; + } + if (y < 0) { + height += y; + y = 0; + } + + cso_save_framebuffer(ctx->cso_context); + cso_save_blend(ctx->cso_context); + cso_save_fragment_shader(ctx->cso_context); + cso_save_viewport(ctx->cso_context); + + setup_mask_blend(); + setup_mask_fill(color); + setup_mask_framebuffer(surf, surf_width, surf_height); + setup_mask_viewport(); + + renderer_draw_quad(ctx->renderer, x, y, + x + width, y + height, 0.0f/*depth should be disabled*/); + + + /* make sure rendering has completed */ + ctx->pipe->flush(ctx->pipe, + PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, + NULL); + +#if DEBUG_MASKS + save_alpha_to_file(0); +#endif + + cso_restore_blend(ctx->cso_context); + cso_restore_framebuffer(ctx->cso_context); + cso_restore_fragment_shader(ctx->cso_context); + cso_restore_viewport(ctx->cso_context); +} + + +static void mask_using_texture(struct pipe_texture *texture, + VGMaskOperation operation, + VGint x, VGint y, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct pipe_surface *surface = + alpha_mask_surface(ctx, PIPE_BUFFER_USAGE_GPU_WRITE); + VGint offsets[4], loc[4]; + + if (!surface) + return; + if (!intersect_rectangles(surface->width, surface->height, + texture->width[0], texture->height[0], + x, y, width, height, + offsets, loc)) + return; +#if 0 + debug_printf("Offset = [%d, %d, %d, %d]\n", offsets[0], + offsets[1], offsets[2], offsets[3]); + debug_printf("Locati = [%d, %d, %d, %d]\n", loc[0], + loc[1], loc[2], loc[3]); +#endif + + /* prepare our blend surface */ + vg_prepare_blend_surface_from_mask(ctx); + + cso_save_samplers(ctx->cso_context); + cso_save_sampler_textures(ctx->cso_context); + cso_save_framebuffer(ctx->cso_context); + cso_save_blend(ctx->cso_context); + cso_save_fragment_shader(ctx->cso_context); + cso_save_viewport(ctx->cso_context); + + setup_mask_samplers(texture); + setup_mask_blend(); + setup_mask_operation(operation); + setup_mask_framebuffer(surface, surface->width, surface->height); + setup_mask_viewport(); + + /* render the quad to propagate the rendering from stencil */ + renderer_draw_texture(ctx->renderer, texture, + offsets[0], offsets[1], + offsets[0] + offsets[2], offsets[1] + offsets[3], + loc[0], loc[1], loc[0] + loc[2], loc[1] + loc[3]); + + /* make sure rendering has completed */ + ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + cso_restore_blend(ctx->cso_context); + cso_restore_framebuffer(ctx->cso_context); + cso_restore_fragment_shader(ctx->cso_context); + cso_restore_samplers(ctx->cso_context); + cso_restore_sampler_textures(ctx->cso_context); + cso_restore_viewport(ctx->cso_context); + + pipe_surface_reference(&surface, NULL); +} + + +#ifdef OPENVG_VERSION_1_1 + +struct vg_mask_layer * mask_layer_create(VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct vg_mask_layer *mask = 0; + + mask = CALLOC_STRUCT(vg_mask_layer); + vg_init_object(&mask->base, ctx, VG_OBJECT_MASK); + mask->width = width; + mask->height = height; + + { + struct pipe_texture pt; + struct pipe_screen *screen = ctx->pipe->screen; + + memset(&pt, 0, sizeof(pt)); + pt.target = PIPE_TEXTURE_2D; + pt.format = PIPE_FORMAT_A8R8G8B8_UNORM; + pf_get_block(PIPE_FORMAT_A8R8G8B8_UNORM, &pt.block); + pt.last_level = 0; + pt.width[0] = width; + pt.height[0] = height; + pt.depth[0] = 1; + pt.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER; + pt.compressed = 0; + + mask->texture = screen->texture_create(screen, &pt); + } + + vg_context_add_object(ctx, VG_OBJECT_MASK, mask); + + return mask; +} + +void mask_layer_destroy(struct vg_mask_layer *layer) +{ + struct vg_context *ctx = vg_current_context(); + + vg_context_remove_object(ctx, VG_OBJECT_MASK, layer); + pipe_texture_release(&layer->texture); + free(layer); +} + +void mask_layer_fill(struct vg_mask_layer *layer, + VGint x, VGint y, + VGint width, VGint height, + VGfloat value) +{ + struct vg_context *ctx = vg_current_context(); + VGfloat alpha_color[4] = {0, 0, 0, 0}; + struct pipe_surface *surface; + + alpha_color[3] = value; + + surface = ctx->pipe->screen->get_tex_surface( + ctx->pipe->screen, layer->texture, + 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + + surface_fill(surface, + layer->width, layer->height, + x, y, width, height, alpha_color); + + ctx->pipe->screen->tex_surface_release(ctx->pipe->screen, &surface); +} + +void mask_copy(struct vg_mask_layer *layer, + VGint sx, VGint sy, + VGint dx, VGint dy, + VGint width, VGint height) +{ + struct vg_context *ctx = vg_current_context(); + struct st_framebuffer *fb_buffers = ctx->draw_buffer; + + renderer_copy_texture(ctx->renderer, + layer->texture, + sx, sy, + sx + width, sy + height, + fb_buffers->alpha_mask, + dx, dy, + dx + width, dy + height); +} + +static void mask_layer_render_to(struct vg_mask_layer *layer, + struct path *path, + VGbitfield paint_modes) +{ + struct vg_context *ctx = vg_current_context(); + const VGfloat fill_color[4] = {1.f, 1.f, 1.f, 1.f}; + struct pipe_screen *screen = ctx->pipe->screen; + struct pipe_surface *surface; + + surface = screen->get_tex_surface(screen, layer->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + + cso_save_framebuffer(ctx->cso_context); + cso_save_fragment_shader(ctx->cso_context); + cso_save_viewport(ctx->cso_context); + + setup_mask_blend(); + setup_mask_fill(fill_color); + setup_mask_framebuffer(surface, layer->width, layer->height); + setup_mask_viewport(); + + if (paint_modes & VG_FILL_PATH) { + struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; + path_fill(path, mat); + } + + if (paint_modes & VG_STROKE_PATH){ + path_stroke(path); + } + + + /* make sure rendering has completed */ + ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + + cso_restore_framebuffer(ctx->cso_context); + cso_restore_fragment_shader(ctx->cso_context); + cso_restore_viewport(ctx->cso_context); + ctx->state.dirty |= BLEND_DIRTY; + + screen->tex_surface_release(ctx->pipe->screen, &surface); +} + +void mask_render_to(struct path *path, + VGbitfield paint_modes, + VGMaskOperation operation) +{ + struct vg_context *ctx = vg_current_context(); + struct st_framebuffer *fb_buffers = ctx->draw_buffer; + struct vg_mask_layer *temp_layer; + VGint width, height; + + width = fb_buffers->alpha_mask->width[0]; + height = fb_buffers->alpha_mask->width[0]; + + temp_layer = mask_layer_create(width, height); + + mask_layer_render_to(temp_layer, path, paint_modes); + + mask_using_layer(temp_layer, 0, 0, width, height, + operation); + + mask_layer_destroy(temp_layer); +} + +void mask_using_layer(struct vg_mask_layer *layer, + VGMaskOperation operation, + VGint x, VGint y, + VGint width, VGint height) +{ + mask_using_texture(layer->texture, operation, + x, y, width, height); +} + +VGint mask_layer_width(struct vg_mask_layer *layer) +{ + return layer->width; +} + +VGint mask_layer_height(struct vg_mask_layer *layer) +{ + return layer->height; +} + + +#endif + +void mask_using_image(struct vg_image *image, + VGMaskOperation operation, + VGint x, VGint y, + VGint width, VGint height) +{ + mask_using_texture(image->texture, operation, + x, y, width, height); +} + +void mask_fill(VGint x, VGint y, VGint width, VGint height, + VGfloat value) +{ + struct vg_context *ctx = vg_current_context(); + VGfloat alpha_color[4] = {.0f, .0f, .0f, value}; + struct pipe_surface *surf = alpha_mask_surface( + ctx, PIPE_BUFFER_USAGE_GPU_WRITE); + +#if DEBUG_MASKS + debug_printf("mask_fill(%d, %d, %d, %d) with rgba(%f, %f, %f, %f)\n", + x, y, width, height, + alpha_color[0], alpha_color[1], + alpha_color[2], alpha_color[3]); + debug_printf("XXX %f === %f \n", + alpha_color[3], value); +#endif + + surface_fill(surf, surf->width, surf->height, + x, y, width, height, alpha_color); + + pipe_surface_reference(&surf, NULL); +} + +VGint mask_bind_samplers(struct pipe_sampler_state **samplers, + struct pipe_texture **textures) +{ + struct vg_context *ctx = vg_current_context(); + + if (ctx->state.vg.masking) { + struct st_framebuffer *fb_buffers = ctx->draw_buffer; + + samplers[1] = &ctx->mask.sampler; + textures[1] = fb_buffers->alpha_mask; + return 1; + } else + return 0; +} diff --git a/src/gallium/state_trackers/vega/mask.h b/src/gallium/state_trackers/vega/mask.h new file mode 100644 index 0000000000..5eaaede0e3 --- /dev/null +++ b/src/gallium/state_trackers/vega/mask.h @@ -0,0 +1,68 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef MASK_H +#define MASK_H + +#include "vg_context.h" + +struct path; +struct vg_image; +struct pipe_texture; + +struct vg_mask_layer *mask_layer_create(VGint width, VGint height); +void mask_layer_destroy(struct vg_mask_layer *layer); +void mask_layer_fill(struct vg_mask_layer *layer, + VGint x, VGint y, + VGint width, VGint height, + VGfloat value); +VGint mask_layer_width(struct vg_mask_layer *layer); +VGint mask_layer_height(struct vg_mask_layer *layer); +void mask_copy(struct vg_mask_layer *layer, + VGint sx, VGint sy, + VGint dx, VGint dy, + VGint width, VGint height); + +void mask_render_to(struct path *path, + VGbitfield paint_modes, + VGMaskOperation operation); + +void mask_using_layer(struct vg_mask_layer *layer, + VGMaskOperation operation, + VGint x, VGint y, + VGint width, VGint height); +void mask_using_image(struct vg_image *image, + VGMaskOperation operation, + VGint x, VGint y, + VGint width, VGint height); +void mask_fill(VGint x, VGint y, + VGint width, VGint height, + VGfloat value); + +VGint mask_bind_samplers(struct pipe_sampler_state **samplers, + struct pipe_texture **textures); + +#endif diff --git a/src/gallium/state_trackers/vega/matrix.h b/src/gallium/state_trackers/vega/matrix.h new file mode 100644 index 0000000000..4c207f912a --- /dev/null +++ b/src/gallium/state_trackers/vega/matrix.h @@ -0,0 +1,462 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef MATRIX_H +#define MATRIX_H + +#include "VG/openvg.h" + +#include "pipe/p_compiler.h" +#include "util/u_math.h" + +#include <stdio.h> +#include <math.h> + +#define floatsEqual(x, y) (fabs(x - y) <= 0.00001f * MIN2(fabs(x), fabs(y))) +#define floatIsZero(x) (floatsEqual((x) + 1, 1)) +#define ABS(x) (fabsf(x)) + +#define DEGREES_TO_RADIANS(d) (0.0174532925199 * (d)) +#define FLT_TO_INT(flt) float_to_int_floor(((VGuint*)&(flt))[0]) + +static INLINE VGint float_to_int_floor(VGuint bits) +{ + int sign = (bits >> 31) ? -1 : 1; + int exp = ((bits >> 23) & 255) - 127; + int mant = bits & 0x007fffff; + int sh = 23 - exp; + + /* abs(value) >= 2^31 -> clamp. */ + + if (exp >= 31) + return (VGint)((sign < 0) ? 0x80000000u : 0x7fffffffu); + + /* abs(value) < 1 -> return -1 or 0. */ + + if (exp < 0) + return (sign < 0 && (exp > -127 || mant != 0)) ? -1 : 0; + + /* abs(value) >= 2^23 -> shift left. */ + + mant |= 0x00800000; + if (sh <= 0) + return sign * (mant << -sh); + + /* Negative -> add a rounding term. */ + + if (sign < 0) + mant += (1 << sh) - 1; + + /* Shift right to obtain the result. */ + + return sign * (mant >> sh); +} + + +struct matrix { + VGfloat m[9]; +}; + +static INLINE void matrix_init(struct matrix *mat, + const VGfloat *val) +{ + memcpy(mat->m, val, sizeof(VGfloat) * 9); +} + +static INLINE void matrix_inits(struct matrix *mat, + VGfloat m11, VGfloat m12, VGfloat m13, + VGfloat m21, VGfloat m22, VGfloat m23, + VGfloat m31, VGfloat m32, VGfloat m33) +{ + mat->m[0] = m11; mat->m[1] = m12; mat->m[2] = m13; + mat->m[3] = m21; mat->m[4] = m22; mat->m[5] = m23; + mat->m[6] = m31; mat->m[7] = m32; mat->m[8] = m33; +} + +static INLINE void matrix_load_identity(struct matrix *matrix) +{ + static const VGfloat identity[9] = {1.f, 0.f, 0.f, + 0.f, 1.f, 0.f, + 0.f, 0.f, 1.f}; + memcpy(matrix->m, identity, sizeof(identity)); +} + +static INLINE VGboolean matrix_is_identity(struct matrix *matrix) +{ + return floatsEqual(matrix->m[0], 1) && floatIsZero(matrix->m[1]) && + floatIsZero(matrix->m[2]) && + floatIsZero(matrix->m[3]) && floatsEqual(matrix->m[4], 1) && + floatIsZero(matrix->m[5]) && + floatIsZero(matrix->m[6]) && floatIsZero(matrix->m[7]) && + floatIsZero(matrix->m[8]); +} + +static INLINE VGboolean matrix_is_affine(struct matrix *matrix) +{ + return floatIsZero(matrix->m[2]) && floatIsZero(matrix->m[5]) + && floatsEqual(matrix->m[8], 1); +} + + +static INLINE void matrix_make_affine(struct matrix *matrix) +{ + matrix->m[2] = 0.f; + matrix->m[5] = 0.f; + matrix->m[8] = 1.f; +} + +static INLINE void matrix_mult(struct matrix *dst, + struct matrix *src) +{ + VGfloat m11 = dst->m[0]*src->m[0] + dst->m[3]*src->m[1] + dst->m[6]*src->m[2]; + VGfloat m12 = dst->m[0]*src->m[3] + dst->m[3]*src->m[4] + dst->m[6]*src->m[5]; + VGfloat m13 = dst->m[0]*src->m[6] + dst->m[3]*src->m[7] + dst->m[6]*src->m[8]; + + VGfloat m21 = dst->m[1]*src->m[0] + dst->m[4]*src->m[1] + dst->m[7]*src->m[2]; + VGfloat m22 = dst->m[1]*src->m[3] + dst->m[4]*src->m[4] + dst->m[7]*src->m[5]; + VGfloat m23 = dst->m[1]*src->m[6] + dst->m[4]*src->m[7] + dst->m[7]*src->m[8]; + + VGfloat m31 = dst->m[2]*src->m[0] + dst->m[5]*src->m[1] + dst->m[8]*src->m[2]; + VGfloat m32 = dst->m[2]*src->m[3] + dst->m[5]*src->m[4] + dst->m[8]*src->m[5]; + VGfloat m33 = dst->m[2]*src->m[6] + dst->m[5]*src->m[7] + dst->m[8]*src->m[8]; + + dst->m[0] = m11; dst->m[1] = m21; dst->m[2] = m31; + dst->m[3] = m12; dst->m[4] = m22; dst->m[5] = m32; + dst->m[6] = m13; dst->m[7] = m23; dst->m[8] = m33; +} + + +static INLINE void matrix_map_point(struct matrix *mat, + VGfloat x, VGfloat y, + VGfloat *out_x, VGfloat *out_y) +{ + /* to be able to do matrix_map_point(m, x, y, &x, &y) use + * temporaries */ + VGfloat tmp_x = x, tmp_y = y; + + *out_x = mat->m[0]*tmp_x + mat->m[3]*tmp_y + mat->m[6]; + *out_y = mat->m[1]*tmp_x + mat->m[4]*tmp_y + mat->m[7]; + if (!matrix_is_affine(mat)) { + VGfloat w = 1/(mat->m[2]*tmp_x + mat->m[5]*tmp_y + mat->m[8]); + *out_x *= w; + *out_y *= w; + } +} + +static INLINE void matrix_translate(struct matrix *dst, + VGfloat tx, VGfloat ty) +{ + if (!matrix_is_affine(dst)) { + struct matrix trans_matrix; + matrix_load_identity(&trans_matrix); + trans_matrix.m[6] = tx; + trans_matrix.m[7] = ty; + matrix_mult(dst, &trans_matrix); + } else { + dst->m[6] += tx*dst->m[0] + ty*dst->m[3]; + dst->m[7] += ty*dst->m[4] + tx*dst->m[1]; + } +} + +static INLINE void matrix_scale(struct matrix *dst, + VGfloat sx, VGfloat sy) +{ + if (!matrix_is_affine(dst)) { + struct matrix scale_matrix; + matrix_load_identity(&scale_matrix); + scale_matrix.m[0] = sx; + scale_matrix.m[4] = sy; + matrix_mult(dst, &scale_matrix); + } else { + dst->m[0] *= sx; dst->m[1] *= sx; + dst->m[3] *= sy; dst->m[4] *= sy; + } +} + +static INLINE void matrix_shear(struct matrix *dst, + VGfloat shx, VGfloat shy) +{ + struct matrix shear_matrix; + matrix_load_identity(&shear_matrix); + shear_matrix.m[1] = shy; + shear_matrix.m[3] = shx; + matrix_mult(dst, &shear_matrix); +} + +static INLINE void matrix_rotate(struct matrix *dst, + VGfloat angle) +{ + struct matrix mat; + float sin_val = 0; + float cos_val = 0; + + + if (floatsEqual(angle, 90) || floatsEqual(angle, -270)) + sin_val = 1.f; + else if (floatsEqual(angle, 270) || floatsEqual(angle, -90)) + sin_val = -1.f; + else if (floatsEqual(angle, 180)) + cos_val = -1.f; + else { + float radians = DEGREES_TO_RADIANS(angle); + sin_val = sin(radians); + cos_val = cos(radians); + } + + if (!matrix_is_affine(dst)) { + matrix_load_identity(&mat); + mat.m[0] = cos_val; mat.m[1] = sin_val; + mat.m[3] = -sin_val; mat.m[4] = cos_val; + + matrix_mult(dst, &mat); + } else { + VGfloat m11 = cos_val*dst->m[0] + sin_val*dst->m[3]; + VGfloat m12 = cos_val*dst->m[1] + sin_val*dst->m[4]; + VGfloat m21 = -sin_val*dst->m[0] + cos_val*dst->m[3]; + VGfloat m22 = -sin_val*dst->m[1] + cos_val*dst->m[4]; + dst->m[0] = m11; dst->m[1] = m12; + dst->m[3] = m21; dst->m[4] = m22; + } +} + + +static INLINE VGfloat matrix_determinant(struct matrix *mat) +{ + return mat->m[0]*(mat->m[8]*mat->m[4]-mat->m[7]*mat->m[5]) - + mat->m[3]*(mat->m[8]*mat->m[1]-mat->m[7]*mat->m[2])+ + mat->m[6]*(mat->m[5]*mat->m[1]-mat->m[4]*mat->m[2]); +} + + +static INLINE void matrix_adjoint(struct matrix *mat) +{ + VGfloat h[9]; + h[0] = mat->m[4]*mat->m[8] - mat->m[5]*mat->m[7]; + h[3] = mat->m[5]*mat->m[6] - mat->m[3]*mat->m[8]; + h[6] = mat->m[3]*mat->m[7] - mat->m[4]*mat->m[6]; + h[1] = mat->m[2]*mat->m[7] - mat->m[1]*mat->m[8]; + h[4] = mat->m[0]*mat->m[8] - mat->m[2]*mat->m[6]; + h[7] = mat->m[1]*mat->m[6] - mat->m[0]*mat->m[7]; + h[2] = mat->m[1]*mat->m[5] - mat->m[2]*mat->m[4]; + h[5] = mat->m[2]*mat->m[3] - mat->m[0]*mat->m[5]; + h[8] = mat->m[0]*mat->m[4] - mat->m[1]*mat->m[3]; + + + memcpy(mat->m, h, sizeof(VGfloat) * 9); +} + +static INLINE void matrix_divs(struct matrix *mat, + VGfloat s) +{ + mat->m[0] /= s; + mat->m[1] /= s; + mat->m[2] /= s; + mat->m[3] /= s; + mat->m[4] /= s; + mat->m[5] /= s; + mat->m[6] /= s; + mat->m[7] /= s; + mat->m[8] /= s; +} + +static INLINE VGboolean matrix_invert(struct matrix *mat) +{ + VGfloat det = matrix_determinant(mat); + + if (floatIsZero(det)) + return VG_FALSE; + + matrix_adjoint(mat); + matrix_divs(mat, det); + return VG_TRUE; +} + +static INLINE VGboolean matrix_is_invertible(struct matrix *mat) +{ + return !floatIsZero(matrix_determinant(mat)); +} + + +static INLINE VGboolean matrix_square_to_quad(VGfloat dx0, VGfloat dy0, + VGfloat dx1, VGfloat dy1, + VGfloat dx3, VGfloat dy3, + VGfloat dx2, VGfloat dy2, + struct matrix *mat) +{ + VGfloat ax = dx0 - dx1 + dx2 - dx3; + VGfloat ay = dy0 - dy1 + dy2 - dy3; + + if (floatIsZero(ax) && floatIsZero(ay)) { + /* affine case */ + matrix_inits(mat, + dx1 - dx0, dy1 - dy0, 0, + dx2 - dx1, dy2 - dy1, 0, + dx0, dy0, 1); + } else { + VGfloat a, b, c, d, e, f, g, h; + VGfloat ax1 = dx1 - dx2; + VGfloat ax2 = dx3 - dx2; + VGfloat ay1 = dy1 - dy2; + VGfloat ay2 = dy3 - dy2; + + /* determinants */ + VGfloat gtop = ax * ay2 - ax2 * ay; + VGfloat htop = ax1 * ay - ax * ay1; + VGfloat bottom = ax1 * ay2 - ax2 * ay1; + + if (!bottom) + return VG_FALSE; + + g = gtop / bottom; + h = htop / bottom; + + a = dx1 - dx0 + g * dx1; + b = dx3 - dx0 + h * dx3; + c = dx0; + d = dy1 - dy0 + g * dy1; + e = dy3 - dy0 + h * dy3; + f = dy0; + + matrix_inits(mat, + a, d, g, + b, e, h, + c, f, 1.f); + } + + return VG_TRUE; +} + +static INLINE VGboolean matrix_quad_to_square(VGfloat sx0, VGfloat sy0, + VGfloat sx1, VGfloat sy1, + VGfloat sx2, VGfloat sy2, + VGfloat sx3, VGfloat sy3, + struct matrix *mat) +{ + if (!matrix_square_to_quad(sx0, sy0, sx1, sy1, + sx2, sy2, sx3, sy3, + mat)) + return VG_FALSE; + + return matrix_invert(mat); +} + + +static INLINE VGboolean matrix_quad_to_quad(VGfloat dx0, VGfloat dy0, + VGfloat dx1, VGfloat dy1, + VGfloat dx2, VGfloat dy2, + VGfloat dx3, VGfloat dy3, + VGfloat sx0, VGfloat sy0, + VGfloat sx1, VGfloat sy1, + VGfloat sx2, VGfloat sy2, + VGfloat sx3, VGfloat sy3, + struct matrix *mat) +{ + struct matrix sqr_to_qd; + + if (!matrix_square_to_quad(dx0, dy0, dx1, dy1, + dx2, dy2, dx3, dy3, + mat)) + return VG_FALSE; + + if (!matrix_quad_to_square(sx0, sy0, sx1, sy1, + sx2, sy2, sx3, sy3, + &sqr_to_qd)) + return VG_FALSE; + + matrix_mult(mat, &sqr_to_qd); + + return VG_TRUE; +} + + +static INLINE VGboolean null_line(const VGfloat *l) +{ + return floatsEqual(l[0], l[2]) && floatsEqual(l[1], l[3]); +} + +static INLINE void line_normal(float *l, float *norm) +{ + norm[0] = l[0]; + norm[1] = l[1]; + + norm[2] = l[0] + (l[3] - l[1]); + norm[3] = l[1] - (l[2] - l[0]); +} + +static INLINE void line_normalize(float *l) +{ + float x = l[2] - l[0]; + float y = l[3] - l[1]; + float len = sqrt(x*x + y*y); + l[2] = l[0] + x/len; + l[3] = l[1] + y/len; +} + +static INLINE VGfloat line_length(VGfloat x1, VGfloat y1, + VGfloat x2, VGfloat y2) +{ + VGfloat x = x2 - x1; + VGfloat y = y2 - y1; + return sqrt(x*x + y*y); +} + +static INLINE VGfloat line_lengthv(const VGfloat *l) +{ + VGfloat x = l[2] - l[0]; + VGfloat y = l[3] - l[1]; + return sqrt(x*x + y*y); +} + + +static INLINE void line_point_at(float *l, float t, float *pt) +{ + float dx = l[2] - l[0]; + float dy = l[3] - l[1]; + + pt[0] = l[0] + dx * t; + pt[1] = l[1] + dy * t; +} + +static INLINE void vector_unit(float *vec) +{ + float len = sqrt(vec[0] * vec[0] + vec[1] * vec[1]); + vec[0] /= len; + vec[1] /= len; +} + +static INLINE void line_normal_vector(float *line, float *vec) +{ + VGfloat normal[4]; + + line_normal(line, normal); + + vec[0] = normal[2] - normal[0]; + vec[1] = normal[3] - normal[1]; + + vector_unit(vec); +} + +#endif diff --git a/src/gallium/state_trackers/vega/paint.c b/src/gallium/state_trackers/vega/paint.c new file mode 100644 index 0000000000..04a6ba9cdc --- /dev/null +++ b/src/gallium/state_trackers/vega/paint.c @@ -0,0 +1,699 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "paint.h" + +#include "shaders_cache.h" +#include "matrix.h" +#include "image.h" +#include "st_inlines.h" + +#include "pipe/p_compiler.h" +#include "pipe/p_inlines.h" + +#include "util/u_memory.h" +#include "util/u_math.h" + +#include "cso_cache/cso_context.h" + +struct vg_paint { + struct vg_object base; + + VGPaintType type; + + struct { + VGfloat color[4]; + VGint colori[4]; + } solid; + + struct { + VGColorRampSpreadMode spread; + VGuint color_data[1024]; + struct { + VGfloat coords[4]; + VGint coordsi[4]; + } linear; + struct { + VGfloat vals[5]; + VGint valsi[5]; + } radial; + struct pipe_texture *texture; + struct pipe_sampler_state sampler; + + VGfloat *ramp_stops; + VGint *ramp_stopsi; + VGint num_stops; + + VGboolean color_ramps_premultiplied; + } gradient; + + struct { + struct pipe_texture *texture; + VGTilingMode tiling_mode; + struct pipe_sampler_state sampler; + } pattern; + + struct pipe_constant_buffer cbuf; + struct pipe_shader_state fs_state; + void *fs; +}; + +static INLINE VGuint mix_pixels(VGuint p1, VGuint a, VGuint p2, VGuint b) +{ + VGuint t = (p1 & 0xff00ff) * a + (p2 & 0xff00ff) * b; + t >>= 8; t &= 0xff00ff; + + p1 = ((p1 >> 8) & 0xff00ff) * a + ((p2 >> 8) & 0xff00ff) * b; + p1 &= 0xff00ff00; p1 |= t; + + return p1; +} + +static INLINE VGuint float4_to_argb(const VGfloat *clr) +{ + return float_to_ubyte(clr[3]) << 24 | + float_to_ubyte(clr[0]) << 16 | + float_to_ubyte(clr[1]) << 8 | + float_to_ubyte(clr[2]) << 0; +} + +static INLINE void create_gradient_data(const VGfloat *ramp_stops, + VGint num, + VGuint *data, + VGint size) +{ + VGint i; + VGint pos = 0; + VGfloat fpos = 0, incr = 1.f / size; + VGuint last_color; + + while (fpos < ramp_stops[0]) { + data[pos] = float4_to_argb(ramp_stops + 1); + fpos += incr; + ++pos; + } + + for (i = 0; i < num - 1; ++i) { + VGint rcur = 5 * i; + VGint rnext = 5 * (i + 1); + VGfloat delta = 1.f/(ramp_stops[rnext] - ramp_stops[rcur]); + while (fpos < ramp_stops[rnext] && pos < size) { + VGint dist = 256 * ((fpos - ramp_stops[rcur]) * delta); + VGint idist = 256 - dist; + VGuint current_color = float4_to_argb(ramp_stops + rcur + 1); + VGuint next_color = float4_to_argb(ramp_stops + rnext + 1); + data[pos] = mix_pixels(current_color, idist, + next_color, dist); + fpos += incr; + ++pos; + } + } + + last_color = float4_to_argb(ramp_stops + ((num - 1) * 5 + 1)); + while (pos < size) { + data[pos] = last_color; + ++pos; + } + data[size-1] = last_color; +} + +static INLINE struct pipe_texture *create_gradient_texture(struct vg_paint *p) +{ + struct pipe_context *pipe = p->base.ctx->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_texture *tex = 0; + struct pipe_texture templ; + + memset(&templ, 0, sizeof(templ)); + templ.target = PIPE_TEXTURE_1D; + templ.format = PIPE_FORMAT_A8R8G8B8_UNORM; + templ.last_level = 0; + templ.width[0] = 1024; + templ.height[0] = 1; + templ.depth[0] = 1; + pf_get_block(PIPE_FORMAT_A8R8G8B8_UNORM, &templ.block); + templ.tex_usage = PIPE_TEXTURE_USAGE_SAMPLER; + + tex = screen->texture_create(screen, &templ); + + { /* upload color_data */ + struct pipe_transfer *transfer = + st_no_flush_get_tex_transfer(p->base.ctx, tex, 0, 0, 0, + PIPE_TRANSFER_WRITE, 0, 0, 1024, 1); + void *map = screen->transfer_map(screen, transfer); + memcpy(map, p->gradient.color_data, sizeof(VGint)*1024); + screen->transfer_unmap(screen, transfer); + screen->tex_transfer_destroy(transfer); + } + + return tex; +} + +struct vg_paint * paint_create(struct vg_context *ctx) +{ + struct vg_paint *paint = CALLOC_STRUCT(vg_paint); + const VGfloat default_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; + const VGfloat def_ling[] = {0.0f, 0.0f, 1.0f, 0.0f}; + const VGfloat def_radg[] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + vg_init_object(&paint->base, ctx, VG_OBJECT_PAINT); + vg_context_add_object(ctx, VG_OBJECT_PAINT, paint); + + paint->type = VG_PAINT_TYPE_COLOR; + memcpy(paint->solid.color, default_color, + 4 * sizeof(VGfloat)); + paint->gradient.spread = VG_COLOR_RAMP_SPREAD_PAD; + memcpy(paint->gradient.linear.coords, def_ling, + 4 * sizeof(VGfloat)); + memcpy(paint->gradient.radial.vals, def_radg, + 5 * sizeof(VGfloat)); + + paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + paint->gradient.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + paint->gradient.sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + paint->gradient.sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + paint->gradient.sampler.normalized_coords = 1; + + memcpy(&paint->pattern.sampler, + &paint->gradient.sampler, + sizeof(struct pipe_sampler_state)); + + return paint; +} + +void paint_destroy(struct vg_paint *paint) +{ + struct vg_context *ctx = paint->base.ctx; + if (paint->pattern.texture) + pipe_texture_reference(&paint->pattern.texture, NULL); + if (ctx) + vg_context_remove_object(ctx, VG_OBJECT_PAINT, paint); + + free(paint->gradient.ramp_stopsi); + free(paint->gradient.ramp_stops); + free(paint); +} + +void paint_set_color(struct vg_paint *paint, + const VGfloat *color) +{ + paint->solid.color[0] = color[0]; + paint->solid.color[1] = color[1]; + paint->solid.color[2] = color[2]; + paint->solid.color[3] = color[3]; + + paint->solid.colori[0] = FLT_TO_INT(color[0]); + paint->solid.colori[1] = FLT_TO_INT(color[1]); + paint->solid.colori[2] = FLT_TO_INT(color[2]); + paint->solid.colori[3] = FLT_TO_INT(color[3]); +} + +static INLINE void paint_color_buffer(struct vg_paint *paint, void *buffer) +{ + VGfloat *map = (VGfloat*)buffer; + memcpy(buffer, paint->solid.color, 4 * sizeof(VGfloat)); + map[4] = 0.f; + map[5] = 1.f; + map[6] = 2.f; + map[7] = 4.f; +} + +static INLINE void paint_linear_gradient_buffer(struct vg_paint *paint, void *buffer) +{ + struct vg_context *ctx = paint->base.ctx; + VGfloat *map = (VGfloat*)buffer; + + map[0] = paint->gradient.linear.coords[2] - paint->gradient.linear.coords[0]; + map[1] = paint->gradient.linear.coords[3] - paint->gradient.linear.coords[1]; + map[2] = 1.f / (map[0] * map[0] + map[1] * map[1]); + map[3] = 1.f; + + map[4] = 0.f; + map[5] = 1.f; + map[6] = 2.f; + map[7] = 4.f; + { + struct matrix mat; + struct matrix inv; + matrix_load_identity(&mat); + matrix_translate(&mat, -paint->gradient.linear.coords[0], -paint->gradient.linear.coords[1]); + memcpy(&inv, &ctx->state.vg.fill_paint_to_user_matrix, + sizeof(struct matrix)); + matrix_invert(&inv); + matrix_mult(&inv, &mat); + memcpy(&mat, &inv, + sizeof(struct matrix)); + + map[8] = mat.m[0]; map[9] = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f; + map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f; + map[16] = mat.m[2]; map[17] = mat.m[5]; map[18] = mat.m[8]; map[19] = 0.f; + } +#if 0 + debug_printf("Coords (%f, %f, %f, %f)\n", + map[0], map[1], map[2], map[3]); +#endif +} + + +static INLINE void paint_radial_gradient_buffer(struct vg_paint *paint, void *buffer) +{ + VGfloat *radialCoords = paint->gradient.radial.vals; + struct vg_context *ctx = paint->base.ctx; + + VGfloat *map = (VGfloat*)buffer; + + map[0] = radialCoords[0] - radialCoords[2]; + map[1] = radialCoords[1] - radialCoords[3]; + map[2] = -map[0] * map[0] - map[1] * map[1] + + radialCoords[4] * radialCoords[4]; + map[3] = 1.f; + + map[4] = 0.f; + map[5] = 1.f; + map[6] = 2.f; + map[7] = 4.f; + + { + struct matrix mat; + struct matrix inv; + matrix_load_identity(&mat); + matrix_translate(&mat, -radialCoords[2], -radialCoords[3]); + memcpy(&inv, &ctx->state.vg.fill_paint_to_user_matrix, + sizeof(struct matrix)); + matrix_invert(&inv); + matrix_mult(&inv, &mat); + memcpy(&mat, &inv, + sizeof(struct matrix)); + + map[8] = mat.m[0]; map[9] = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f; + map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f; + map[16] = mat.m[2]; map[17] = mat.m[5]; map[18] = mat.m[8]; map[19] = 0.f; + } + +#if 0 + debug_printf("Coords (%f, %f, %f, %f)\n", + map[0], map[1], map[2], map[3]); +#endif +} + + +static INLINE void paint_pattern_buffer(struct vg_paint *paint, void *buffer) +{ + struct vg_context *ctx = paint->base.ctx; + + VGfloat *map = (VGfloat *)buffer; + memcpy(map, paint->solid.color, 4 * sizeof(VGfloat)); + + map[4] = 0.f; + map[5] = 1.f; + map[6] = paint->pattern.texture->width[0]; + map[7] = paint->pattern.texture->height[0]; + { + struct matrix mat; + memcpy(&mat, &ctx->state.vg.fill_paint_to_user_matrix, + sizeof(struct matrix)); + matrix_invert(&mat); + { + struct matrix pm; + memcpy(&pm, &ctx->state.vg.path_user_to_surface_matrix, + sizeof(struct matrix)); + matrix_invert(&pm); + matrix_mult(&pm, &mat); + memcpy(&mat, &pm, sizeof(struct matrix)); + } + + map[8] = mat.m[0]; map[9] = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f; + map[12] = mat.m[1]; map[13] = mat.m[4]; map[14] = mat.m[7]; map[15] = 0.f; + map[16] = mat.m[2]; map[17] = mat.m[5]; map[18] = mat.m[8]; map[19] = 0.f; + } +} + +void paint_set_type(struct vg_paint *paint, VGPaintType type) +{ + paint->type = type; +} + +void paint_set_ramp_stops(struct vg_paint *paint, const VGfloat *stops, + int num) +{ + const VGfloat default_stops[] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; + VGint i; + const VGint num_stops = num / 5; + VGfloat last_coord; + + paint->gradient.num_stops = num; + if (num) { + free(paint->gradient.ramp_stops); + paint->gradient.ramp_stops = malloc(sizeof(VGfloat)*num); + memcpy(paint->gradient.ramp_stops, stops, sizeof(VGfloat)*num); + } else + return; + + /* stops must be in increasing order. the last stop is 1.0. if the + * first one is bigger than 1 then the whole sequence is invalid*/ + if (stops[0] > 1) { + stops = default_stops; + num = 10; + } + last_coord = stops[0]; + for (i = 1; i < num_stops; ++i) { + VGint idx = 5 * i; + VGfloat coord = stops[idx]; + if (!floatsEqual(last_coord, coord) && coord < last_coord) { + stops = default_stops; + num = 10; + break; + } + last_coord = coord; + } + + create_gradient_data(stops, num / 5, paint->gradient.color_data, + 1024); + + if (paint->gradient.texture) { + pipe_texture_reference(&paint->gradient.texture, NULL); + paint->gradient.texture = 0; + } + + paint->gradient.texture = create_gradient_texture(paint); +} + +void paint_set_colori(struct vg_paint *p, + VGuint rgba) +{ + p->solid.color[0] = ((rgba >> 24) & 0xff) / 255.f; + p->solid.color[1] = ((rgba >> 16) & 0xff) / 255.f; + p->solid.color[2] = ((rgba >> 8) & 0xff) / 255.f; + p->solid.color[3] = ((rgba >> 0) & 0xff) / 255.f; +} + +VGuint paint_colori(struct vg_paint *p) +{ +#define F2B(f) (float_to_ubyte(f)) + + return ((F2B(p->solid.color[0]) << 24) | + (F2B(p->solid.color[1]) << 16) | + (F2B(p->solid.color[2]) << 8) | + (F2B(p->solid.color[3]) << 0)); +#undef F2B +} + +void paint_set_linear_gradient(struct vg_paint *paint, + const VGfloat *coords) +{ + memcpy(paint->gradient.linear.coords, coords, sizeof(VGfloat) * 4); +} + +void paint_set_spread_mode(struct vg_paint *paint, + VGint mode) +{ + paint->gradient.spread = mode; + switch(mode) { + case VG_COLOR_RAMP_SPREAD_PAD: + paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + break; + case VG_COLOR_RAMP_SPREAD_REPEAT: + paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_REPEAT; + break; + case VG_COLOR_RAMP_SPREAD_REFLECT: + paint->gradient.sampler.wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT; + break; + } +} + +VGColorRampSpreadMode paint_spread_mode(struct vg_paint *paint) +{ + return paint->gradient.spread; +} + +void paint_set_radial_gradient(struct vg_paint *paint, + const VGfloat *values) +{ + memcpy(paint->gradient.radial.vals, values, sizeof(VGfloat) * 5); +} + +void paint_set_pattern(struct vg_paint *paint, + struct vg_image *img) +{ + if (paint->pattern.texture) + pipe_texture_reference(&paint->pattern.texture, NULL); + + paint->pattern.texture = 0; + pipe_texture_reference(&paint->pattern.texture, + img->texture); +} + +void paint_set_pattern_tiling(struct vg_paint *paint, + VGTilingMode mode) +{ + paint->pattern.tiling_mode = mode; + + switch(mode) { + case VG_TILE_FILL: + paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER; + paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER; + break; + case VG_TILE_PAD: + paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + break; + case VG_TILE_REPEAT: + paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_REPEAT; + paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_REPEAT; + break; + case VG_TILE_REFLECT: + paint->pattern.sampler.wrap_s = PIPE_TEX_WRAP_MIRROR_REPEAT; + paint->pattern.sampler.wrap_t = PIPE_TEX_WRAP_MIRROR_REPEAT; + break; + default: + debug_assert("!Unknown tiling mode"); + } +} + +void paint_get_color(struct vg_paint *paint, + VGfloat *color) +{ + color[0] = paint->solid.color[0]; + color[1] = paint->solid.color[1]; + color[2] = paint->solid.color[2]; + color[3] = paint->solid.color[3]; +} + +void paint_ramp_stops(struct vg_paint *paint, VGfloat *stops, + int num) +{ + memcpy(stops, paint->gradient.ramp_stops, sizeof(VGfloat)*num); +} + +void paint_linear_gradient(struct vg_paint *paint, + VGfloat *coords) +{ + memcpy(coords, paint->gradient.linear.coords, sizeof(VGfloat)*4); +} + +void paint_radial_gradient(struct vg_paint *paint, + VGfloat *coords) +{ + memcpy(coords, paint->gradient.radial.vals, sizeof(VGfloat)*5); +} + +int paint_num_ramp_stops(struct vg_paint *paint) +{ + return paint->gradient.num_stops; +} + +VGPaintType paint_type(struct vg_paint *paint) +{ + return paint->type; +} + +void paint_set_coloriv(struct vg_paint *paint, + const VGint *color) +{ + paint->solid.color[0] = color[0]; + paint->solid.color[1] = color[1]; + paint->solid.color[2] = color[2]; + paint->solid.color[3] = color[3]; + + paint->solid.colori[0] = color[0]; + paint->solid.colori[1] = color[1]; + paint->solid.colori[2] = color[2]; + paint->solid.colori[3] = color[3]; +} + +void paint_get_coloriv(struct vg_paint *paint, + VGint *color) +{ + color[0] = paint->solid.colori[0]; + color[1] = paint->solid.colori[1]; + color[2] = paint->solid.colori[2]; + color[3] = paint->solid.colori[3]; +} + +void paint_set_color_ramp_premultiplied(struct vg_paint *paint, + VGboolean set) +{ + paint->gradient.color_ramps_premultiplied = set; +} + +VGboolean paint_color_ramp_premultiplied(struct vg_paint *paint) +{ + return paint->gradient.color_ramps_premultiplied; +} + +void paint_set_ramp_stopsi(struct vg_paint *paint, const VGint *stops, + int num) +{ + if (num) { + free(paint->gradient.ramp_stopsi); + paint->gradient.ramp_stopsi = malloc(sizeof(VGint)*num); + memcpy(paint->gradient.ramp_stopsi, stops, sizeof(VGint)*num); + } +} + +void paint_ramp_stopsi(struct vg_paint *paint, VGint *stops, + int num) +{ + memcpy(stops, paint->gradient.ramp_stopsi, sizeof(VGint)*num); +} + +void paint_set_linear_gradienti(struct vg_paint *paint, + const VGint *coords) +{ + memcpy(paint->gradient.linear.coordsi, coords, sizeof(VGint) * 4); +} + +void paint_linear_gradienti(struct vg_paint *paint, + VGint *coords) +{ + memcpy(coords, paint->gradient.linear.coordsi, sizeof(VGint)*4); +} + +void paint_set_radial_gradienti(struct vg_paint *paint, + const VGint *values) +{ + memcpy(paint->gradient.radial.valsi, values, sizeof(VGint) * 5); +} + +void paint_radial_gradienti(struct vg_paint *paint, + VGint *coords) +{ + memcpy(coords, paint->gradient.radial.valsi, sizeof(VGint)*5); +} + +VGTilingMode paint_pattern_tiling(struct vg_paint *paint) +{ + return paint->pattern.tiling_mode; +} + +VGint paint_bind_samplers(struct vg_paint *paint, struct pipe_sampler_state **samplers, + struct pipe_texture **textures) +{ + struct vg_context *ctx = vg_current_context(); + + switch(paint->type) { + case VG_PAINT_TYPE_LINEAR_GRADIENT: + case VG_PAINT_TYPE_RADIAL_GRADIENT: { + if (paint->gradient.texture) { + paint->gradient.sampler.min_img_filter = image_sampler_filter(ctx); + paint->gradient.sampler.mag_img_filter = image_sampler_filter(ctx); + samplers[0] = &paint->gradient.sampler; + textures[0] = paint->gradient.texture; + return 1; + } + } + break; + case VG_PAINT_TYPE_PATTERN: { + memcpy(paint->pattern.sampler.border_color, + ctx->state.vg.tile_fill_color, + sizeof(VGfloat) * 4); + paint->pattern.sampler.min_img_filter = image_sampler_filter(ctx); + paint->pattern.sampler.mag_img_filter = image_sampler_filter(ctx); + samplers[0] = &paint->pattern.sampler; + textures[0] = paint->pattern.texture; + return 1; + } + break; + default: + samplers[0] = &paint->pattern.sampler; /* dummy */ + textures[0] = 0; + return 0; + break; + } + return 0; +} + +void paint_resolve_type(struct vg_paint *paint) +{ + if (paint->type == VG_PAINT_TYPE_PATTERN && + !paint->pattern.texture) { + paint->type = VG_PAINT_TYPE_COLOR; + } +} + +VGint paint_constant_buffer_size(struct vg_paint *paint) +{ + switch(paint->type) { + case VG_PAINT_TYPE_COLOR: + return 8 * sizeof(VGfloat);/*4 color + 4 constants (0.f,1.f,2.f,4.f)*/ + break; + case VG_PAINT_TYPE_LINEAR_GRADIENT: + return 20 * sizeof(VGfloat); + break; + case VG_PAINT_TYPE_RADIAL_GRADIENT: + return 20 * sizeof(VGfloat); + break; + case VG_PAINT_TYPE_PATTERN: + return 20 * sizeof(VGfloat); + break; + default: + debug_printf("Uknown paint type: %d\n", paint->type); + } + + return 0; +} + +void paint_fill_constant_buffer(struct vg_paint *paint, + void *buffer) +{ + switch(paint->type) { + case VG_PAINT_TYPE_COLOR: + paint_color_buffer(paint, buffer); + break; + case VG_PAINT_TYPE_LINEAR_GRADIENT: + paint_linear_gradient_buffer(paint, buffer); + break; + case VG_PAINT_TYPE_RADIAL_GRADIENT: + paint_radial_gradient_buffer(paint, buffer); + break; + case VG_PAINT_TYPE_PATTERN: + paint_pattern_buffer(paint, buffer); + break; + + default: + abort(); + } +} diff --git a/src/gallium/state_trackers/vega/paint.h b/src/gallium/state_trackers/vega/paint.h new file mode 100644 index 0000000000..999b5c167c --- /dev/null +++ b/src/gallium/state_trackers/vega/paint.h @@ -0,0 +1,118 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef PAINT_H +#define PAINT_H + +#include "vg_context.h" + +#include "VG/openvg.h" +#include "pipe/p_state.h" + +struct vg_paint; +struct vg_image; +struct pipe_sampler_state; +struct pipe_texture; + +struct vg_paint *paint_create(struct vg_context *ctx); +void paint_destroy(struct vg_paint *paint); + +void paint_set_color(struct vg_paint *paint, + const VGfloat *color); +void paint_get_color(struct vg_paint *paint, + VGfloat *color); + +void paint_set_coloriv(struct vg_paint *paint, + const VGint *color); +void paint_get_coloriv(struct vg_paint *paint, + VGint *color); + +void paint_set_colori(struct vg_paint *paint, + VGuint rgba); + +VGuint paint_colori(struct vg_paint *paint); + +void paint_set_type(struct vg_paint *paint, VGPaintType type); +VGPaintType paint_type(struct vg_paint *paint); +void paint_resolve_type(struct vg_paint *paint); + +void paint_set_linear_gradient(struct vg_paint *paint, + const VGfloat *coords); +void paint_linear_gradient(struct vg_paint *paint, + VGfloat *coords); +void paint_set_linear_gradienti(struct vg_paint *paint, + const VGint *coords); +void paint_linear_gradienti(struct vg_paint *paint, + VGint *coords); + + +void paint_set_radial_gradient(struct vg_paint *paint, + const VGfloat *values); +void paint_radial_gradient(struct vg_paint *paint, + VGfloat *coords); +void paint_set_radial_gradienti(struct vg_paint *paint, + const VGint *values); +void paint_radial_gradienti(struct vg_paint *paint, + VGint *coords); + + +void paint_set_ramp_stops(struct vg_paint *paint, const VGfloat *stops, + int num); +void paint_ramp_stops(struct vg_paint *paint, VGfloat *stops, + int num); + +void paint_set_ramp_stopsi(struct vg_paint *paint, const VGint *stops, + int num); +void paint_ramp_stopsi(struct vg_paint *paint, VGint *stops, + int num); + +int paint_num_ramp_stops(struct vg_paint *paint); + +void paint_set_spread_mode(struct vg_paint *paint, + VGint mode); +VGColorRampSpreadMode paint_spread_mode(struct vg_paint *paint); + + +void paint_set_pattern(struct vg_paint *paint, + struct vg_image *img); +void paint_set_pattern_tiling(struct vg_paint *paint, + VGTilingMode mode); +VGTilingMode paint_pattern_tiling(struct vg_paint *paint); + +void paint_set_color_ramp_premultiplied(struct vg_paint *paint, + VGboolean set); +VGboolean paint_color_ramp_premultiplied(struct vg_paint *paint); + + +VGint paint_bind_samplers(struct vg_paint *paint, struct pipe_sampler_state **samplers, + struct pipe_texture **textures); + +VGint paint_constant_buffer_size(struct vg_paint *paint); +void paint_fill_constant_buffer(struct vg_paint *paint, + void *buffer); + + +#endif diff --git a/src/gallium/state_trackers/vega/path.c b/src/gallium/state_trackers/vega/path.c new file mode 100644 index 0000000000..4fc23a7a27 --- /dev/null +++ b/src/gallium/state_trackers/vega/path.c @@ -0,0 +1,2034 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "path.h" + +#include "stroker.h" +#include "polygon.h" +#include "bezier.h" +#include "matrix.h" +#include "vg_context.h" +#include "util_array.h" +#include "arc.h" +#include "path_utils.h" +#include "paint.h" +#include "shader.h" + +#include "util/u_memory.h" + +#include <assert.h> + +#define DEBUG_PATH 0 + +struct path { + struct vg_object base; + VGbitfield caps; + VGboolean dirty; + VGboolean dirty_stroke; + + VGPathDatatype datatype; + + VGfloat scale; + VGfloat bias; + + VGint num_segments; + + struct array * segments; + struct array * control_points; + + struct { + struct polygon_array polygon_array; + struct matrix matrix; + } fill_polys; + + struct { + struct path *path; + struct matrix matrix; + VGfloat stroke_width; + VGfloat miter_limit; + VGCapStyle cap_style; + VGJoinStyle join_style; + } stroked; +}; + + +static INLINE void data_at(void **data, + struct path *p, + VGint start, VGint count, + VGfloat *out) +{ + VGPathDatatype dt = p->datatype; + VGint i; + VGint end = start + count; + VGfloat *itr = out; + + switch(dt) { + case VG_PATH_DATATYPE_S_8: { + VGbyte **bdata = (VGbyte **)data; + for (i = start; i < end; ++i) { + *itr = (*bdata)[i]; + ++itr; + } + *bdata += count; + } + break; + case VG_PATH_DATATYPE_S_16: { + VGshort **bdata = (VGshort **)data; + for (i = start; i < end; ++i) { + *itr = (*bdata)[i]; + ++itr; + } + *bdata += count; + } + break; + case VG_PATH_DATATYPE_S_32: { + VGint **bdata = (VGint **)data; + for (i = start; i < end; ++i) { + *itr = (*bdata)[i]; + ++itr; + } + *bdata += count; + } + break; + case VG_PATH_DATATYPE_F: { + VGfloat **fdata = (VGfloat **)data; + for (i = start; i < end; ++i) { + *itr = (*fdata)[i]; + ++itr; + } + *fdata += count; + } + break; + default: + debug_assert(!"Unknown path datatype!"); + } +} + + +void vg_float_to_datatype(VGPathDatatype datatype, + VGubyte *common_data, + const VGfloat *data, + VGint num_coords) +{ + VGint i; + switch(datatype) { + case VG_PATH_DATATYPE_S_8: { + for (i = 0; i < num_coords; ++i) { + common_data[i] = (VGubyte)data[i]; + } + } + break; + case VG_PATH_DATATYPE_S_16: { + VGshort *buf = (VGshort*)common_data; + for (i = 0; i < num_coords; ++i) { + buf[i] = (VGshort)data[i]; + } + } + break; + case VG_PATH_DATATYPE_S_32: { + VGint *buf = (VGint*)common_data; + for (i = 0; i < num_coords; ++i) { + buf[i] = (VGint)data[i]; + } + } + break; + case VG_PATH_DATATYPE_F: { + memcpy(common_data, data, sizeof(VGfloat) * num_coords); + } + break; + default: + debug_assert(!"Unknown path datatype!"); + } +} + +static void coords_adjust_by_scale_bias(struct path *p, + void *pdata, VGint num_coords, + VGfloat scale, VGfloat bias, + VGPathDatatype datatype) +{ + VGfloat data[8]; + void *coords = (VGfloat *)pdata; + VGubyte *common_data = (VGubyte *)pdata; + VGint size_dst = size_for_datatype(datatype); + VGint i; + + for (i = 0; i < num_coords; ++i) { + data_at(&coords, p, 0, 1, data); + data[0] = data[0] * scale + bias; + vg_float_to_datatype(datatype, common_data, data, 1); + common_data += size_dst; + } +} + +struct path * path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias, + VGint segmentCapacityHint, + VGint coordCapacityHint, + VGbitfield capabilities) +{ + struct path *path = CALLOC_STRUCT(path); + + vg_init_object(&path->base, vg_current_context(), VG_OBJECT_PATH); + path->caps = capabilities & VG_PATH_CAPABILITY_ALL; + vg_context_add_object(vg_current_context(), VG_OBJECT_PATH, path); + + path->datatype = dt; + path->scale = scale; + path->bias = bias; + + path->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8)); + path->control_points = array_create(size_for_datatype(dt)); + + path->dirty = VG_TRUE; + path->dirty_stroke = VG_TRUE; + + return path; +} + +void path_destroy(struct path *p) +{ + vg_context_remove_object(vg_current_context(), VG_OBJECT_PATH, p); + + array_destroy(p->segments); + array_destroy(p->control_points); + array_destroy(p->fill_polys.polygon_array.array); + + if (p->stroked.path) + path_destroy(p->stroked.path); + + free(p); +} + +VGbitfield path_capabilities(struct path *p) +{ + return p->caps; +} + +void path_set_capabilities(struct path *p, VGbitfield bf) +{ + p->caps = (bf & VG_PATH_CAPABILITY_ALL); +} + +void path_append_data(struct path *p, + VGint numSegments, + const VGubyte * pathSegments, + const void * pathData) +{ + VGint old_segments = p->num_segments; + VGint num_new_coords = num_elements_for_segments(pathSegments, numSegments); + array_append_data(p->segments, pathSegments, numSegments); + array_append_data(p->control_points, pathData, num_new_coords); + + p->num_segments += numSegments; + if (!floatsEqual(p->scale, 1.f) || !floatsEqual(p->bias, 0.f)) { + VGubyte *coords = (VGubyte*)p->control_points->data; + coords_adjust_by_scale_bias(p, + coords + old_segments * p->control_points->datatype_size, + num_new_coords, + p->scale, p->bias, p->datatype); + } + p->dirty = VG_TRUE; + p->dirty_stroke = VG_TRUE; +} + +VGint path_num_segments(struct path *p) +{ + return p->num_segments; +} + +static INLINE void map_if_relative(VGfloat ox, VGfloat oy, + VGboolean relative, + VGfloat *x, VGfloat *y) +{ + if (relative) { + if (x) + *x += ox; + if (y) + *y += oy; + } +} + +static INLINE void close_polygon(struct polygon *current, + VGfloat sx, VGfloat sy, + VGfloat ox, VGfloat oy, + struct matrix *matrix) +{ + if (!floatsEqual(sx, ox) || + !floatsEqual(sy, oy)) { + VGfloat x0 = sx; + VGfloat y0 = sy; + matrix_map_point(matrix, x0, y0, &x0, &y0); + polygon_vertex_append(current, x0, y0); + } +} + +static void convert_path(struct path *p, + VGPathDatatype to, + void *dst, + VGint num_coords) +{ + VGfloat data[8]; + void *coords = (VGfloat *)p->control_points->data; + VGubyte *common_data = (VGubyte *)dst; + VGint size_dst = size_for_datatype(to); + VGint i; + + for (i = 0; i < num_coords; ++i) { + data_at(&coords, p, 0, 1, data); + vg_float_to_datatype(to, common_data, data, 1); + common_data += size_dst; + } +} + + +static void polygon_array_calculate_bounds( struct polygon_array *polyarray ) +{ + struct array *polys = polyarray->array; + VGfloat min_x, max_x; + VGfloat min_y, max_y; + VGfloat bounds[4]; + unsigned i; + + assert(polys); + assert(polys->num_elements); + polygon_bounding_rect((((struct polygon**)polys->data)[0]), bounds); + min_x = bounds[0]; + min_y = bounds[1]; + max_x = bounds[0] + bounds[2]; + max_y = bounds[1] + bounds[3]; + for (i = 1; i < polys->num_elements; ++i) { + struct polygon *p = (((struct polygon**)polys->data)[i]); + polygon_bounding_rect(p, bounds); + min_x = MIN2(min_x, bounds[0]); + min_y = MIN2(min_y, bounds[1]); + max_x = MAX2(max_x, bounds[0] + bounds[2]); + max_y = MAX2(max_y, bounds[1] + bounds[3]); + } + + polyarray->min_x = min_x; + polyarray->min_y = min_y; + polyarray->max_x = max_x; + polyarray->max_y = max_y; +} + + +static struct polygon_array * path_get_fill_polygons(struct path *p, struct matrix *matrix) +{ + VGint i; + struct polygon *current = 0; + VGfloat sx, sy, px, py, ox, oy; + VGfloat x0, y0, x1, y1, x2, y2, x3, y3; + VGfloat data[8]; + void *coords = (VGfloat *)p->control_points->data; + struct array *array; + + if (p->fill_polys.polygon_array.array) + { + if (memcmp( &p->fill_polys.matrix, + matrix, + sizeof *matrix ) == 0 && p->dirty == VG_FALSE) + { + return &p->fill_polys.polygon_array; + } + else { + array_destroy( p->fill_polys.polygon_array.array ); + p->fill_polys.polygon_array.array = NULL; + } + } + + array = array_create(sizeof(struct array*)); + + sx = sy = px = py = ox = oy = 0.f; + + current = polygon_create(32); + + for (i = 0; i < p->num_segments; ++i) { + VGubyte segment = ((VGubyte*)(p->segments->data))[i]; + VGint command = SEGMENT_COMMAND(segment); + VGboolean relative = SEGMENT_ABS_REL(segment); + + switch(command) { + case VG_CLOSE_PATH: + close_polygon(current, sx, sy, ox, oy, matrix); + ox = sx; + oy = sy; + break; + case VG_MOVE_TO: + if (current && polygon_vertex_count(current) > 0) { + /* add polygon */ + close_polygon(current, sx, sy, ox, oy, matrix); + array_append_data(array, ¤t, 1); + current = polygon_create(32); + } + data_at(&coords, p, 0, 2, data); + x0 = data[0]; + y0 = data[1]; + map_if_relative(ox, oy, relative, &x0, &y0); + sx = x0; + sy = y0; + ox = x0; + oy = y0; + px = x0; + py = y0; + matrix_map_point(matrix, x0, y0, &x0, &y0); + polygon_vertex_append(current, x0, y0); + break; + case VG_LINE_TO: + data_at(&coords, p, 0, 2, data); + x0 = data[0]; + y0 = data[1]; + map_if_relative(ox, oy, relative, &x0, &y0); + ox = x0; + oy = y0; + px = x0; + py = y0; + matrix_map_point(matrix, x0, y0, &x0, &y0); + polygon_vertex_append(current, x0, y0); + break; + case VG_HLINE_TO: + data_at(&coords, p, 0, 1, data); + x0 = data[0]; + y0 = oy; + map_if_relative(ox, oy, relative, &x0, 0); + ox = x0; + px = x0; + py = y0; + matrix_map_point(matrix, x0, y0, &x0, &y0); + polygon_vertex_append(current, x0, y0); + break; + case VG_VLINE_TO: + data_at(&coords, p, 0, 1, data); + x0 = ox; + y0 = data[0]; + map_if_relative(ox, oy, relative, 0, &y0); + oy = y0; + px = x0; + py = y0; + matrix_map_point(matrix, x0, y0, &x0, &y0); + polygon_vertex_append(current, x0, y0); + break; + case VG_CUBIC_TO: { + struct bezier bezier; + data_at(&coords, p, 0, 6, data); + x0 = ox; + y0 = oy; + x1 = data[0]; + y1 = data[1]; + x2 = data[2]; + y2 = data[3]; + x3 = data[4]; + y3 = data[5]; + map_if_relative(ox, oy, relative, &x1, &y1); + map_if_relative(ox, oy, relative, &x2, &y2); + map_if_relative(ox, oy, relative, &x3, &y3); + ox = x3; + oy = y3; + px = x2; + py = y2; + assert(matrix_is_affine(matrix)); + matrix_map_point(matrix, x0, y0, &x0, &y0); + matrix_map_point(matrix, x1, y1, &x1, &y1); + matrix_map_point(matrix, x2, y2, &x2, &y2); + matrix_map_point(matrix, x3, y3, &x3, &y3); + bezier_init(&bezier, x0, y0, x1, y1, + x2, y2, x3, y3); + bezier_add_to_polygon(&bezier, current); + } + break; + case VG_QUAD_TO: { + struct bezier bezier; + data_at(&coords, p, 0, 4, data); + x0 = ox; + y0 = oy; + x1 = data[0]; + y1 = data[1]; + x3 = data[2]; + y3 = data[3]; + map_if_relative(ox, oy, relative, &x1, &y1); + map_if_relative(ox, oy, relative, &x3, &y3); + px = x1; + py = y1; + { /* form a cubic out of it */ + x2 = (x3 + 2*x1) / 3.f; + y2 = (y3 + 2*y1) / 3.f; + x1 = (x0 + 2*x1) / 3.f; + y1 = (y0 + 2*y1) / 3.f; + } + ox = x3; + oy = y3; + assert(matrix_is_affine(matrix)); + matrix_map_point(matrix, x0, y0, &x0, &y0); + matrix_map_point(matrix, x1, y1, &x1, &y1); + matrix_map_point(matrix, x2, y2, &x2, &y2); + matrix_map_point(matrix, x3, y3, &x3, &y3); + bezier_init(&bezier, x0, y0, x1, y1, + x2, y2, x3, y3); + bezier_add_to_polygon(&bezier, current); + } + break; + case VG_SQUAD_TO: { + struct bezier bezier; + data_at(&coords, p, 0, 2, data); + x0 = ox; + y0 = oy; + x1 = 2*ox-px; + y1 = 2*oy-py; + x3 = data[0]; + y3 = data[1]; + map_if_relative(ox, oy, relative, &x3, &y3); + px = x1; + py = y1; + { /* form a cubic out of it */ + x2 = (x3 + 2*x1) / 3.f; + y2 = (y3 + 2*y1) / 3.f; + x1 = (x0 + 2*x1) / 3.f; + y1 = (y0 + 2*y1) / 3.f; + } + ox = x3; + oy = y3; + assert(matrix_is_affine(matrix)); + matrix_map_point(matrix, x0, y0, &x0, &y0); + matrix_map_point(matrix, x1, y1, &x1, &y1); + matrix_map_point(matrix, x2, y2, &x2, &y2); + matrix_map_point(matrix, x3, y3, &x3, &y3); + bezier_init(&bezier, x0, y0, x1, y1, + x2, y2, x3, y3); + bezier_add_to_polygon(&bezier, current); + } + break; + case VG_SCUBIC_TO: { + struct bezier bezier; + data_at(&coords, p, 0, 4, data); + x0 = ox; + y0 = oy; + x1 = 2*ox-px; + y1 = 2*oy-py; + x2 = data[0]; + y2 = data[1]; + x3 = data[2]; + y3 = data[3]; + map_if_relative(ox, oy, relative, &x2, &y2); + map_if_relative(ox, oy, relative, &x3, &y3); + ox = x3; + oy = y3; + px = x2; + py = y2; + assert(matrix_is_affine(matrix)); + matrix_map_point(matrix, x0, y0, &x0, &y0); + matrix_map_point(matrix, x1, y1, &x1, &y1); + matrix_map_point(matrix, x2, y2, &x2, &y2); + matrix_map_point(matrix, x3, y3, &x3, &y3); + bezier_init(&bezier, x0, y0, x1, y1, + x2, y2, x3, y3); + bezier_add_to_polygon(&bezier, current); + } + break; + case VG_SCCWARC_TO: + case VG_SCWARC_TO: + case VG_LCCWARC_TO: + case VG_LCWARC_TO: { + VGfloat rh, rv, rot; + struct arc arc; + + data_at(&coords, p, 0, 5, data); + x0 = ox; + y0 = oy; + rh = data[0]; + rv = data[1]; + rot = data[2]; + x1 = data[3]; + y1 = data[4]; + map_if_relative(ox, oy, relative, &x1, &y1); +#if 0 + debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n", + x0, y0, x1, y1, rh, rv, rot); +#endif + arc_init(&arc, command, x0, y0, x1, y1, + rh, rv, rot); + arc_add_to_polygon(&arc, current, + matrix); + ox = x1; + oy = y1; + px = x1; + py = y1; + } + break; + default: + abort(); + assert(!"Unknown segment!"); + } + } + if (current) { + if (polygon_vertex_count(current) > 0) { + close_polygon(current, sx, sy, ox, oy, matrix); + array_append_data(array, ¤t, 1); + } else + polygon_destroy(current); + } + + p->fill_polys.polygon_array.array = array; + p->fill_polys.matrix = *matrix; + + polygon_array_calculate_bounds( &p->fill_polys.polygon_array ); + + p->dirty = VG_FALSE; + + return &p->fill_polys.polygon_array; +} + +VGbyte path_datatype_size(struct path *p) +{ + return size_for_datatype(p->datatype); +} + +VGPathDatatype path_datatype(struct path *p) +{ + return p->datatype; +} + +VGfloat path_scale(struct path *p) +{ + return p->scale; +} + +VGfloat path_bias(struct path *p) +{ + return p->bias; +} + +VGint path_num_coords(struct path *p) +{ + return num_elements_for_segments((VGubyte*)p->segments->data, + p->num_segments); +} + +void path_modify_coords(struct path *p, + VGint startIndex, + VGint numSegments, + const void * pathData) +{ + VGubyte *segments = (VGubyte*)(p->segments->data); + VGint count = num_elements_for_segments(&segments[startIndex], numSegments); + VGint start_cp = num_elements_for_segments(segments, startIndex); + + array_change_data(p->control_points, pathData, start_cp, count); + coords_adjust_by_scale_bias(p, + ((VGubyte*)p->control_points->data) + + (startIndex * p->control_points->datatype_size), + path_num_coords(p), + p->scale, p->bias, p->datatype); + p->dirty = VG_TRUE; + p->dirty_stroke = VG_TRUE; +} + +void path_for_each_segment(struct path *path, + path_for_each_cb cb, + void *user_data) +{ + VGint i; + struct path_for_each_data p; + VGfloat data[8]; + void *coords = (VGfloat *)path->control_points->data; + + p.coords = data; + p.sx = p.sy = p.px = p.py = p.ox = p.oy = 0.f; + p.user_data = user_data; + + for (i = 0; i < path->num_segments; ++i) { + VGint command; + VGboolean relative; + + p.segment = ((VGubyte*)(path->segments->data))[i]; + command = SEGMENT_COMMAND(p.segment); + relative = SEGMENT_ABS_REL(p.segment); + + switch(command) { + case VG_CLOSE_PATH: + cb(path, &p); + break; + case VG_MOVE_TO: + data_at(&coords, path, 0, 2, data); + map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); + cb(path, &p); + p.sx = data[0]; + p.sy = data[1]; + p.ox = data[0]; + p.oy = data[1]; + p.px = data[0]; + p.py = data[1]; + break; + case VG_LINE_TO: + data_at(&coords, path, 0, 2, data); + map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); + cb(path, &p); + p.ox = data[0]; + p.oy = data[1]; + p.px = data[0]; + p.py = data[1]; + break; + case VG_HLINE_TO: + data_at(&coords, path, 0, 1, data); + map_if_relative(p.ox, p.oy, relative, &data[0], 0); + p.segment = VG_LINE_TO; + data[1] = p.oy; + cb(path, &p); + p.ox = data[0]; + p.oy = data[1]; + p.px = data[0]; + p.py = data[1]; + break; + case VG_VLINE_TO: + data_at(&coords, path, 0, 1, data); + map_if_relative(p.ox, p.oy, relative, 0, &data[0]); + p.segment = VG_LINE_TO; + data[1] = data[0]; + data[0] = p.ox; + cb(path, &p); + p.ox = data[0]; + p.oy = data[1]; + p.px = data[0]; + p.py = data[1]; + break; + case VG_CUBIC_TO: { + data_at(&coords, path, 0, 6, data); + map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); + map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]); + map_if_relative(p.ox, p.oy, relative, &data[4], &data[5]); + cb(path, &p); + p.px = data[2]; + p.py = data[3]; + p.ox = data[4]; + p.oy = data[5]; + } + break; + case VG_QUAD_TO: { + data_at(&coords, path, 0, 4, data); + map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); + map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]); + cb(path, &p); + p.px = data[0]; + p.py = data[1]; + p.ox = data[2]; + p.oy = data[3]; + } + break; + case VG_SQUAD_TO: { + data_at(&coords, path, 0, 2, data); + map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); + cb(path, &p); + p.px = 2*p.ox-p.px; + p.py = 2*p.oy-p.py; + p.ox = data[2]; + p.oy = data[3]; + } + break; + case VG_SCUBIC_TO: { + data_at(&coords, path, 0, 4, data); + map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); + map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]); + cb(path, &p); + p.px = data[0]; + p.py = data[1]; + p.ox = data[2]; + p.oy = data[3]; + } + break; + case VG_SCCWARC_TO: + case VG_SCWARC_TO: + case VG_LCCWARC_TO: + case VG_LCWARC_TO: { + data_at(&coords, path, 0, 5, data); + map_if_relative(p.ox, p.oy, relative, &data[3], &data[4]); +#if 0 + debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n", + p.ox, p.oy, data[3], data[4], data[0], data[1], data[2]); +#endif + cb(path, &p); + p.ox = data[3]; + p.oy = data[4]; + p.px = data[3]; + p.py = data[4]; + } + break; + default: + abort(); + assert(!"Unknown segment!"); + } + } +} + +struct transform_data { + struct array *segments; + struct array *coords; + + struct matrix *matrix; + + VGPathDatatype datatype; +}; + +static VGboolean transform_cb(struct path *p, + struct path_for_each_data *pd) +{ + struct transform_data *td = (struct transform_data *)pd->user_data; + VGint num_coords = num_elements_for_segments(&pd->segment, 1); + VGubyte segment = SEGMENT_COMMAND(pd->segment);/* abs bit is 0 */ + VGfloat data[8]; + VGubyte common_data[sizeof(VGfloat)*8]; + + memcpy(data, pd->coords, sizeof(VGfloat) * num_coords); + + switch(segment) { + case VG_CLOSE_PATH: + break; + case VG_MOVE_TO: + matrix_map_point(td->matrix, + data[0], data[1], &data[0], &data[1]); + break; + case VG_LINE_TO: + matrix_map_point(td->matrix, + data[0], data[1], &data[0], &data[1]); + break; + case VG_HLINE_TO: + case VG_VLINE_TO: + assert(0); + break; + case VG_QUAD_TO: + matrix_map_point(td->matrix, + data[0], data[1], &data[0], &data[1]); + matrix_map_point(td->matrix, + data[2], data[3], &data[2], &data[3]); + break; + case VG_CUBIC_TO: + matrix_map_point(td->matrix, + data[0], data[1], &data[0], &data[1]); + matrix_map_point(td->matrix, + data[2], data[3], &data[2], &data[3]); + matrix_map_point(td->matrix, + data[4], data[5], &data[4], &data[5]); + break; + case VG_SQUAD_TO: + matrix_map_point(td->matrix, + data[0], data[1], &data[0], &data[1]); + break; + case VG_SCUBIC_TO: + matrix_map_point(td->matrix, + data[0], data[1], &data[0], &data[1]); + matrix_map_point(td->matrix, + data[2], data[3], &data[2], &data[3]); + break; + case VG_SCCWARC_TO: + case VG_SCWARC_TO: + case VG_LCCWARC_TO: + case VG_LCWARC_TO: { + struct arc arc; + struct path *path = path_create(td->datatype, + 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); + arc_init(&arc, segment, + pd->ox, pd->oy, data[3], data[4], + data[0], data[1], data[2]); + + arc_to_path(&arc, path, td->matrix); + + num_coords = path_num_coords(path); + + array_append_data(td->segments, path->segments->data, + path->num_segments); + array_append_data(td->coords, path->control_points->data, + num_coords); + path_destroy(path); + + return VG_TRUE; + } + break; + default: + break; + } + + vg_float_to_datatype(td->datatype, common_data, data, num_coords); + + array_append_data(td->segments, &pd->segment, 1); + array_append_data(td->coords, common_data, num_coords); + return VG_TRUE; +} + +void path_transform(struct path *dst, struct path *src) +{ + struct transform_data data; + struct vg_context *ctx = dst->base.ctx; + + data.segments = dst->segments; + data.coords = dst->control_points; + data.matrix = &ctx->state.vg.path_user_to_surface_matrix; + data.datatype = dst->datatype; + + path_for_each_segment(src, transform_cb, (void*)&data); + + dst->num_segments = dst->segments->num_elements; + dst->dirty = VG_TRUE; + dst->dirty_stroke = VG_TRUE; +} + +void path_append_path(struct path *dst, + struct path *src) +{ + VGint num_coords = path_num_coords(src); + void *dst_data = malloc(size_for_datatype(dst->datatype) * num_coords); + array_append_data(dst->segments, + src->segments->data, + src->num_segments); + convert_path(src, dst->datatype, + dst_data, num_coords); + array_append_data(dst->control_points, + dst_data, + num_coords); + free(dst_data); + + dst->num_segments += src->num_segments; + dst->dirty = VG_TRUE; + dst->dirty_stroke = VG_TRUE; +} + +static INLINE VGboolean is_segment_arc(VGubyte segment) +{ + VGubyte scommand = SEGMENT_COMMAND(segment); + return (scommand == VG_SCCWARC_TO || + scommand == VG_SCWARC_TO || + scommand == VG_LCCWARC_TO || + scommand == VG_LCWARC_TO); +} + +struct path_iter_data { + struct path *path; + VGubyte segment; + void *coords; + VGfloat px, py, ox, oy, sx, sy; +}; +static INLINE VGubyte normalize_coords(struct path_iter_data *pd, + VGint *num_coords, + VGfloat *data) +{ + VGint command = SEGMENT_COMMAND(pd->segment); + VGboolean relative = SEGMENT_ABS_REL(pd->segment); + + switch(command) { + case VG_CLOSE_PATH: + *num_coords = 0; + pd->ox = pd->sx; + pd->oy = pd->sy; + return VG_CLOSE_PATH; + break; + case VG_MOVE_TO: + data_at(&pd->coords, pd->path, 0, 2, data); + map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]); + pd->sx = data[0]; + pd->sy = data[1]; + pd->ox = data[0]; + pd->oy = data[1]; + pd->px = data[0]; + pd->py = data[1]; + *num_coords = 2; + return VG_MOVE_TO_ABS; + break; + case VG_LINE_TO: + data_at(&pd->coords, pd->path, 0, 2, data); + map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]); + pd->ox = data[0]; + pd->oy = data[1]; + pd->px = data[0]; + pd->py = data[1]; + *num_coords = 2; + return VG_LINE_TO_ABS; + break; + case VG_HLINE_TO: + data_at(&pd->coords, pd->path, 0, 1, data); + map_if_relative(pd->ox, pd->oy, relative, &data[0], 0); + data[1] = pd->oy; + pd->ox = data[0]; + pd->oy = data[1]; + pd->px = data[0]; + pd->py = data[1]; + *num_coords = 2; + return VG_LINE_TO_ABS; + break; + case VG_VLINE_TO: + data_at(&pd->coords, pd->path, 0, 1, data); + map_if_relative(pd->ox, pd->oy, relative, 0, &data[0]); + data[1] = data[0]; + data[0] = pd->ox; + pd->ox = data[0]; + pd->oy = data[1]; + pd->px = data[0]; + pd->py = data[1]; + *num_coords = 2; + return VG_LINE_TO_ABS; + break; + case VG_CUBIC_TO: { + data_at(&pd->coords, pd->path, 0, 6, data); + map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]); + map_if_relative(pd->ox, pd->oy, relative, &data[2], &data[3]); + map_if_relative(pd->ox, pd->oy, relative, &data[4], &data[5]); + pd->px = data[2]; + pd->py = data[3]; + pd->ox = data[4]; + pd->oy = data[5]; + *num_coords = 6; + return VG_CUBIC_TO_ABS; + } + break; + case VG_QUAD_TO: { + VGfloat x0, y0, x1, y1, x2, y2, x3, y3; + data_at(&pd->coords, pd->path, 0, 4, data); + x0 = pd->ox; + y0 = pd->oy; + x1 = data[0]; + y1 = data[1]; + x3 = data[2]; + y3 = data[3]; + map_if_relative(pd->ox, pd->oy, relative, &x1, &y1); + map_if_relative(pd->ox, pd->oy, relative, &x3, &y3); + pd->px = x1; + pd->py = y1; + { /* form a cubic out of it */ + x2 = (x3 + 2*x1) / 3.f; + y2 = (y3 + 2*y1) / 3.f; + x1 = (x0 + 2*x1) / 3.f; + y1 = (y0 + 2*y1) / 3.f; + } + pd->ox = x3; + pd->oy = y3; + data[0] = x1; + data[1] = y1; + data[2] = x2; + data[3] = y2; + data[4] = x3; + data[5] = y3; + *num_coords = 6; + return VG_CUBIC_TO_ABS; + } + break; + case VG_SQUAD_TO: { + VGfloat x0, y0, x1, y1, x2, y2, x3, y3; + data_at(&pd->coords, pd->path, 0, 2, data); + x0 = pd->ox; + y0 = pd->oy; + x1 = 2 * pd->ox - pd->px; + y1 = 2 * pd->oy - pd->py; + x3 = data[0]; + y3 = data[1]; + map_if_relative(pd->ox, pd->oy, relative, &x3, &y3); + pd->px = x1; + pd->py = y1; + { /* form a cubic out of it */ + x2 = (x3 + 2*x1) / 3.f; + y2 = (y3 + 2*y1) / 3.f; + x1 = (x0 + 2*x1) / 3.f; + y1 = (y0 + 2*y1) / 3.f; + } + pd->ox = x3; + pd->oy = y3; + data[0] = x1; + data[1] = y1; + data[2] = x2; + data[3] = y2; + data[4] = x3; + data[5] = y3; + *num_coords = 6; + return VG_CUBIC_TO_ABS; + } + break; + case VG_SCUBIC_TO: { + VGfloat x0, y0, x1, y1, x2, y2, x3, y3; + data_at(&pd->coords, pd->path, 0, 4, data); + x0 = pd->ox; + y0 = pd->oy; + x1 = 2*pd->ox-pd->px; + y1 = 2*pd->oy-pd->py; + x2 = data[0]; + y2 = data[1]; + x3 = data[2]; + y3 = data[3]; + map_if_relative(pd->ox, pd->oy, relative, &x2, &y2); + map_if_relative(pd->ox, pd->oy, relative, &x3, &y3); + pd->ox = x3; + pd->oy = y3; + pd->px = x2; + pd->py = y2; + data[0] = x1; + data[1] = y1; + data[2] = x2; + data[3] = y2; + data[4] = x3; + data[5] = y3; + *num_coords = 6; + return VG_CUBIC_TO_ABS; + } + break; + case VG_SCCWARC_TO: + case VG_SCWARC_TO: + case VG_LCCWARC_TO: + case VG_LCWARC_TO: { + data_at(&pd->coords, pd->path, 0, 5, data); + map_if_relative(pd->ox, pd->oy, relative, &data[3], &data[4]); + pd->ox = data[3]; + pd->oy = data[4]; + pd->px = data[3]; + pd->py = data[4]; + *num_coords = 5; + return command | VG_ABSOLUTE; + } + break; + default: + abort(); + assert(!"Unknown segment!"); + } +} + +static void linearly_interpolate(VGfloat *result, + const VGfloat *start, + const VGfloat *end, + VGfloat amount, + VGint number) +{ + VGint i; + for (i = 0; i < number; ++i) { + result[i] = start[i] + (end[i] - start[i]) * amount; + } +} + +VGboolean path_interpolate(struct path *dst, + struct path *start, struct path *end, + VGfloat amount) +{ + /* temporary path that we can discard if it will turn + * out that start is not compatible with end */ + struct path *res_path = path_create(dst->datatype, + 1.0, 0.0, + 0, 0, dst->caps); + VGint i; + VGfloat start_coords[8]; + VGfloat end_coords[8]; + VGfloat results[8]; + VGubyte common_data[sizeof(VGfloat)*8]; + struct path_iter_data start_iter, end_iter; + + memset(&start_iter, 0, sizeof(struct path_iter_data)); + memset(&end_iter, 0, sizeof(struct path_iter_data)); + + start_iter.path = start; + start_iter.coords = start->control_points->data; + end_iter.path = end; + end_iter.coords = end->control_points->data; + + for (i = 0; i < start->num_segments; ++i) { + VGubyte segment; + VGubyte ssegment, esegment; + VGint snum_coords, enum_coords; + start_iter.segment = ((VGubyte*)(start->segments->data))[i]; + end_iter.segment = ((VGubyte*)(end->segments->data))[i]; + + ssegment = normalize_coords(&start_iter, &snum_coords, + start_coords); + esegment = normalize_coords(&end_iter, &enum_coords, + end_coords); + + if (is_segment_arc(ssegment)) { + if (!is_segment_arc(esegment)) { + path_destroy(res_path); + return VG_FALSE; + } + if (amount > 0.5) + segment = esegment; + else + segment = ssegment; + } else if (is_segment_arc(esegment)) { + path_destroy(res_path); + return VG_FALSE; + } + else if (ssegment != esegment) { + path_destroy(res_path); + return VG_FALSE; + } + else + segment = ssegment; + + linearly_interpolate(results, start_coords, end_coords, + amount, snum_coords); + vg_float_to_datatype(dst->datatype, common_data, results, snum_coords); + path_append_data(res_path, 1, &segment, common_data); + } + + path_append_path(dst, res_path); + path_destroy(res_path); + + dst->dirty = VG_TRUE; + dst->dirty_stroke = VG_TRUE; + + return VG_TRUE; +} + +void path_clear(struct path *p, VGbitfield capabilities) +{ + path_set_capabilities(p, capabilities); + array_destroy(p->segments); + array_destroy(p->control_points); + p->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8)); + p->control_points = array_create(size_for_datatype(p->datatype)); + p->num_segments = 0; + p->dirty = VG_TRUE; + p->dirty_stroke = VG_TRUE; +} + +struct path * path_create_stroke(struct path *p, + struct matrix *matrix) +{ + VGint i; + VGfloat sx, sy, px, py, ox, oy; + VGfloat x0, y0, x1, y1, x2, y2, x3, y3; + VGfloat data[8]; + void *coords = (VGfloat *)p->control_points->data; + int dashed = (p->base.ctx->state.vg.stroke.dash_pattern_num ? 1 : 0); + struct dash_stroker stroker; + struct vg_state *vg_state = &p->base.ctx->state.vg; + + if (p->stroked.path) + { + /* ### compare the dash patterns to see if we can cache them. + * for now we simply always bail out if the path is dashed. + */ + if (memcmp( &p->stroked.matrix, + matrix, + sizeof *matrix ) == 0 && + !dashed && !p->dirty_stroke && + floatsEqual(p->stroked.stroke_width, vg_state->stroke.line_width.f) && + floatsEqual(p->stroked.miter_limit, vg_state->stroke.miter_limit.f) && + p->stroked.cap_style == vg_state->stroke.cap_style && + p->stroked.join_style == vg_state->stroke.join_style) + { + return p->stroked.path; + } + else { + path_destroy( p->stroked.path ); + p->stroked.path = NULL; + } + } + + + sx = sy = px = py = ox = oy = 0.f; + + if (dashed) + dash_stroker_init((struct stroker *)&stroker, vg_state); + else + stroker_init((struct stroker *)&stroker, vg_state); + + stroker_begin((struct stroker *)&stroker); + + for (i = 0; i < p->num_segments; ++i) { + VGubyte segment = ((VGubyte*)(p->segments->data))[i]; + VGint command = SEGMENT_COMMAND(segment); + VGboolean relative = SEGMENT_ABS_REL(segment); + + switch(command) { + case VG_CLOSE_PATH: { + VGfloat x0 = sx; + VGfloat y0 = sy; + matrix_map_point(matrix, x0, y0, &x0, &y0); + stroker_line_to((struct stroker *)&stroker, x0, y0); + } + break; + case VG_MOVE_TO: + data_at(&coords, p, 0, 2, data); + x0 = data[0]; + y0 = data[1]; + map_if_relative(ox, oy, relative, &x0, &y0); + sx = x0; + sy = y0; + ox = x0; + oy = y0; + px = x0; + py = y0; + matrix_map_point(matrix, x0, y0, &x0, &y0); + stroker_move_to((struct stroker *)&stroker, x0, y0); + break; + case VG_LINE_TO: + data_at(&coords, p, 0, 2, data); + x0 = data[0]; + y0 = data[1]; + map_if_relative(ox, oy, relative, &x0, &y0); + ox = x0; + oy = y0; + px = x0; + py = y0; + matrix_map_point(matrix, x0, y0, &x0, &y0); + stroker_line_to((struct stroker *)&stroker, x0, y0); + break; + case VG_HLINE_TO: + data_at(&coords, p, 0, 1, data); + x0 = data[0]; + y0 = oy; + map_if_relative(ox, oy, relative, &x0, 0); + ox = x0; + px = x0; + py = y0; + matrix_map_point(matrix, x0, y0, &x0, &y0); + stroker_line_to((struct stroker *)&stroker, x0, y0); + break; + case VG_VLINE_TO: + data_at(&coords, p, 0, 1, data); + x0 = ox; + y0 = data[0]; + map_if_relative(ox, oy, relative, 0, &y0); + oy = y0; + px = x0; + py = y0; + matrix_map_point(matrix, x0, y0, &x0, &y0); + stroker_line_to((struct stroker *)&stroker, x0, y0); + break; + case VG_CUBIC_TO: { + data_at(&coords, p, 0, 6, data); + x0 = ox; + y0 = oy; + x1 = data[0]; + y1 = data[1]; + x2 = data[2]; + y2 = data[3]; + x3 = data[4]; + y3 = data[5]; + map_if_relative(ox, oy, relative, &x1, &y1); + map_if_relative(ox, oy, relative, &x2, &y2); + map_if_relative(ox, oy, relative, &x3, &y3); + if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && + floatsEqual(x1, x2) && floatsEqual(y1, y2) && + floatsEqual(x2, x3) && floatsEqual(y2, y3)) { + /*ignore the empty segment */ + continue; + } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { + /* if dup vertex, emit a line */ + ox = x3; + oy = y3; + matrix_map_point(matrix, x3, y3, &x3, &y3); + stroker_line_to((struct stroker *)&stroker, x3, y3); + continue; + } + ox = x3; + oy = y3; + px = x2; + py = y2; + assert(matrix_is_affine(matrix)); + matrix_map_point(matrix, x0, y0, &x0, &y0); + matrix_map_point(matrix, x1, y1, &x1, &y1); + matrix_map_point(matrix, x2, y2, &x2, &y2); + matrix_map_point(matrix, x3, y3, &x3, &y3); + stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); + } + break; + case VG_QUAD_TO: { + data_at(&coords, p, 0, 4, data); + x0 = ox; + y0 = oy; + x1 = data[0]; + y1 = data[1]; + x3 = data[2]; + y3 = data[3]; + map_if_relative(ox, oy, relative, &x1, &y1); + map_if_relative(ox, oy, relative, &x3, &y3); + px = x1; + py = y1; + { /* form a cubic out of it */ + x2 = (x3 + 2*x1) / 3.f; + y2 = (y3 + 2*y1) / 3.f; + x1 = (x0 + 2*x1) / 3.f; + y1 = (y0 + 2*y1) / 3.f; + } + if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && + floatsEqual(x1, x2) && floatsEqual(y1, y2) && + floatsEqual(x2, x3) && floatsEqual(y2, y3)) { + /*ignore the empty segment */ + continue; + } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { + /* if dup vertex, emit a line */ + ox = x3; + oy = y3; + matrix_map_point(matrix, x3, y3, &x3, &y3); + stroker_line_to((struct stroker *)&stroker, x3, y3); + continue; + } + ox = x3; + oy = y3; + assert(matrix_is_affine(matrix)); + matrix_map_point(matrix, x0, y0, &x0, &y0); + matrix_map_point(matrix, x1, y1, &x1, &y1); + matrix_map_point(matrix, x2, y2, &x2, &y2); + matrix_map_point(matrix, x3, y3, &x3, &y3); + stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); + } + break; + case VG_SQUAD_TO: { + data_at(&coords, p, 0, 2, data); + x0 = ox; + y0 = oy; + x1 = 2*ox-px; + y1 = 2*oy-py; + x3 = data[0]; + y3 = data[1]; + map_if_relative(ox, oy, relative, &x3, &y3); + px = x1; + py = y1; + { /* form a cubic out of it */ + x2 = (x3 + 2*x1) / 3.f; + y2 = (y3 + 2*y1) / 3.f; + x1 = (x0 + 2*x1) / 3.f; + y1 = (y0 + 2*y1) / 3.f; + } + if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && + floatsEqual(x1, x2) && floatsEqual(y1, y2) && + floatsEqual(x2, x3) && floatsEqual(y2, y3)) { + /*ignore the empty segment */ + continue; + } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { + /* if dup vertex, emit a line */ + ox = x3; + oy = y3; + matrix_map_point(matrix, x3, y3, &x3, &y3); + stroker_line_to((struct stroker *)&stroker, x3, y3); + continue; + } + ox = x3; + oy = y3; + assert(matrix_is_affine(matrix)); + matrix_map_point(matrix, x0, y0, &x0, &y0); + matrix_map_point(matrix, x1, y1, &x1, &y1); + matrix_map_point(matrix, x2, y2, &x2, &y2); + matrix_map_point(matrix, x3, y3, &x3, &y3); + stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); + } + break; + case VG_SCUBIC_TO: { + data_at(&coords, p, 0, 4, data); + x0 = ox; + y0 = oy; + x1 = 2*ox-px; + y1 = 2*oy-py; + x2 = data[0]; + y2 = data[1]; + x3 = data[2]; + y3 = data[3]; + map_if_relative(ox, oy, relative, &x2, &y2); + map_if_relative(ox, oy, relative, &x3, &y3); + if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && + floatsEqual(x1, x2) && floatsEqual(y1, y2) && + floatsEqual(x2, x3) && floatsEqual(y2, y3)) { + /*ignore the empty segment */ + continue; + } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { + /* if dup vertex, emit a line */ + ox = x3; + oy = y3; + matrix_map_point(matrix, x3, y3, &x3, &y3); + stroker_line_to((struct stroker *)&stroker, x3, y3); + continue; + } + ox = x3; + oy = y3; + px = x2; + py = y2; + assert(matrix_is_affine(matrix)); + matrix_map_point(matrix, x0, y0, &x0, &y0); + matrix_map_point(matrix, x1, y1, &x1, &y1); + matrix_map_point(matrix, x2, y2, &x2, &y2); + matrix_map_point(matrix, x3, y3, &x3, &y3); + stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); + } + break; + case VG_SCCWARC_TO: + case VG_SCWARC_TO: + case VG_LCCWARC_TO: + case VG_LCWARC_TO: { + VGfloat rh, rv, rot; + struct arc arc; + + data_at(&coords, p, 0, 5, data); + x0 = ox; + y0 = oy; + rh = data[0]; + rv = data[1]; + rot = data[2]; + x1 = data[3]; + y1 = data[4]; + map_if_relative(ox, oy, relative, &x1, &y1); + if (floatsEqual(x1, ox) && floatsEqual(y1, oy)) { + /* if dup vertex, emit a line */ + ox = x1; + oy = y1; + matrix_map_point(matrix, x1, y1, &x1, &y1); + stroker_line_to((struct stroker *)&stroker, x1, y1); + continue; + } + arc_init(&arc, command, x0, y0, x1, y1, + rh, rv, rot); + arc_stroke_cb(&arc, (struct stroker *)&stroker, + matrix); + ox = x1; + oy = y1; + px = x1; + py = y1; + } + break; + default: + abort(); + assert(!"Unknown segment!"); + } + } + + stroker_end((struct stroker *)&stroker); + + if (dashed) + dash_stroker_cleanup((struct dash_stroker *)&stroker); + else + stroker_cleanup((struct stroker *)&stroker); + + p->stroked.path = stroker.base.path; + p->stroked.matrix = *matrix; + p->dirty_stroke = VG_FALSE; + p->stroked.stroke_width = vg_state->stroke.line_width.f; + p->stroked.miter_limit = vg_state->stroke.miter_limit.f; + p->stroked.cap_style = vg_state->stroke.cap_style; + p->stroked.join_style = vg_state->stroke.join_style; + + return stroker.base.path; +} + +void path_render(struct path *p, VGbitfield paintModes) +{ + struct vg_context *ctx = vg_current_context(); + struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; + + vg_validate_state(ctx); + + shader_set_drawing_image(ctx->shader, VG_FALSE); + shader_set_image(ctx->shader, 0); +#if 0 + fprintf(stderr, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n", + mat->m[0], mat->m[1], mat->m[2], + mat->m[3], mat->m[4], mat->m[5], + mat->m[6], mat->m[7], mat->m[8]); +#endif + if (paintModes & VG_FILL_PATH) { + /* First the fill */ + shader_set_paint(ctx->shader, ctx->state.vg.fill_paint); + shader_bind(ctx->shader); + path_fill(p, mat); + } + + if (paintModes & VG_STROKE_PATH){ + /* 8.7.5: "line width less than or equal to 0 prevents stroking from + * taking place."*/ + if (ctx->state.vg.stroke.line_width.f <= 0) + return; + shader_set_paint(ctx->shader, ctx->state.vg.stroke_paint); + shader_bind(ctx->shader); + path_stroke(p); + } +} + +void path_fill(struct path *p, struct matrix *mat) +{ + struct vg_context *ctx = vg_current_context(); + { + struct polygon_array *polygon_array = path_get_fill_polygons(p, mat); + struct array *polys = polygon_array->array; + + if (!polygon_array || !polys || !polys->num_elements) { + return; + } + polygon_array_fill(polygon_array, ctx); + } +} + +void path_stroke(struct path *p) +{ + struct vg_context *ctx = vg_current_context(); + struct matrix *mat = &ctx->state.vg.path_user_to_surface_matrix; + VGFillRule old_fill = ctx->state.vg.fill_rule; + struct matrix identity; + struct path *stroke; + + matrix_load_identity(&identity); + stroke = path_create_stroke(p, &identity); + if (stroke && !path_is_empty(stroke)) { + ctx->state.vg.fill_rule = VG_NON_ZERO; + + path_fill(stroke, mat); + + ctx->state.vg.fill_rule = old_fill; + } +} + +void path_move_to(struct path *p, float x, float y) +{ + VGubyte segment = VG_MOVE_TO_ABS; + VGubyte common_data[sizeof(VGfloat) * 2]; + VGfloat data[2] = {x, y}; + + vg_float_to_datatype(p->datatype, common_data, data, 2); + path_append_data(p, 1, &segment, common_data); +} + +void path_line_to(struct path *p, float x, float y) +{ + VGubyte segment = VG_LINE_TO_ABS; + VGubyte common_data[sizeof(VGfloat) * 2]; + VGfloat data[2] = {x, y}; + + vg_float_to_datatype(p->datatype, common_data, data, 2); + + path_append_data(p, 1, &segment, common_data); +} + +void path_cubic_to(struct path *p, float px1, float py1, + float px2, float py2, + float x, float y) +{ + VGubyte segment = VG_CUBIC_TO_ABS; + VGubyte common_data[sizeof(VGfloat) * 6]; + VGfloat data[6]; + + data[0] = px1; data[1] = py1; + data[2] = px2; data[3] = py2; + data[4] = x; data[5] = y; + + vg_float_to_datatype(p->datatype, common_data, data, 6); + + path_append_data(p, 1, &segment, common_data); +} + +static INLINE void line_bounds(VGfloat *line /*x1,y1,x2,y2*/, + VGfloat *bounds) +{ + bounds[0] = MIN2(line[0], line[2]); + bounds[1] = MIN2(line[1], line[3]); + bounds[2] = MAX2(line[0], line[2]) - bounds[0]; + bounds[3] = MAX2(line[1], line[3]) - bounds[1]; +} + +static INLINE void unite_bounds(VGfloat *bounds, + VGfloat *el) +{ + VGfloat cx1, cy1, cx2, cy2; + VGfloat nx1, ny1, nx2, ny2; + + cx1 = bounds[0]; + cy1 = bounds[1]; + cx2 = bounds[0] + bounds[2]; + cy2 = bounds[1] + bounds[3]; + + nx1 = el[0]; + ny1 = el[1]; + nx2 = el[0] + el[2]; + ny2 = el[1] + el[3]; + + bounds[0] = MIN2(cx1, nx1); + bounds[1] = MIN2(cy1, ny1); + bounds[2] = MAX2(cx2, nx2) - bounds[0]; + bounds[3] = MAX2(cy2, ny2) - bounds[1]; +} + +static INLINE void set_bounds(VGfloat *bounds, + VGfloat *element_bounds, + VGboolean *initialized) +{ + if (!(*initialized)) { + memcpy(bounds, element_bounds, 4 * sizeof(VGfloat)); + *initialized = VG_TRUE; + } else + unite_bounds(bounds, element_bounds); +} + +void path_bounding_rect(struct path *p, float *x, float *y, + float *w, float *h) +{ + VGint i; + VGfloat coords[8]; + struct path_iter_data iter; + VGint num_coords; + VGfloat bounds[4]; + VGfloat element_bounds[4]; + VGfloat ox, oy; + VGboolean bounds_inited = VG_FALSE; + + memset(&iter, 0, sizeof(struct path_iter_data)); + memset(&bounds, 0, sizeof(bounds)); + + if (!p->num_segments) { + bounds[2] = -1; + bounds[3] = -1; + } + + + iter.path = p; + iter.coords = p->control_points->data; + + for (i = 0; i < p->num_segments; ++i) { + VGubyte segment; + iter.segment = ((VGubyte*)(p->segments->data))[i]; + + ox = iter.ox; + oy = iter.oy; + + segment = normalize_coords(&iter, &num_coords, coords); + + switch(segment) { + case VG_CLOSE_PATH: + case VG_MOVE_TO_ABS: + break; + case VG_LINE_TO_ABS: { + VGfloat line[4] = {ox, oy, coords[0], coords[1]}; + line_bounds(line, element_bounds); + set_bounds(bounds, element_bounds, &bounds_inited); + } + break; + case VG_CUBIC_TO_ABS: { + struct bezier bezier; + bezier_init(&bezier, ox, oy, + coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5]); + bezier_exact_bounds(&bezier, element_bounds); + set_bounds(bounds, element_bounds, &bounds_inited); + } + break; + case VG_SCCWARC_TO: + case VG_SCWARC_TO: + case VG_LCCWARC_TO: + case VG_LCWARC_TO: { + struct arc arc; + struct matrix identity; + struct path *path = path_create(VG_PATH_DATATYPE_F, + 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); + + matrix_load_identity(&identity); + arc_init(&arc, segment, + ox, oy, coords[3], coords[4], + coords[0], coords[1], coords[2]); + + arc_to_path(&arc, path, &identity); + + path_bounding_rect(path, element_bounds + 0, element_bounds + 1, + element_bounds + 2, element_bounds + 3); + set_bounds(bounds, element_bounds, &bounds_inited); + } + break; + default: + assert(0); + } + } + + *x = bounds[0]; + *y = bounds[1]; + *w = bounds[2]; + *h = bounds[3]; +} + +float path_length(struct path *p, int start_segment, int num_segments) +{ + VGint i; + VGfloat coords[8]; + struct path_iter_data iter; + VGint num_coords; + VGfloat length = 0; + VGfloat ox, oy; + VGboolean in_range = VG_FALSE; + + memset(&iter, 0, sizeof(struct path_iter_data)); + + iter.path = p; + iter.coords = p->control_points->data; + + for (i = 0; i < (start_segment + num_segments); ++i) { + VGubyte segment; + + iter.segment = ((VGubyte*)(p->segments->data))[i]; + + ox = iter.ox; + oy = iter.oy; + + segment = normalize_coords(&iter, &num_coords, coords); + + in_range = (i >= start_segment) && i <= (start_segment + num_segments); + if (!in_range) + continue; + + switch(segment) { + case VG_MOVE_TO_ABS: + break; + case VG_CLOSE_PATH: { + VGfloat line[4] = {ox, oy, iter.sx, iter.sy}; + length += line_lengthv(line); + } + break; + case VG_LINE_TO_ABS: { + VGfloat line[4] = {ox, oy, coords[0], coords[1]}; + length += line_lengthv(line); + } + break; + case VG_CUBIC_TO_ABS: { + struct bezier bezier; + bezier_init(&bezier, ox, oy, + coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5]); + length += bezier_length(&bezier, BEZIER_DEFAULT_ERROR); + } + break; + case VG_SCCWARC_TO: + case VG_SCWARC_TO: + case VG_LCCWARC_TO: + case VG_LCWARC_TO: { + struct arc arc; + struct matrix identity; + struct path *path = path_create(VG_PATH_DATATYPE_F, + 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); + + matrix_load_identity(&identity); + arc_init(&arc, segment, + ox, oy, coords[3], coords[4], + coords[0], coords[1], coords[2]); + + arc_to_path(&arc, path, &identity); + + length += path_length(path, 0, path_num_segments(path)); + } + break; + default: + assert(0); + } + } + + return length; +} + +static INLINE VGboolean point_on_current_segment(VGfloat distance, + VGfloat length, + VGfloat segment_length) +{ + return + (((floatIsZero(distance) || distance < 0) && floatIsZero(length)) || + ((distance > length || floatsEqual(distance, length)) && + (floatsEqual(distance, length + segment_length) || + distance < (length + segment_length)))); +} + +static VGboolean path_point_segment(struct path_iter_data iter, + struct path_iter_data prev_iter, + VGfloat coords[8], + VGfloat distance, + VGfloat length, VGfloat *current_length, + VGfloat *point, VGfloat *normal) +{ + switch (iter.segment) { + case VG_MOVE_TO_ABS: + break; + case VG_CLOSE_PATH: { + VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy}; + VGboolean on_current_segment = VG_FALSE; + *current_length = line_lengthv(line); + on_current_segment = point_on_current_segment(distance, + length, + *current_length); + if (on_current_segment) { + VGfloat at = (distance - length) / line_lengthv(line); + line_normal_vector(line, normal); + line_point_at(line, at, point); + return VG_TRUE; + } + } + break; + case VG_LINE_TO_ABS: { + VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]}; + VGboolean on_current_segment = VG_FALSE; + *current_length = line_lengthv(line); + on_current_segment = point_on_current_segment(distance, + length, + *current_length); + if (on_current_segment) { + VGfloat at = (distance - length) / line_lengthv(line); + line_normal_vector(line, normal); + line_point_at(line, at, point); + return VG_TRUE; + } + } + break; + case VG_CUBIC_TO_ABS: { + struct bezier bezier; + bezier_init(&bezier, prev_iter.ox, prev_iter.oy, + coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5]); + *current_length = bezier_length(&bezier, BEZIER_DEFAULT_ERROR); + if (point_on_current_segment(distance, length, *current_length)) { + bezier_point_at_length(&bezier, distance - length, + point, normal); + return VG_TRUE; + } + } + break; + case VG_SCCWARC_TO: + case VG_SCWARC_TO: + case VG_LCCWARC_TO: + case VG_LCWARC_TO: { + struct arc arc; + struct matrix identity; + struct path *path = path_create(VG_PATH_DATATYPE_F, + 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); + + matrix_load_identity(&identity); + arc_init(&arc, iter.segment, + prev_iter.ox, prev_iter.oy, coords[3], coords[4], + coords[0], coords[1], coords[2]); + + arc_to_path(&arc, path, &identity); + + *current_length = path_length(path, 0, path_num_segments(path)); + if (point_on_current_segment(distance, length, *current_length)) { + path_point(path, 0, path_num_segments(path), + distance - length, point, normal); + return VG_TRUE; + } + } + break; + default: + assert(0); + } + return VG_FALSE; +} + +void path_point(struct path *p, VGint start_segment, VGint num_segments, + VGfloat distance, VGfloat *point, VGfloat *normal) +{ + VGint i; + VGfloat coords[8]; + struct path_iter_data iter, prev_iter; + VGint num_coords; + VGfloat length = 0; + VGfloat current_length = 0; + + memset(&iter, 0, sizeof(struct path_iter_data)); + memset(&prev_iter, 0, sizeof(struct path_iter_data)); + + point[0] = 0; + point[1] = 0; + + normal[0] = 0; + normal[1] = -1; + + iter.path = p; + iter.coords = p->control_points->data; + if (distance < 0) + distance = 0; + + for (i = 0; i < (start_segment + num_segments); ++i) { + VGboolean outside_range = (i < start_segment || + i >= (start_segment + num_segments)); + + prev_iter = iter; + + iter.segment = ((VGubyte*)(p->segments->data))[i]; + iter.segment = normalize_coords(&iter, &num_coords, coords); + + if (outside_range) + continue; + + if (path_point_segment(iter, prev_iter, coords, + distance, length, ¤t_length, + point, normal)) + return; + + length += current_length; + } + + /* + *OpenVG 1.0 - 8.6.11 vgPointAlongPath + * + * If distance is greater than or equal to the path length + *(i.e., the value returned by vgPathLength when called with the same + *startSegment and numSegments parameters), the visual ending point of + *the path is used. + */ + { + switch (iter.segment) { + case VG_MOVE_TO_ABS: + break; + case VG_CLOSE_PATH: { + VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy}; + line_normal_vector(line, normal); + line_point_at(line, 1.f, point); + } + break; + case VG_LINE_TO_ABS: { + VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]}; + line_normal_vector(line, normal); + line_point_at(line, 1.f, point); + } + break; + case VG_CUBIC_TO_ABS: { + struct bezier bezier; + bezier_init(&bezier, prev_iter.ox, prev_iter.oy, + coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5]); + bezier_point_at_t(&bezier, 1.f, point, normal); + } + break; + case VG_SCCWARC_TO: + case VG_SCWARC_TO: + case VG_LCCWARC_TO: + case VG_LCWARC_TO: { + struct arc arc; + struct matrix identity; + struct path *path = path_create(VG_PATH_DATATYPE_F, + 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); + + matrix_load_identity(&identity); + arc_init(&arc, iter.segment, + prev_iter.ox, prev_iter.oy, coords[3], coords[4], + coords[0], coords[1], coords[2]); + + arc_to_path(&arc, path, &identity); + + path_point(path, 0, path_num_segments(path), + /* to make sure we're bigger than len * 2 it */ + 2 * path_length(path, 0, path_num_segments(path)), + point, normal); + } + break; + default: + assert(0); + } + } +} + +VGboolean path_is_empty(struct path *p) +{ + return p->segments->num_elements == 0; +} diff --git a/src/gallium/state_trackers/vega/path.h b/src/gallium/state_trackers/vega/path.h new file mode 100644 index 0000000000..e34538b736 --- /dev/null +++ b/src/gallium/state_trackers/vega/path.h @@ -0,0 +1,126 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef _PATH_H +#define _PATH_H + +#include "VG/openvg.h" + +struct path; +struct polygon; +struct matrix; + +enum fill_rule { + ODD_EVEN_FILL, + WINDING_FILL +}; + + +struct path_for_each_data { + VGubyte segment; + /* all coords are absolute, even if segment is relative */ + const VGfloat *coords; + VGfloat sx, sy, ox, oy, px, py; + void *user_data; +}; + +typedef VGboolean (*path_for_each_cb)(struct path *p, + struct path_for_each_data *data); + + +struct path *path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias, + VGint segmentCapacityHint, + VGint coordCapacityHint, + VGbitfield capabilities); +void path_destroy(struct path *p); + +VGbitfield path_capabilities(struct path *p); +void path_set_capabilities(struct path *p, VGbitfield bf); + +void path_append_data(struct path *p, + VGint numSegments, + const VGubyte * pathSegments, + const void * pathData); + +void path_append_path(struct path *dst, + struct path *src); + +VGint path_num_segments(struct path *p); + +void path_bounding_rect(struct path *p, float *x, float *y, + float *w, float *h); +float path_length(struct path *p, int start_segment, int num_segments); + +void path_set_fill_rule(enum fill_rule fill); +enum fill_rule path_fill_rule(enum fill_rule fill); + +VGboolean path_is_empty(struct path *p); + +VGbyte path_datatype_size(struct path *p); + +VGPathDatatype path_datatype(struct path *p); +VGfloat path_scale(struct path *p); +VGfloat path_bias(struct path *p); +VGint path_num_coords(struct path *p); + +void path_modify_coords(struct path *p, + VGint startIndex, + VGint numSegments, + const void * pathData); + +struct path *path_create_stroke(struct path *p, + struct matrix *m); + +void path_for_each_segment(struct path *path, + path_for_each_cb cb, + void *user_data); + +void path_transform(struct path *dst, struct path *src); +VGboolean path_interpolate(struct path *dst, + struct path *start, struct path *end, + VGfloat amount); + +void path_clear(struct path *p, VGbitfield capabilities); +void path_render(struct path *p, VGbitfield paintModes); +void path_fill(struct path *p, struct matrix *mat); +void path_stroke(struct path *p); + +void path_move_to(struct path *p, float x, float y); +void path_line_to(struct path *p, float x, float y); +void path_cubic_to(struct path *p, float px1, float py1, + float px2, float py2, + float x, float y); + +void path_point(struct path *p, VGint startSegment, VGint numSegments, + VGfloat distance, VGfloat *point, VGfloat *normal); + + + +void vg_float_to_datatype(VGPathDatatype datatype, + VGubyte *common_data, + const VGfloat *data, + VGint num_coords); +#endif diff --git a/src/gallium/state_trackers/vega/path_utils.h b/src/gallium/state_trackers/vega/path_utils.h new file mode 100644 index 0000000000..c2b3221dc5 --- /dev/null +++ b/src/gallium/state_trackers/vega/path_utils.h @@ -0,0 +1,109 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef PATH_UTILS_H +#define PATH_UTILS_H + +#include "VG/openvg.h" + +#define SEGMENT_COMMAND(command) /* Extract segment type */ \ + ((command) & 0x1e) +#define SEGMENT_ABS_REL(command) /* Extract absolute/relative bit */ \ + ((command) & 0x1) + +static INLINE VGint size_for_datatype(VGPathDatatype datatype) +{ + switch(datatype) { + case VG_PATH_DATATYPE_S_8: + return 1; + case VG_PATH_DATATYPE_S_16: + return 2; + case VG_PATH_DATATYPE_S_32: + return 4; + case VG_PATH_DATATYPE_F: + return 4; + default: + assert(!"unknown datatype"); + } + return 0; +} + +static INLINE VGint num_elements_for_segments(const VGubyte *segments, + VGint num_segments) +{ + VGint i; + VGint count = 0; + + for (i = 0; i < num_segments; ++i) { + VGubyte segment = segments[i]; + VGint command = SEGMENT_COMMAND(segment); + switch(command) { + case VG_CLOSE_PATH: + break; + case VG_MOVE_TO: + count += 2; + break; + case VG_LINE_TO: + count += 2; + break; + case VG_HLINE_TO: + count += 1; + break; + case VG_VLINE_TO: + count += 1; + break; + case VG_QUAD_TO: + count += 4; + break; + case VG_CUBIC_TO: + count += 6; + break; + case VG_SQUAD_TO: + count += 2; + break; + case VG_SCUBIC_TO: + count += 4; + break; + case VG_SCCWARC_TO: + count += 5; + break; + case VG_SCWARC_TO: + count += 5; + break; + case VG_LCCWARC_TO: + count += 5; + break; + case VG_LCWARC_TO: + count += 5; + break; + default: + assert(!"Unknown segment!"); + } + } + return count; +} + +#endif diff --git a/src/gallium/state_trackers/vega/polygon.c b/src/gallium/state_trackers/vega/polygon.c new file mode 100644 index 0000000000..b6d282d803 --- /dev/null +++ b/src/gallium/state_trackers/vega/polygon.c @@ -0,0 +1,550 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "polygon.h" + +#include "matrix.h" /*for floatsEqual*/ +#include "vg_context.h" +#include "vg_state.h" +#include "paint.h" +#include "renderer.h" +#include "util_array.h" +#include "VG/openvg.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_state.h" +#include "pipe/p_inlines.h" +#include "pipe/p_screen.h" + +#include "util/u_draw_quad.h" +#include "util/u_math.h" + +#include <string.h> +#include <stdlib.h> + +#define DEBUG_POLYGON 0 + +#define COMPONENTS 2 + +struct polygon +{ + VGfloat *data; + VGint size; + + VGint num_verts; + + VGboolean dirty; + struct pipe_buffer *vbuf; + struct pipe_screen *screen; +}; + +static float *ptr_to_vertex(float *data, int idx) +{ + return data + (idx * COMPONENTS); +} + +#if 0 +static void polygon_print(struct polygon *poly) +{ + int i; + float *vert; + debug_printf("Polygon %p, size = %d\n", poly, poly->num_verts); + for (i = 0; i < poly->num_verts; ++i) { + vert = ptr_to_vertex(poly->data, i); + debug_printf("%f, %f, ", vert[0], vert[1]); + } + debug_printf("\nend\n"); +} +#endif + + +struct polygon * polygon_create(int size) +{ + struct polygon *poly = (struct polygon*)malloc(sizeof(struct polygon)); + + poly->data = malloc(sizeof(float) * COMPONENTS * size); + poly->size = size; + poly->num_verts = 0; + poly->dirty = VG_TRUE; + poly->vbuf = NULL; + + return poly; +} + +struct polygon * polygon_create_from_data(float *data, int size) +{ + struct polygon *poly = polygon_create(size); + + memcpy(poly->data, data, sizeof(float) * COMPONENTS * size); + poly->num_verts = size; + poly->dirty = VG_TRUE; + poly->vbuf = NULL; + + return poly; +} + +void polygon_destroy(struct polygon *poly) +{ + if (poly->vbuf) + pipe_buffer_reference(&poly->vbuf, NULL); + + free(poly->data); + free(poly); +} + +void polygon_resize(struct polygon *poly, int new_size) +{ + float *data = (float*)malloc(sizeof(float) * COMPONENTS * new_size); + int size = MIN2(sizeof(float) * COMPONENTS * new_size, + sizeof(float) * COMPONENTS * poly->size); + memcpy(data, poly->data, size); + free(poly->data); + poly->data = data; + poly->size = new_size; + poly->dirty = VG_TRUE; +} + +int polygon_size(struct polygon *poly) +{ + return poly->size; +} + +int polygon_vertex_count(struct polygon *poly) +{ + return poly->num_verts; +} + +float * polygon_data(struct polygon *poly) +{ + return poly->data; +} + +void polygon_vertex_append(struct polygon *p, + float x, float y) +{ + float *vert; +#if DEBUG_POLYGON + debug_printf("Append vertex [%f, %f]\n", x, y); +#endif + if (p->num_verts >= p->size) { + polygon_resize(p, p->size * 2); + } + + vert = ptr_to_vertex(p->data, p->num_verts); + vert[0] = x; + vert[1] = y; + ++p->num_verts; + p->dirty = VG_TRUE; +} + +void polygon_set_vertex(struct polygon *p, int idx, + float x, float y) +{ + float *vert; + if (idx >= p->num_verts) { + /*fixme: error reporting*/ + abort(); + return; + } + + vert = ptr_to_vertex(p->data, idx); + vert[0] = x; + vert[1] = y; + p->dirty = VG_TRUE; +} + +void polygon_vertex(struct polygon *p, int idx, + float *vertex) +{ + float *vert; + if (idx >= p->num_verts) { + /*fixme: error reporting*/ + abort(); + return; + } + + vert = ptr_to_vertex(p->data, idx); + vertex[0] = vert[0]; + vertex[1] = vert[1]; +} + +void polygon_bounding_rect(struct polygon *p, + float *rect) +{ + int i; + float minx, miny, maxx, maxy; + float *vert = ptr_to_vertex(p->data, 0); + minx = vert[0]; + maxx = vert[0]; + miny = vert[1]; + maxy = vert[1]; + + for (i = 1; i < p->num_verts; ++i) { + vert = ptr_to_vertex(p->data, i); + minx = MIN2(vert[0], minx); + miny = MIN2(vert[1], miny); + + maxx = MAX2(vert[0], maxx); + maxy = MAX2(vert[1], maxy); + } + + rect[0] = minx; + rect[1] = miny; + rect[2] = maxx - minx; + rect[3] = maxy - miny; +} + +int polygon_contains_point(struct polygon *p, + float x, float y) +{ + return 0; +} + +void polygon_append_polygon(struct polygon *dst, + struct polygon *src) +{ + if (dst->num_verts + src->num_verts >= dst->size) { + polygon_resize(dst, dst->num_verts + src->num_verts * 1.5); + } + memcpy(ptr_to_vertex(dst->data, dst->num_verts), + src->data, src->num_verts * COMPONENTS * sizeof(VGfloat)); + dst->num_verts += src->num_verts; +} + +VGboolean polygon_is_closed(struct polygon *p) +{ + VGfloat start[2], end[2]; + + polygon_vertex(p, 0, start); + polygon_vertex(p, p->num_verts - 1, end); + + return floatsEqual(start[0], end[0]) && floatsEqual(start[1], end[1]); +} + +static void set_blend_for_fill(struct pipe_blend_state *blend) +{ + memset(blend, 0, sizeof(struct pipe_blend_state)); + blend->colormask = 0; /*disable colorwrites*/ + + blend->rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend->rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; + blend->alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; +} + +static void draw_polygon(struct vg_context *ctx, + struct polygon *poly) +{ + int vert_size; + struct pipe_context *pipe; + struct pipe_vertex_buffer vbuffer; + struct pipe_vertex_element velement; + + vert_size = poly->num_verts * COMPONENTS * sizeof(float); + + /*polygon_print(poly);*/ + + pipe = ctx->pipe; + + if (poly->vbuf == NULL || poly->dirty) { + if (poly->vbuf) { + pipe_buffer_reference(&poly->vbuf, + NULL); + } + poly->screen = pipe->screen; + poly->vbuf= pipe_user_buffer_create(poly->screen, + poly->data, + vert_size); + poly->dirty = VG_FALSE; + } + + + /* tell pipe about the vertex buffer */ + memset(&vbuffer, 0, sizeof(vbuffer)); + vbuffer.buffer = poly->vbuf; + vbuffer.stride = COMPONENTS * sizeof(float); /* vertex size */ + vbuffer.buffer_offset = 0; + vbuffer.max_index = poly->num_verts - 1; + pipe->set_vertex_buffers(pipe, 1, &vbuffer); + + /* tell pipe about the vertex attributes */ + velement.src_offset = 0; + velement.vertex_buffer_index = 0; + velement.src_format = PIPE_FORMAT_R32G32_FLOAT; + velement.nr_components = COMPONENTS; + pipe->set_vertex_elements(pipe, 1, &velement); + + /* draw */ + pipe->draw_arrays(pipe, PIPE_PRIM_TRIANGLE_FAN, + 0, poly->num_verts); +} + +void polygon_fill(struct polygon *poly, struct vg_context *ctx) +{ + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_blend_state blend; + VGfloat bounds[4]; + VGfloat min_x, min_y, max_x, max_y; + assert(poly); + polygon_bounding_rect(poly, bounds); + min_x = bounds[0]; + min_y = bounds[1]; + max_x = bounds[0] + bounds[2]; + max_y = bounds[1] + bounds[3]; + +#if DEBUG_POLYGON + debug_printf("Poly bounds are [%f, %f], [%f, %f]\n", + min_x, min_y, max_x, max_y); +#endif + + set_blend_for_fill(&blend); + + memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); + + cso_save_blend(ctx->cso_context); + cso_save_depth_stencil_alpha(ctx->cso_context); + + dsa.stencil[0].enabled = 1; + if (ctx->state.vg.fill_rule == VG_EVEN_ODD) { + dsa.stencil[0].writemask = 1; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT; + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].ref_value = 0; + dsa.stencil[0].valuemask = ~0; + + cso_set_blend(ctx->cso_context, &blend); + cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); + draw_polygon(ctx, poly); + } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) { + struct pipe_screen *screen = ctx->pipe->screen; + + if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { + /* front */ + dsa.stencil[0].writemask = ~0; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].ref_value = 0; + dsa.stencil[0].valuemask = ~0; + + /* back */ + dsa.stencil[1].enabled = 1; + dsa.stencil[1].writemask = ~0; + dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; + dsa.stencil[1].func = PIPE_FUNC_ALWAYS; + dsa.stencil[1].ref_value = 0; + dsa.stencil[1].valuemask = ~0; + + cso_set_blend(ctx->cso_context, &blend); + cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); + draw_polygon(ctx, poly); + } else { + struct pipe_rasterizer_state raster; + + memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state)); + + cso_save_rasterizer(ctx->cso_context); + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].ref_value = 0; + dsa.stencil[0].valuemask = ~0; + + raster.cull_mode = raster.front_winding ^ PIPE_WINDING_BOTH; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; + + cso_set_blend(ctx->cso_context, &blend); + cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); + cso_set_rasterizer(ctx->cso_context, &raster); + draw_polygon(ctx, poly); + + raster.cull_mode = raster.front_winding; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; + cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); + cso_set_rasterizer(ctx->cso_context, &raster); + draw_polygon(ctx, poly); + + cso_restore_rasterizer(ctx->cso_context); + } + } + + /* restore color writes */ + cso_restore_blend(ctx->cso_context); + /* setup stencil ops */ + dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].ref_value = 0; + dsa.stencil[0].valuemask = dsa.stencil[0].writemask; + dsa.stencil[1].enabled = 0; + memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth, + sizeof(struct pipe_depth_state)); + cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); + + /* render the quad to propagate the rendering from stencil */ + renderer_draw_quad(ctx->renderer, min_x, min_y, + max_x, max_y, 0.0f/*depth should be disabled*/); + + cso_restore_depth_stencil_alpha(ctx->cso_context); +} + +void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx) +{ + struct array *polys = polyarray->array; + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_blend_state blend; + VGfloat min_x = polyarray->min_x; + VGfloat min_y = polyarray->min_y; + VGfloat max_x = polyarray->max_x; + VGfloat max_y = polyarray->max_y; + VGint i; + + +#if DEBUG_POLYGON + debug_printf("%s: Poly bounds are [%f, %f], [%f, %f]\n", + __FUNCTION__, + min_x, min_y, max_x, max_y); +#endif + + set_blend_for_fill(&blend); + + memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); + + cso_save_blend(ctx->cso_context); + cso_save_depth_stencil_alpha(ctx->cso_context); + + dsa.stencil[0].enabled = 1; + if (ctx->state.vg.fill_rule == VG_EVEN_ODD) { + dsa.stencil[0].writemask = 1; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INVERT; + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].ref_value = 0; + dsa.stencil[0].valuemask = ~0; + + cso_set_blend(ctx->cso_context, &blend); + cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); + for (i = 0; i < polys->num_elements; ++i) { + struct polygon *poly = (((struct polygon**)polys->data)[i]); + draw_polygon(ctx, poly); + } + } else if (ctx->state.vg.fill_rule == VG_NON_ZERO) { + struct pipe_screen *screen = ctx->pipe->screen; + + if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { + /* front */ + dsa.stencil[0].writemask = ~0; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].ref_value = 0; + dsa.stencil[0].valuemask = ~0; + + /* back */ + dsa.stencil[1].enabled = 1; + dsa.stencil[1].writemask = ~0; + dsa.stencil[1].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[1].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[1].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; + dsa.stencil[1].func = PIPE_FUNC_ALWAYS; + dsa.stencil[1].ref_value = 0; + dsa.stencil[1].valuemask = ~0; + + cso_set_blend(ctx->cso_context, &blend); + cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); + for (i = 0; i < polys->num_elements; ++i) { + struct polygon *poly = (((struct polygon**)polys->data)[i]); + draw_polygon(ctx, poly); + } + } else { + struct pipe_rasterizer_state raster; + + memcpy(&raster, &ctx->state.g3d.rasterizer, sizeof(struct pipe_rasterizer_state)); + + cso_save_rasterizer(ctx->cso_context); + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].ref_value = 0; + dsa.stencil[0].valuemask = ~0; + + raster.cull_mode = raster.front_winding ^ PIPE_WINDING_BOTH; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_INCR_WRAP; + + cso_set_blend(ctx->cso_context, &blend); + cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); + cso_set_rasterizer(ctx->cso_context, &raster); + for (i = 0; i < polys->num_elements; ++i) { + struct polygon *poly = (((struct polygon**)polys->data)[i]); + draw_polygon(ctx, poly); + } + + raster.cull_mode = raster.front_winding; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_KEEP; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_DECR_WRAP; + cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); + cso_set_rasterizer(ctx->cso_context, &raster); + for (i = 0; i < polys->num_elements; ++i) { + struct polygon *poly = (((struct polygon**)polys->data)[i]); + draw_polygon(ctx, poly); + } + + cso_restore_rasterizer(ctx->cso_context); + } + } + + /* restore color writes */ + cso_restore_blend(ctx->cso_context); + /* setup stencil ops */ + dsa.stencil[0].func = PIPE_FUNC_NOTEQUAL; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].ref_value = 0; + dsa.stencil[0].valuemask = dsa.stencil[0].writemask; + dsa.stencil[1].enabled = 0; + memcpy(&dsa.depth, &ctx->state.g3d.dsa.depth, + sizeof(struct pipe_depth_state)); + cso_set_depth_stencil_alpha(ctx->cso_context, &dsa); + + /* render the quad to propagate the rendering from stencil */ + renderer_draw_quad(ctx->renderer, min_x, min_y, + max_x, max_y, 0.0f/*depth should be disabled*/); + + cso_restore_depth_stencil_alpha(ctx->cso_context); +} diff --git a/src/gallium/state_trackers/vega/polygon.h b/src/gallium/state_trackers/vega/polygon.h new file mode 100644 index 0000000000..22672b728e --- /dev/null +++ b/src/gallium/state_trackers/vega/polygon.h @@ -0,0 +1,75 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef POLYGON_H +#define POLYGON_H + +#include "VG/openvg.h" + +struct polygon; +struct vg_context; +struct vg_paint; +struct array; + +struct polygon *polygon_create(int size); +struct polygon *polygon_create_from_data(float *data, int size); +void polygon_destroy(struct polygon *poly); + +void polygon_resize(struct polygon *poly, int new_size); +int polygon_size(struct polygon *poly); + +int polygon_vertex_count(struct polygon *poly); +float * polygon_data(struct polygon *poly); + +void polygon_vertex_append(struct polygon *p, + float x, float y); +void polygon_append_polygon(struct polygon *dst, + struct polygon *src); +void polygon_set_vertex(struct polygon *p, int idx, + float x, float y); +void polygon_vertex(struct polygon *p, int idx, + float *vertex); + +void polygon_bounding_rect(struct polygon *p, + float *rect); +int polygon_contains_point(struct polygon *p, + float x, float y); + +VGboolean polygon_is_closed(struct polygon *p); + +void polygon_fill(struct polygon *p, struct vg_context *pipe); + +/* TODO: make a file/module around this struct + */ +struct polygon_array { + struct array *array; + VGfloat min_x, max_x; + VGfloat min_y, max_y; +}; + +void polygon_array_fill(struct polygon_array *polyarray, struct vg_context *ctx); + +#endif diff --git a/src/gallium/state_trackers/vega/renderer.c b/src/gallium/state_trackers/vega/renderer.c new file mode 100644 index 0000000000..f7c5f2f0cd --- /dev/null +++ b/src/gallium/state_trackers/vega/renderer.c @@ -0,0 +1,592 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "renderer.h" + +#include "vg_context.h" + +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "pipe/p_inlines.h" +#include "pipe/p_screen.h" +#include "pipe/p_shader_tokens.h" + +#include "util/u_draw_quad.h" +#include "util/u_simple_shaders.h" +#include "util/u_memory.h" + +#include "cso_cache/cso_context.h" + +struct renderer { + struct pipe_context *pipe; + struct vg_context *owner; + + struct cso_context *cso; + + void *fs; + + VGfloat vertices[4][2][4]; +}; + +static void setup_shaders(struct renderer *ctx) +{ + struct pipe_context *pipe = ctx->pipe; + /* fragment shader */ + ctx->fs = util_make_fragment_tex_shader(pipe); +} + +static struct pipe_buffer * +setup_vertex_data(struct renderer *ctx, + float x0, float y0, float x1, float y1, float z) +{ + ctx->vertices[0][0][0] = x0; + ctx->vertices[0][0][1] = y0; + ctx->vertices[0][0][2] = z; + ctx->vertices[0][1][0] = 0.0f; /*s*/ + ctx->vertices[0][1][1] = 0.0f; /*t*/ + + ctx->vertices[1][0][0] = x1; + ctx->vertices[1][0][1] = y0; + ctx->vertices[1][0][2] = z; + ctx->vertices[1][1][0] = 1.0f; /*s*/ + ctx->vertices[1][1][1] = 0.0f; /*t*/ + + ctx->vertices[2][0][0] = x1; + ctx->vertices[2][0][1] = y1; + ctx->vertices[2][0][2] = z; + ctx->vertices[2][1][0] = 1.0f; + ctx->vertices[2][1][1] = 1.0f; + + ctx->vertices[3][0][0] = x0; + ctx->vertices[3][0][1] = y1; + ctx->vertices[3][0][2] = z; + ctx->vertices[3][1][0] = 0.0f; + ctx->vertices[3][1][1] = 1.0f; + + return pipe_user_buffer_create( ctx->pipe->screen, + ctx->vertices, + sizeof(ctx->vertices) ); +} + +static struct pipe_buffer * +setup_vertex_data_tex(struct renderer *ctx, + float x0, float y0, float x1, float y1, + float s0, float t0, float s1, float t1, + float z) +{ + ctx->vertices[0][0][0] = x0; + ctx->vertices[0][0][1] = y0; + ctx->vertices[0][0][2] = z; + ctx->vertices[0][1][0] = s0; /*s*/ + ctx->vertices[0][1][1] = t0; /*t*/ + + ctx->vertices[1][0][0] = x1; + ctx->vertices[1][0][1] = y0; + ctx->vertices[1][0][2] = z; + ctx->vertices[1][1][0] = s1; /*s*/ + ctx->vertices[1][1][1] = t0; /*t*/ + + ctx->vertices[2][0][0] = x1; + ctx->vertices[2][0][1] = y1; + ctx->vertices[2][0][2] = z; + ctx->vertices[2][1][0] = s1; + ctx->vertices[2][1][1] = t1; + + ctx->vertices[3][0][0] = x0; + ctx->vertices[3][0][1] = y1; + ctx->vertices[3][0][2] = z; + ctx->vertices[3][1][0] = s0; + ctx->vertices[3][1][1] = t1; + + return pipe_user_buffer_create( ctx->pipe->screen, + ctx->vertices, + sizeof(ctx->vertices) ); +} + + +static struct pipe_buffer * +setup_vertex_data_qtex(struct renderer *ctx, + float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3, + float s0, float t0, float s1, float t1, + float z) +{ + ctx->vertices[0][0][0] = x0; + ctx->vertices[0][0][1] = y0; + ctx->vertices[0][0][2] = z; + ctx->vertices[0][1][0] = s0; /*s*/ + ctx->vertices[0][1][1] = t0; /*t*/ + + ctx->vertices[1][0][0] = x1; + ctx->vertices[1][0][1] = y1; + ctx->vertices[1][0][2] = z; + ctx->vertices[1][1][0] = s1; /*s*/ + ctx->vertices[1][1][1] = t0; /*t*/ + + ctx->vertices[2][0][0] = x2; + ctx->vertices[2][0][1] = y2; + ctx->vertices[2][0][2] = z; + ctx->vertices[2][1][0] = s1; + ctx->vertices[2][1][1] = t1; + + ctx->vertices[3][0][0] = x3; + ctx->vertices[3][0][1] = y3; + ctx->vertices[3][0][2] = z; + ctx->vertices[3][1][0] = s0; + ctx->vertices[3][1][1] = t1; + + return pipe_user_buffer_create( ctx->pipe->screen, + ctx->vertices, + sizeof(ctx->vertices) ); +} + +struct renderer * renderer_create(struct vg_context *owner) +{ + VGint i; + struct renderer *renderer = CALLOC_STRUCT(renderer); + + if (!renderer) + return NULL; + + renderer->owner = owner; + renderer->pipe = owner->pipe; + renderer->cso = owner->cso_context; + + setup_shaders(renderer); + + /* init vertex data that doesn't change */ + for (i = 0; i < 4; i++) { + renderer->vertices[i][0][3] = 1.0f; /* w */ + renderer->vertices[i][1][2] = 0.0f; /* r */ + renderer->vertices[i][1][3] = 1.0f; /* q */ + } + + return renderer; +} + +void renderer_destroy(struct renderer *ctx) +{ +#if 0 + if (ctx->fs) { + cso_delete_fragment_shader(ctx->cso, ctx->fs); + ctx->fs = NULL; + } +#endif + free(ctx); +} + +void renderer_draw_quad(struct renderer *r, + VGfloat x1, VGfloat y1, + VGfloat x2, VGfloat y2, + VGfloat depth) +{ + struct pipe_buffer *buf; + + buf = setup_vertex_data(r, x1, y1, x2, y2, depth); + + if (buf) { + util_draw_vertex_buffer(r->pipe, buf, 0, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ + + pipe_buffer_reference( &buf, + NULL ); + } +} + +void renderer_draw_texture(struct renderer *r, + struct pipe_texture *tex, + VGfloat x1offset, VGfloat y1offset, + VGfloat x2offset, VGfloat y2offset, + VGfloat x1, VGfloat y1, + VGfloat x2, VGfloat y2) +{ + struct pipe_context *pipe = r->pipe; + struct pipe_buffer *buf; + VGfloat s0, t0, s1, t1; + + assert(tex->width[0] != 0); + assert(tex->height[0] != 0); + + s0 = x1offset / tex->width[0]; + s1 = x2offset / tex->width[0]; + t0 = y1offset / tex->height[0]; + t1 = y2offset / tex->height[0]; + + cso_save_vertex_shader(r->cso); + /* shaders */ + cso_set_vertex_shader_handle(r->cso, vg_texture_vs(r->owner)); + + /* draw quad */ + buf = setup_vertex_data_tex(r, x1, y1, x2, y2, + s0, t0, s1, t1, 0.0f); + + if (buf) { + util_draw_vertex_buffer(pipe, buf, 0, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ + + pipe_buffer_reference( &buf, + NULL ); + } + + cso_restore_vertex_shader(r->cso); +} + +void renderer_copy_texture(struct renderer *ctx, + struct pipe_texture *src, + VGfloat sx1, VGfloat sy1, + VGfloat sx2, VGfloat sy2, + struct pipe_texture *dst, + VGfloat dx1, VGfloat dy1, + VGfloat dx2, VGfloat dy2) +{ + struct pipe_context *pipe = ctx->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_buffer *buf; + struct pipe_surface *dst_surf = screen->get_tex_surface( + screen, dst, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + struct pipe_framebuffer_state fb; + float s0, t0, s1, t1; + + assert(src->width[0] != 0); + assert(src->height[0] != 0); + assert(dst->width[0] != 0); + assert(dst->height[0] != 0); + +#if 0 + debug_printf("copy texture [%f, %f, %f, %f], [%f, %f, %f, %f]\n", + sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); +#endif + +#if 1 + s0 = sx1 / src->width[0]; + s1 = sx2 / src->width[0]; + t0 = sy1 / src->height[0]; + t1 = sy2 / src->height[0]; +#else + s0 = 0; + s1 = 1; + t0 = 0; + t1 = 1; +#endif + + assert(screen->is_format_supported(screen, dst_surf->format, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)); + + /* save state (restored below) */ + cso_save_blend(ctx->cso); + cso_save_samplers(ctx->cso); + cso_save_sampler_textures(ctx->cso); + cso_save_framebuffer(ctx->cso); + cso_save_fragment_shader(ctx->cso); + cso_save_vertex_shader(ctx->cso); + + cso_save_viewport(ctx->cso); + + + /* set misc state we care about */ + { + struct pipe_blend_state blend; + memset(&blend, 0, sizeof(blend)); + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.colormask = PIPE_MASK_RGBA; + cso_set_blend(ctx->cso, &blend); + } + + /* sampler */ + { + struct pipe_sampler_state sampler; + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.normalized_coords = 1; + cso_single_sampler(ctx->cso, 0, &sampler); + cso_single_sampler_done(ctx->cso); + } + + vg_set_viewport(ctx->owner, VEGA_Y0_TOP); + + /* texture */ + cso_set_sampler_textures(ctx->cso, 1, &src); + + /* shaders */ + cso_set_vertex_shader_handle(ctx->cso, vg_texture_vs(ctx->owner)); + cso_set_fragment_shader_handle(ctx->cso, ctx->fs); + + /* drawing dest */ + memset(&fb, 0, sizeof(fb)); + fb.width = dst_surf->width; + fb.height = dst_surf->height; + fb.nr_cbufs = 1; + fb.cbufs[0] = dst_surf; + { + VGint i; + for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) + fb.cbufs[i] = 0; + } + cso_set_framebuffer(ctx->cso, &fb); + + /* draw quad */ + buf = setup_vertex_data_tex(ctx, + dx1, dy1, + dx2, dy2, + s0, t0, s1, t1, + 0.0f); + + if (buf) { + util_draw_vertex_buffer(ctx->pipe, buf, 0, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ + + pipe_buffer_reference( &buf, + NULL ); + } + + /* restore state we changed */ + cso_restore_blend(ctx->cso); + cso_restore_samplers(ctx->cso); + cso_restore_sampler_textures(ctx->cso); + cso_restore_framebuffer(ctx->cso); + cso_restore_vertex_shader(ctx->cso); + cso_restore_fragment_shader(ctx->cso); + cso_restore_viewport(ctx->cso); + + pipe_surface_reference(&dst_surf, NULL); +} + +void renderer_copy_surface(struct renderer *ctx, + struct pipe_surface *src, + int srcX0, int srcY0, + int srcX1, int srcY1, + struct pipe_surface *dst, + int dstX0, int dstY0, + int dstX1, int dstY1, + float z, unsigned filter) +{ + struct pipe_context *pipe = ctx->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_buffer *buf; + struct pipe_texture texTemp, *tex; + struct pipe_surface *texSurf; + struct pipe_framebuffer_state fb; + struct st_framebuffer *stfb = ctx->owner->draw_buffer; + const int srcW = abs(srcX1 - srcX0); + const int srcH = abs(srcY1 - srcY0); + const int srcLeft = MIN2(srcX0, srcX1); + const int srcTop = MIN2(srcY0, srcY1); + + assert(filter == PIPE_TEX_MIPFILTER_NEAREST || + filter == PIPE_TEX_MIPFILTER_LINEAR); + + if (srcLeft != srcX0) { + /* left-right flip */ + int tmp = dstX0; + dstX0 = dstX1; + dstX1 = tmp; + } + + if (srcTop != srcY0) { + /* up-down flip */ + int tmp = dstY0; + dstY0 = dstY1; + dstY1 = tmp; + } + + assert(screen->is_format_supported(screen, src->format, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)); + assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)); + assert(screen->is_format_supported(screen, dst->format, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)); + + /* + * XXX for now we're always creating a temporary texture. + * Strictly speaking that's not always needed. + */ + + /* create temp texture */ + memset(&texTemp, 0, sizeof(texTemp)); + texTemp.target = PIPE_TEXTURE_2D; + texTemp.format = src->format; + texTemp.last_level = 0; + texTemp.width[0] = srcW; + texTemp.height[0] = srcH; + texTemp.depth[0] = 1; + pf_get_block(src->format, &texTemp.block); + + tex = screen->texture_create(screen, &texTemp); + if (!tex) + return; + + texSurf = screen->get_tex_surface(screen, tex, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + + /* load temp texture */ + pipe->surface_copy(pipe, + texSurf, 0, 0, /* dest */ + src, srcLeft, srcTop, /* src */ + srcW, srcH); /* size */ + + /* free the surface, update the texture if necessary.*/ + screen->tex_surface_destroy(texSurf); + + /* save state (restored below) */ + cso_save_blend(ctx->cso); + cso_save_samplers(ctx->cso); + cso_save_sampler_textures(ctx->cso); + cso_save_framebuffer(ctx->cso); + cso_save_fragment_shader(ctx->cso); + cso_save_vertex_shader(ctx->cso); + cso_save_viewport(ctx->cso); + + /* set misc state we care about */ + { + struct pipe_blend_state blend; + memset(&blend, 0, sizeof(blend)); + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.colormask = PIPE_MASK_RGBA; + cso_set_blend(ctx->cso, &blend); + } + + vg_set_viewport(ctx->owner, VEGA_Y0_TOP); + + /* sampler */ + { + struct pipe_sampler_state sampler; + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.normalized_coords = 1; + cso_single_sampler(ctx->cso, 0, &sampler); + cso_single_sampler_done(ctx->cso); + } + + /* texture */ + cso_set_sampler_textures(ctx->cso, 1, &tex); + + /* shaders */ + cso_set_fragment_shader_handle(ctx->cso, ctx->fs); + cso_set_vertex_shader_handle(ctx->cso, vg_texture_vs(ctx->owner)); + + /* drawing dest */ + if (stfb->strb->surface != dst) { + memset(&fb, 0, sizeof(fb)); + fb.width = dst->width; + fb.height = dst->height; + fb.nr_cbufs = 1; + fb.cbufs[0] = dst; + fb.zsbuf = stfb->dsrb->surface; + cso_set_framebuffer(ctx->cso, &fb); + } + + /* draw quad */ + buf = setup_vertex_data(ctx, + (float) dstX0, (float) dstY0, + (float) dstX1, (float) dstY1, z); + + if (buf) { + util_draw_vertex_buffer(ctx->pipe, buf, 0, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ + + pipe_buffer_reference( &buf, + NULL ); + } + + + /* restore state we changed */ + cso_restore_blend(ctx->cso); + cso_restore_samplers(ctx->cso); + cso_restore_sampler_textures(ctx->cso); + cso_restore_framebuffer(ctx->cso); + cso_restore_fragment_shader(ctx->cso); + cso_restore_vertex_shader(ctx->cso); + cso_restore_viewport(ctx->cso); + + pipe_texture_reference(&tex, NULL); +} + +void renderer_texture_quad(struct renderer *r, + struct pipe_texture *tex, + VGfloat x1offset, VGfloat y1offset, + VGfloat x2offset, VGfloat y2offset, + VGfloat x1, VGfloat y1, + VGfloat x2, VGfloat y2, + VGfloat x3, VGfloat y3, + VGfloat x4, VGfloat y4) +{ + struct pipe_context *pipe = r->pipe; + struct pipe_buffer *buf; + VGfloat s0, t0, s1, t1; + + assert(tex->width[0] != 0); + assert(tex->height[0] != 0); + + s0 = x1offset / tex->width[0]; + s1 = x2offset / tex->width[0]; + t0 = y1offset / tex->height[0]; + t1 = y2offset / tex->height[0]; + + cso_save_vertex_shader(r->cso); + /* shaders */ + cso_set_vertex_shader_handle(r->cso, vg_texture_vs(r->owner)); + + /* draw quad */ + buf = setup_vertex_data_qtex(r, x1, y1, x2, y2, x3, y3, x4, y4, + s0, t0, s1, t1, 0.0f); + + if (buf) { + util_draw_vertex_buffer(pipe, buf, 0, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ + + pipe_buffer_reference(&buf, + NULL); + } + + cso_restore_vertex_shader(r->cso); +} diff --git a/src/gallium/state_trackers/vega/renderer.h b/src/gallium/state_trackers/vega/renderer.h new file mode 100644 index 0000000000..990cd32c31 --- /dev/null +++ b/src/gallium/state_trackers/vega/renderer.h @@ -0,0 +1,76 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef RENDERER_H +#define RENDERER_H + +#include "VG/openvg.h" + +struct renderer; + +struct vg_context; +struct pipe_texture; +struct pipe_surface; + +struct renderer *renderer_create(struct vg_context *owner); +void renderer_destroy(struct renderer *); + +void renderer_draw_quad(struct renderer *, + VGfloat x1, VGfloat y1, + VGfloat x2, VGfloat y2, + VGfloat depth); +void renderer_draw_texture(struct renderer *, + struct pipe_texture *texture, + VGfloat x1offset, VGfloat y1offset, + VGfloat x2offset, VGfloat y2offset, + VGfloat x1, VGfloat y1, + VGfloat x2, VGfloat y2); +void renderer_texture_quad(struct renderer *, + struct pipe_texture *texture, + VGfloat x1offset, VGfloat y1offset, + VGfloat x2offset, VGfloat y2offset, + VGfloat x1, VGfloat y1, + VGfloat x2, VGfloat y2, + VGfloat x3, VGfloat y3, + VGfloat x4, VGfloat y4); +void renderer_copy_texture(struct renderer *r, + struct pipe_texture *src, + VGfloat sx1, VGfloat sy1, + VGfloat sx2, VGfloat sy2, + struct pipe_texture *dst, + VGfloat dx1, VGfloat dy1, + VGfloat dx2, VGfloat dy2); +void renderer_copy_surface(struct renderer *r, + struct pipe_surface *src, + int sx1, int sy1, + int sx2, int sy2, + struct pipe_surface *dst, + int dx1, int dy1, + int dx2, int dy2, + float z, unsigned filter); + + +#endif diff --git a/src/gallium/state_trackers/vega/shader.c b/src/gallium/state_trackers/vega/shader.c new file mode 100644 index 0000000000..d9074a377b --- /dev/null +++ b/src/gallium/state_trackers/vega/shader.c @@ -0,0 +1,310 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "shader.h" + +#include "vg_context.h" +#include "shaders_cache.h" +#include "paint.h" +#include "mask.h" +#include "image.h" + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_state.h" +#include "pipe/p_inlines.h" +#include "util/u_memory.h" + +#define MAX_CONSTANTS 20 + +struct shader { + struct vg_context *context; + + VGboolean masking; + struct vg_paint *paint; + struct vg_image *image; + + VGboolean drawing_image; + VGImageMode image_mode; + + float constants[MAX_CONSTANTS]; + struct pipe_constant_buffer cbuf; + struct pipe_shader_state fs_state; + void *fs; +}; + +struct shader * shader_create(struct vg_context *ctx) +{ + struct shader *shader = 0; + + shader = CALLOC_STRUCT(shader); + shader->context = ctx; + + return shader; +} + +void shader_destroy(struct shader *shader) +{ + free(shader); +} + +void shader_set_masking(struct shader *shader, VGboolean set) +{ + shader->masking = set; +} + +VGboolean shader_is_masking(struct shader *shader) +{ + return shader->masking; +} + +void shader_set_paint(struct shader *shader, struct vg_paint *paint) +{ + shader->paint = paint; +} + +struct vg_paint * shader_paint(struct shader *shader) +{ + return shader->paint; +} + + +static void setup_constant_buffer(struct shader *shader) +{ + struct vg_context *ctx = shader->context; + struct pipe_context *pipe = shader->context->pipe; + struct pipe_constant_buffer *cbuf = &shader->cbuf; + VGint param_bytes = paint_constant_buffer_size(shader->paint); + float temp_buf[MAX_CONSTANTS]; + + assert(param_bytes <= sizeof(temp_buf)); + paint_fill_constant_buffer(shader->paint, temp_buf); + + if (cbuf->buffer == NULL || + memcmp(temp_buf, shader->constants, param_bytes) != 0) + { + pipe_buffer_reference(&cbuf->buffer, NULL); + + memcpy(shader->constants, temp_buf, param_bytes); + cbuf->buffer = pipe_user_buffer_create(pipe->screen, + &shader->constants, + sizeof(shader->constants)); + } + + ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf); +} + +static VGint blend_bind_samplers(struct vg_context *ctx, + struct pipe_sampler_state **samplers, + struct pipe_texture **textures) +{ + VGBlendMode bmode = ctx->state.vg.blend_mode; + + if (bmode == VG_BLEND_MULTIPLY || + bmode == VG_BLEND_SCREEN || + bmode == VG_BLEND_DARKEN || + bmode == VG_BLEND_LIGHTEN) { + struct st_framebuffer *stfb = ctx->draw_buffer; + + vg_prepare_blend_surface(ctx); + + samplers[2] = &ctx->blend_sampler; + textures[2] = stfb->blend_texture; + + if (!samplers[0] || !textures[0]) { + samplers[1] = samplers[2]; + textures[1] = textures[2]; + } + if (!samplers[1] || !textures[1]) { + samplers[1] = samplers[0]; + textures[1] = textures[0]; + } + + return 1; + } + return 0; +} + +static void setup_samplers(struct shader *shader) +{ + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + struct pipe_texture *textures[PIPE_MAX_SAMPLERS]; + struct vg_context *ctx = shader->context; + /* a little wonky: we use the num as a boolean that just says + * whether any sampler/textures have been set. the actual numbering + * for samplers is always the same: + * 0 - paint sampler/texture for gradient/pattern + * 1 - mask sampler/texture + * 2 - blend sampler/texture + * 3 - image sampler/texture + * */ + VGint num = 0; + + samplers[0] = NULL; + samplers[1] = NULL; + samplers[2] = NULL; + samplers[3] = NULL; + textures[0] = NULL; + textures[1] = NULL; + textures[2] = NULL; + textures[3] = NULL; + + num += paint_bind_samplers(shader->paint, samplers, textures); + num += mask_bind_samplers(samplers, textures); + num += blend_bind_samplers(ctx, samplers, textures); + if (shader->drawing_image && shader->image) + num += image_bind_samplers(shader->image, samplers, textures); + + if (num) { + cso_set_samplers(ctx->cso_context, 4, (const struct pipe_sampler_state **)samplers); + cso_set_sampler_textures(ctx->cso_context, 4, textures); + } +} + +static INLINE VGboolean is_format_bw(struct shader *shader) +{ +#if 0 + struct vg_context *ctx = shader->context; + struct st_framebuffer *stfb = ctx->draw_buffer; +#endif + + if (shader->drawing_image && shader->image) { + if (shader->image->format == VG_BW_1) + return VG_TRUE; + } + + return VG_FALSE; +} + +static void setup_shader_program(struct shader *shader) +{ + struct vg_context *ctx = shader->context; + VGint shader_id = 0; + VGBlendMode blend_mode = ctx->state.vg.blend_mode; + VGboolean black_white = is_format_bw(shader); + + /* 1st stage: fill */ + if (!shader->drawing_image || + (shader->image_mode == VG_DRAW_IMAGE_MULTIPLY || shader->image_mode == VG_DRAW_IMAGE_STENCIL)) { + switch(paint_type(shader->paint)) { + case VG_PAINT_TYPE_COLOR: + shader_id |= VEGA_SOLID_FILL_SHADER; + break; + case VG_PAINT_TYPE_LINEAR_GRADIENT: + shader_id |= VEGA_LINEAR_GRADIENT_SHADER; + break; + case VG_PAINT_TYPE_RADIAL_GRADIENT: + shader_id |= VEGA_RADIAL_GRADIENT_SHADER; + break; + case VG_PAINT_TYPE_PATTERN: + shader_id |= VEGA_PATTERN_SHADER; + break; + + default: + abort(); + } + } + + /* second stage image */ + if (shader->drawing_image) { + switch(shader->image_mode) { + case VG_DRAW_IMAGE_NORMAL: + shader_id |= VEGA_IMAGE_NORMAL_SHADER; + break; + case VG_DRAW_IMAGE_MULTIPLY: + shader_id |= VEGA_IMAGE_MULTIPLY_SHADER; + break; + case VG_DRAW_IMAGE_STENCIL: + shader_id |= VEGA_IMAGE_STENCIL_SHADER; + break; + default: + debug_printf("Unknown image mode!"); + } + } + + if (shader->masking) + shader_id |= VEGA_MASK_SHADER; + + switch(blend_mode) { + case VG_BLEND_MULTIPLY: + shader_id |= VEGA_BLEND_MULTIPLY_SHADER; + break; + case VG_BLEND_SCREEN: + shader_id |= VEGA_BLEND_SCREEN_SHADER; + break; + case VG_BLEND_DARKEN: + shader_id |= VEGA_BLEND_DARKEN_SHADER; + break; + case VG_BLEND_LIGHTEN: + shader_id |= VEGA_BLEND_LIGHTEN_SHADER; + break; + default: + /* handled by pipe_blend_state */ + break; + } + + if (black_white) + shader_id |= VEGA_BW_SHADER; + + shader->fs = shaders_cache_fill(ctx->sc, shader_id); + cso_set_fragment_shader_handle(ctx->cso_context, shader->fs); +} + + +void shader_bind(struct shader *shader) +{ + /* first resolve the real paint type */ + paint_resolve_type(shader->paint); + + setup_constant_buffer(shader); + setup_samplers(shader); + setup_shader_program(shader); +} + +void shader_set_image_mode(struct shader *shader, VGImageMode image_mode) +{ + shader->image_mode = image_mode; +} + +VGImageMode shader_image_mode(struct shader *shader) +{ + return shader->image_mode; +} + +void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image) +{ + shader->drawing_image = drawing_image; +} + +VGboolean shader_drawing_image(struct shader *shader) +{ + return shader->drawing_image; +} + +void shader_set_image(struct shader *shader, struct vg_image *img) +{ + shader->image = img; +} diff --git a/src/gallium/state_trackers/vega/shader.h b/src/gallium/state_trackers/vega/shader.h new file mode 100644 index 0000000000..847eee6a31 --- /dev/null +++ b/src/gallium/state_trackers/vega/shader.h @@ -0,0 +1,56 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef SHADER_H +#define SHADER_H + +#include "VG/openvg.h" + +struct shader; +struct vg_paint; +struct vg_context; +struct vg_image; + +struct shader *shader_create(struct vg_context *context); +void shader_destroy(struct shader *shader); + +void shader_set_masking(struct shader *shader, VGboolean set); +VGboolean shader_is_masking(struct shader *shader); + +void shader_set_paint(struct shader *shader, struct vg_paint *paint); +struct vg_paint *shader_paint(struct shader *shader); + +void shader_set_image_mode(struct shader *shader, VGImageMode image_mode); +VGImageMode shader_image_mode(struct shader *shader); + +void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image); +VGboolean shader_drawing_image(struct shader *shader); + +void shader_set_image(struct shader *shader, struct vg_image *img); + +void shader_bind(struct shader *shader); + +#endif diff --git a/src/gallium/state_trackers/vega/shaders_cache.c b/src/gallium/state_trackers/vega/shaders_cache.c new file mode 100644 index 0000000000..fd0831fab1 --- /dev/null +++ b/src/gallium/state_trackers/vega/shaders_cache.c @@ -0,0 +1,439 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "shaders_cache.h" + +#include "vg_context.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "pipe/p_screen.h" +#include "pipe/p_shader_tokens.h" + +#include "tgsi/tgsi_build.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_parse.h" +#include "tgsi/tgsi_util.h" +#include "tgsi/tgsi_text.h" + +#include "util/u_memory.h" +#include "util/u_math.h" +#include "util/u_debug.h" +#include "cso_cache/cso_hash.h" +#include "cso_cache/cso_context.h" + +#include "VG/openvg.h" + +#include "asm_fill.h" + +/* Essentially we construct an ubber-shader based on the state + * of the pipeline. The stages are: + * 1) Fill (mandatory, solid color/gradient/pattern/image draw) + * 2) Image composition (image mode multiply and stencil) + * 3) Mask + * 4) Extended blend (multiply/screen/darken/lighten) + * 5) Premultiply/Unpremultiply + * 6) Color transform (to black and white) + */ +#define SHADER_STAGES 6 + +struct cached_shader { + void *driver_shader; + struct pipe_shader_state state; +}; + +struct shaders_cache { + struct vg_context *pipe; + + struct cso_hash *hash; +}; + + +static INLINE struct tgsi_token *tokens_from_assembly(const char *txt, int num_tokens) +{ + struct tgsi_token *tokens; + + tokens = (struct tgsi_token *) MALLOC(num_tokens * sizeof(tokens[0])); + + tgsi_text_translate(txt, tokens, num_tokens); + +#if DEBUG_SHADERS + tgsi_dump(tokens, 0); +#endif + + return tokens; +} + +#define ALL_FILLS (VEGA_SOLID_FILL_SHADER | \ + VEGA_LINEAR_GRADIENT_SHADER | \ + VEGA_RADIAL_GRADIENT_SHADER | \ + VEGA_PATTERN_SHADER | \ + VEGA_IMAGE_NORMAL_SHADER) + + +/* +static const char max_shader_preamble[] = + "FRAG1.1\n" + "DCL IN[0], POSITION, LINEAR\n" + "DCL IN[1], GENERIC[0], PERSPECTIVE\n" + "DCL OUT[0], COLOR, CONSTANT\n" + "DCL CONST[0..9], CONSTANT\n" + "DCL TEMP[0..9], CONSTANT\n" + "DCL SAMP[0..9], CONSTANT\n"; + + max_shader_preamble strlen == 175 +*/ +#define MAX_PREAMBLE 175 + +static INLINE VGint range_min(VGint min, VGint current) +{ + if (min < 0) + min = current; + else + min = MIN2(min, current); + return min; +} + +static INLINE VGint range_max(VGint max, VGint current) +{ + return MAX2(max, current); +} + +static void +create_preamble(char *txt, + const struct shader_asm_info *shaders[SHADER_STAGES], + int num_shaders) +{ + VGboolean declare_input = VG_FALSE; + VGint start_const = -1, end_const = 0; + VGint start_temp = -1, end_temp = 0; + VGint start_sampler = -1, end_sampler = 0; + VGint i; + VGint num_consts, num_temps, num_samplers; + + for (i = 0; i < num_shaders; ++i) { + if (shaders[i]->num_consts) + start_const = range_min(start_const, shaders[i]->start_const); + if (shaders[i]->num_temps) + start_temp = range_min(start_temp, shaders[i]->start_temp); + if (shaders[i]->num_samplers) + start_sampler = range_min(start_sampler, shaders[i]->start_sampler); + + end_const = range_max(end_const, shaders[i]->start_const + + shaders[i]->num_consts); + end_temp = range_max(end_temp, shaders[i]->start_temp + + shaders[i]->num_temps); + end_sampler = range_max(end_sampler, shaders[i]->start_sampler + + shaders[i]->num_samplers); + if (shaders[i]->needs_position) + declare_input = VG_TRUE; + } + /* if they're still unitialized, initialize them */ + if (start_const < 0) + start_const = 0; + if (start_temp < 0) + start_temp = 0; + if (start_sampler < 0) + start_sampler = 0; + + num_consts = end_const - start_const; + num_temps = end_temp - start_temp; + num_samplers = end_sampler - start_sampler; + /* end exclusive */ + --end_const; + --end_temp; + --end_sampler; + + sprintf(txt, "FRAG1.1\n"); + + if (declare_input) { + sprintf(txt + strlen(txt), "DCL IN[0], POSITION, LINEAR\n"); + sprintf(txt + strlen(txt), "DCL IN[1], GENERIC[0], PERSPECTIVE\n"); + } + + /* we always have a color output */ + sprintf(txt + strlen(txt), "DCL OUT[0], COLOR, CONSTANT\n"); + + if (num_consts > 1) + sprintf(txt + strlen(txt), "DCL CONST[%d..%d], CONSTANT\n", start_const, end_const); + else if (num_consts == 1) + sprintf(txt + strlen(txt), "DCL CONST[%d], CONSTANT\n", start_const); + + if (num_temps > 1) + sprintf(txt + strlen(txt), "DCL TEMP[%d..%d], CONSTANT\n", start_temp, end_temp); + else if (num_temps > 1) + sprintf(txt + strlen(txt), "DCL TEMP[%d], CONSTANT\n", start_temp); + + if (num_samplers > 1) + sprintf(txt + strlen(txt), "DCL SAMP[%d..%d], CONSTANT\n", start_sampler, end_sampler); + else if (num_samplers == 1) + sprintf(txt + strlen(txt), "DCL SAMP[%d], CONSTANT\n", start_sampler); +} + +static void * +combine_shaders(const struct shader_asm_info *shaders[SHADER_STAGES], int num_shaders, + struct pipe_context *pipe, + struct pipe_shader_state *shader) +{ + char *combined_txt; + int combined_len = MAX_PREAMBLE; + int combined_tokens = 0; + int i = 0; + int current_shader = 0; + int current_len; + + for (i = 0; i < num_shaders; ++i) { + combined_len += strlen(shaders[i]->txt); + combined_tokens += shaders[i]->num_tokens; + } + /* add for the %s->TEMP[0] substitutions */ + combined_len += num_shaders * 7 /*TEMP[0]*/ + 4 /*"END\n"*/; + + combined_txt = (char*)malloc(combined_len); + combined_txt[0] = '\0'; + + create_preamble(combined_txt, shaders, num_shaders); + + while (current_shader < num_shaders) { + const char temp[] = "TEMP[0]"; + const char out[] = "OUT[0]"; + const char *subst = temp; + + current_len = strlen(combined_txt); + + /* if the last shader then output */ + if (current_shader + 1 == num_shaders) + subst = out; + + snprintf(combined_txt + current_len, + combined_len - current_len, + shaders[current_shader]->txt, + subst); + ++current_shader; + } + + + current_len = strlen(combined_txt); + snprintf(combined_txt + current_len, + combined_len - current_len, + "END\n"); + + debug_printf("Combined shader is : \n%s\n", + combined_txt); + + shader->tokens = tokens_from_assembly( + combined_txt, combined_tokens); + + free(combined_txt); + + return pipe->create_fs_state(pipe, shader); +} + +static void * +create_shader(struct pipe_context *pipe, + int id, + struct pipe_shader_state *shader) +{ + int idx = 0; + const struct shader_asm_info * shaders[SHADER_STAGES]; + + /* the shader has to have a fill */ + debug_assert(id & ALL_FILLS); + + /* first stage */ + if (id & VEGA_SOLID_FILL_SHADER) { + debug_assert(idx == 0); + shaders[idx] = &shaders_asm[0]; + debug_assert(shaders_asm[0].id == VEGA_SOLID_FILL_SHADER); + ++idx; + } + if ((id & VEGA_LINEAR_GRADIENT_SHADER)) { + debug_assert(idx == 0); + shaders[idx] = &shaders_asm[1]; + debug_assert(shaders_asm[1].id == VEGA_LINEAR_GRADIENT_SHADER); + ++idx; + } + if ((id & VEGA_RADIAL_GRADIENT_SHADER)) { + debug_assert(idx == 0); + shaders[idx] = &shaders_asm[2]; + debug_assert(shaders_asm[2].id == VEGA_RADIAL_GRADIENT_SHADER); + ++idx; + } + if ((id & VEGA_PATTERN_SHADER)) { + debug_assert(idx == 0); + debug_assert(shaders_asm[3].id == VEGA_PATTERN_SHADER); + shaders[idx] = &shaders_asm[3]; + ++idx; + } + if ((id & VEGA_IMAGE_NORMAL_SHADER)) { + debug_assert(idx == 0); + debug_assert(shaders_asm[4].id == VEGA_IMAGE_NORMAL_SHADER); + shaders[idx] = &shaders_asm[4]; + ++idx; + } + + /* second stage */ + if ((id & VEGA_IMAGE_MULTIPLY_SHADER)) { + debug_assert(shaders_asm[5].id == VEGA_IMAGE_MULTIPLY_SHADER); + shaders[idx] = &shaders_asm[5]; + ++idx; + } else if ((id & VEGA_IMAGE_STENCIL_SHADER)) { + debug_assert(shaders_asm[6].id == VEGA_IMAGE_STENCIL_SHADER); + shaders[idx] = &shaders_asm[6]; + ++idx; + } + + /* third stage */ + if ((id & VEGA_MASK_SHADER)) { + debug_assert(idx == 1); + debug_assert(shaders_asm[7].id == VEGA_MASK_SHADER); + shaders[idx] = &shaders_asm[7]; + ++idx; + } + + /* fourth stage */ + if ((id & VEGA_BLEND_MULTIPLY_SHADER)) { + debug_assert(shaders_asm[8].id == VEGA_BLEND_MULTIPLY_SHADER); + shaders[idx] = &shaders_asm[8]; + ++idx; + } else if ((id & VEGA_BLEND_SCREEN_SHADER)) { + debug_assert(shaders_asm[9].id == VEGA_BLEND_SCREEN_SHADER); + shaders[idx] = &shaders_asm[9]; + ++idx; + } else if ((id & VEGA_BLEND_DARKEN_SHADER)) { + debug_assert(shaders_asm[10].id == VEGA_BLEND_DARKEN_SHADER); + shaders[idx] = &shaders_asm[10]; + ++idx; + } else if ((id & VEGA_BLEND_LIGHTEN_SHADER)) { + debug_assert(shaders_asm[11].id == VEGA_BLEND_LIGHTEN_SHADER); + shaders[idx] = &shaders_asm[11]; + ++idx; + } + + /* fifth stage */ + if ((id & VEGA_PREMULTIPLY_SHADER)) { + debug_assert(shaders_asm[12].id == VEGA_PREMULTIPLY_SHADER); + shaders[idx] = &shaders_asm[12]; + ++idx; + } else if ((id & VEGA_UNPREMULTIPLY_SHADER)) { + debug_assert(shaders_asm[13].id == VEGA_UNPREMULTIPLY_SHADER); + shaders[idx] = &shaders_asm[13]; + ++idx; + } + + /* sixth stage */ + if ((id & VEGA_BW_SHADER)) { + debug_assert(shaders_asm[14].id == VEGA_BW_SHADER); + shaders[idx] = &shaders_asm[14]; + ++idx; + } + + return combine_shaders(shaders, idx, pipe, shader); +} + +/*************************************************/ + +struct shaders_cache * shaders_cache_create(struct vg_context *vg) +{ + struct shaders_cache *sc = CALLOC_STRUCT(shaders_cache); + + sc->pipe = vg; + sc->hash = cso_hash_create(); + + return sc; +} + +void shaders_cache_destroy(struct shaders_cache *sc) +{ + struct cso_hash_iter iter = cso_hash_first_node(sc->hash); + + while (!cso_hash_iter_is_null(iter)) { + struct cached_shader *cached = + (struct cached_shader *)cso_hash_iter_data(iter); + cso_delete_fragment_shader(sc->pipe->cso_context, + cached->driver_shader); + iter = cso_hash_erase(sc->hash, iter); + } + + cso_hash_delete(sc->hash); + free(sc); +} + +void * shaders_cache_fill(struct shaders_cache *sc, + int shader_key) +{ + VGint key = shader_key; + struct cached_shader *cached; + struct cso_hash_iter iter = cso_hash_find(sc->hash, key); + + if (cso_hash_iter_is_null(iter)) { + cached = CALLOC_STRUCT(cached_shader); + cached->driver_shader = create_shader(sc->pipe->pipe, key, &cached->state); + + cso_hash_insert(sc->hash, key, cached); + + return cached->driver_shader; + } + + cached = (struct cached_shader *)cso_hash_iter_data(iter); + + assert(cached->driver_shader); + return cached->driver_shader; +} + +struct vg_shader * shader_create_from_text(struct pipe_context *pipe, + const char *txt, int num_tokens, + int type) +{ + struct vg_shader *shader = (struct vg_shader *)malloc( + sizeof(struct vg_shader)); + struct tgsi_token *tokens = tokens_from_assembly(txt, num_tokens); + struct pipe_shader_state state; + + debug_assert(type == PIPE_SHADER_VERTEX || + type == PIPE_SHADER_FRAGMENT); + + state.tokens = tokens; + shader->type = type; + shader->tokens = tokens; + + if (type == PIPE_SHADER_FRAGMENT) + shader->driver = pipe->create_fs_state(pipe, &state); + else + shader->driver = pipe->create_vs_state(pipe, &state); + return shader; +} + +void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader) +{ + if (shader->type == PIPE_SHADER_FRAGMENT) + cso_delete_fragment_shader(ctx->cso_context, shader->driver); + else + cso_delete_vertex_shader(ctx->cso_context, shader->driver); + free(shader->tokens); + free(shader); +} diff --git a/src/gallium/state_trackers/vega/shaders_cache.h b/src/gallium/state_trackers/vega/shaders_cache.h new file mode 100644 index 0000000000..feca58b61a --- /dev/null +++ b/src/gallium/state_trackers/vega/shaders_cache.h @@ -0,0 +1,77 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef SHADERS_CACHE_H +#define SHADERS_CACHE_H + + +struct vg_context; +struct pipe_context; +struct tgsi_token; +struct shaders_cache; + +enum VegaShaderType { + VEGA_SOLID_FILL_SHADER = 1 << 0, + VEGA_LINEAR_GRADIENT_SHADER = 1 << 1, + VEGA_RADIAL_GRADIENT_SHADER = 1 << 2, + VEGA_PATTERN_SHADER = 1 << 3, + VEGA_IMAGE_NORMAL_SHADER = 1 << 4, + VEGA_IMAGE_MULTIPLY_SHADER = 1 << 5, + VEGA_IMAGE_STENCIL_SHADER = 1 << 6, + + VEGA_MASK_SHADER = 1 << 7, + + VEGA_BLEND_MULTIPLY_SHADER = 1 << 8, + VEGA_BLEND_SCREEN_SHADER = 1 << 9, + VEGA_BLEND_DARKEN_SHADER = 1 << 10, + VEGA_BLEND_LIGHTEN_SHADER = 1 << 11, + + VEGA_PREMULTIPLY_SHADER = 1 << 12, + VEGA_UNPREMULTIPLY_SHADER = 1 << 13, + + VEGA_BW_SHADER = 1 << 14 +}; + +struct vg_shader { + void *driver; + struct tgsi_token *tokens; + int type;/* PIPE_SHADER_VERTEX, PIPE_SHADER_FRAGMENT */ +}; + +struct shaders_cache *shaders_cache_create(struct vg_context *pipe); +void shaders_cache_destroy(struct shaders_cache *sc); +void *shaders_cache_fill(struct shaders_cache *sc, + int shader_key); + +struct vg_shader *shader_create_from_text(struct pipe_context *pipe, + const char *txt, int num_tokens, + int type); + +void vg_shader_destroy(struct vg_context *ctx, struct vg_shader *shader); + + + +#endif diff --git a/src/gallium/state_trackers/vega/st_inlines.h b/src/gallium/state_trackers/vega/st_inlines.h new file mode 100644 index 0000000000..1f331dfcdb --- /dev/null +++ b/src/gallium/state_trackers/vega/st_inlines.h @@ -0,0 +1,159 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * Functions for checking if buffers/textures are referenced when we need + * to read/write from/to them. Flush when needed. + */ + +#ifndef ST_INLINES_H +#define ST_INLINES_H + +#include "vg_context.h" + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "pipe/p_state.h" + +static INLINE struct pipe_transfer * +st_cond_flush_get_tex_transfer(struct vg_context *st, + struct pipe_texture *pt, + unsigned int face, + unsigned int level, + unsigned int zslice, + enum pipe_transfer_usage usage, + unsigned int x, unsigned int y, + unsigned int w, unsigned int h) +{ + struct pipe_screen *screen = st->pipe->screen; + struct pipe_context *pipe = st->pipe; + unsigned referenced = + pipe->is_texture_referenced(pipe, pt, face, level); + + if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) || + usage == PIPE_TRANSFER_WRITE || + usage == PIPE_TRANSFER_READ_WRITE)) + vgFlush(); + + return screen->get_tex_transfer(screen, pt, face, level, zslice, usage, + x, y, w, h); +} + +static INLINE struct pipe_transfer * +st_no_flush_get_tex_transfer(struct vg_context *st, + struct pipe_texture *pt, + unsigned int face, + unsigned int level, + unsigned int zslice, + enum pipe_transfer_usage usage, + unsigned int x, unsigned int y, + unsigned int w, unsigned int h) +{ + struct pipe_screen *screen = st->pipe->screen; + + return screen->get_tex_transfer(screen, pt, face, level, + zslice, usage, x, y, w, h); +} + +static INLINE void * +st_cond_flush_pipe_buffer_map(struct vg_context *st, + struct pipe_buffer *buf, + unsigned int map_flags) +{ + struct pipe_context *pipe = st->pipe; + unsigned int referenced = pipe->is_buffer_referenced(pipe, buf); + + if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) || + (map_flags & PIPE_BUFFER_USAGE_CPU_WRITE))) + vgFlush(); + + return pipe_buffer_map(pipe->screen, buf, map_flags); +} + +static INLINE void * +st_no_flush_pipe_buffer_map(struct vg_context *st, + struct pipe_buffer *buf, + unsigned int map_flags) +{ + return pipe_buffer_map(st->pipe->screen, buf, map_flags); +} + + +static INLINE void +st_cond_flush_pipe_buffer_write(struct vg_context *st, + struct pipe_buffer *buf, + unsigned int offset, + unsigned int size, + const void * data) +{ + struct pipe_context *pipe = st->pipe; + + if (pipe->is_buffer_referenced(pipe, buf)) + vgFlush(); + + pipe_buffer_write(pipe->screen, buf, offset, size, data); +} + +static INLINE void +st_no_flush_pipe_buffer_write(struct vg_context *st, + struct pipe_buffer *buf, + unsigned int offset, + unsigned int size, + const void * data) +{ + pipe_buffer_write(st->pipe->screen, buf, offset, size, data); +} + +static INLINE void +st_cond_flush_pipe_buffer_read(struct vg_context *st, + struct pipe_buffer *buf, + unsigned int offset, + unsigned int size, + void * data) +{ + struct pipe_context *pipe = st->pipe; + + if (pipe->is_buffer_referenced(pipe, buf) & PIPE_REFERENCED_FOR_WRITE) + vgFlush(); + + pipe_buffer_read(pipe->screen, buf, offset, size, data); +} + +static INLINE void +st_no_flush_pipe_buffer_read(struct vg_context *st, + struct pipe_buffer *buf, + unsigned int offset, + unsigned int size, + void * data) +{ + pipe_buffer_read(st->pipe->screen, buf, offset, size, data); +} + +#endif + diff --git a/src/gallium/state_trackers/vega/stroker.c b/src/gallium/state_trackers/vega/stroker.c new file mode 100644 index 0000000000..1b92d2b5c6 --- /dev/null +++ b/src/gallium/state_trackers/vega/stroker.c @@ -0,0 +1,1349 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "stroker.h" + +#include "path.h" +#include "vg_state.h" +#include "util_array.h" +#include "arc.h" +#include "bezier.h" +#include "matrix.h" +#include "path_utils.h" +#include "polygon.h" + +#include "math.h" + +#ifndef M_2PI +#define M_2PI 6.28318530717958647692528676655900576 +#endif + +#define STROKE_SEGMENTS 0 +#define STROKE_DEBUG 0 +#define DEBUG_EMITS 0 + +static const VGfloat curve_threshold = 0.25f; + +static const VGfloat zero_coords[] = {0.f, 0.f}; + +enum intersection_type { + NoIntersections, + BoundedIntersection, + UnboundedIntersection, +}; + +enum line_join_mode { + FlatJoin, + SquareJoin, + MiterJoin, + RoundJoin, + RoundCap +}; + +struct stroke_iterator { + void (*next)(struct stroke_iterator *); + VGboolean (*has_next)(struct stroke_iterator *); + + VGPathCommand (*current_command)(struct stroke_iterator *it); + void (*current_coords)(struct stroke_iterator *it, VGfloat *coords); + + VGint position; + VGint coord_position; + + const VGubyte *cmds; + const VGfloat *coords; + VGint num_commands; + VGint num_coords; + + struct polygon *curve_poly; + VGint curve_index; +}; + +static VGPathCommand stroke_itr_command(struct stroke_iterator *itr) +{ + return itr->current_command(itr); +} + +static void stroke_itr_coords(struct stroke_iterator *itr, VGfloat *coords) +{ + itr->current_coords(itr, coords); +} + +static void stroke_fw_itr_coords(struct stroke_iterator *itr, VGfloat *coords) +{ + if (itr->position >= itr->num_commands) + return; + switch (stroke_itr_command(itr)) { + case VG_MOVE_TO_ABS: + coords[0] = itr->coords[itr->coord_position]; + coords[1] = itr->coords[itr->coord_position + 1]; + break; + case VG_LINE_TO_ABS: + coords[0] = itr->coords[itr->coord_position]; + coords[1] = itr->coords[itr->coord_position + 1]; + break; + case VG_CUBIC_TO_ABS: + coords[0] = itr->coords[itr->coord_position]; + coords[1] = itr->coords[itr->coord_position + 1]; + coords[2] = itr->coords[itr->coord_position + 2]; + coords[3] = itr->coords[itr->coord_position + 3]; + coords[4] = itr->coords[itr->coord_position + 4]; + coords[5] = itr->coords[itr->coord_position + 5]; + break; + default: + debug_assert(!"invalid command!\n"); + } +} + + +static void stroke_bw_itr_coords(struct stroke_iterator *itr, VGfloat *coords) +{ + if (itr->position >= itr->num_commands) + return; + switch (stroke_itr_command(itr)) { + case VG_MOVE_TO_ABS: + coords[0] = itr->coords[itr->coord_position]; + coords[1] = itr->coords[itr->coord_position + 1]; + break; + case VG_LINE_TO_ABS: + coords[0] = itr->coords[itr->coord_position]; + coords[1] = itr->coords[itr->coord_position + 1]; + break; + case VG_CUBIC_TO_ABS: + coords[0] = itr->coords[itr->coord_position + 4]; + coords[1] = itr->coords[itr->coord_position + 5]; + coords[2] = itr->coords[itr->coord_position + 2]; + coords[3] = itr->coords[itr->coord_position + 3]; + coords[4] = itr->coords[itr->coord_position + 0]; + coords[5] = itr->coords[itr->coord_position + 1]; + break; + default: + debug_assert(!"invalid command!\n"); + } +} + + +static VGPathCommand stroke_fw_current_command(struct stroke_iterator *it) +{ + return it->cmds[it->position]; +} + +static VGPathCommand stroke_bw_current_command(struct stroke_iterator *it) +{ + VGPathCommand prev_cmd; + if (it->position == it->num_commands -1) + return VG_MOVE_TO_ABS; + + prev_cmd = it->cmds[it->position + 1]; + return prev_cmd; +} + +static VGboolean stroke_fw_has_next(struct stroke_iterator *itr) +{ + return itr->position < (itr->num_commands - 1); +} + +static VGboolean stroke_bw_has_next(struct stroke_iterator *itr) +{ + return itr->position > 0; +} + +static void stroke_fw_next(struct stroke_iterator *itr) +{ + VGubyte cmd; + debug_assert(stroke_fw_has_next(itr)); + + cmd = stroke_itr_command(itr); + + itr->coord_position += num_elements_for_segments(&cmd, 1); + ++itr->position; +} + +static void stroke_bw_next(struct stroke_iterator *itr) +{ + VGubyte cmd; + debug_assert(stroke_bw_has_next(itr)); + + --itr->position; + cmd = stroke_itr_command(itr); + + itr->coord_position -= num_elements_for_segments(&cmd, 1); +} + +static void stroke_itr_common_init(struct stroke_iterator *itr, + struct array *cmds, + struct array *coords) +{ + itr->cmds = (VGubyte*)cmds->data; + itr->num_commands = cmds->num_elements; + + itr->coords = (VGfloat*)coords->data; + itr->num_coords = coords->num_elements; +} + +static void stroke_forward_iterator(struct stroke_iterator *itr, + struct array *cmds, + struct array *coords) +{ + stroke_itr_common_init(itr, cmds, coords); + itr->position = 0; + itr->coord_position = 0; + + itr->next = stroke_fw_next; + itr->has_next = stroke_fw_has_next; + itr->current_command = stroke_fw_current_command; + itr->current_coords = stroke_fw_itr_coords; +} + +static void stroke_backward_iterator(struct stroke_iterator *itr, + struct array *cmds, + struct array *coords) +{ + VGubyte cmd; + stroke_itr_common_init(itr, cmds, coords); + itr->position = itr->num_commands - 1; + + cmd = stroke_bw_current_command(itr); + itr->coord_position = itr->num_coords - + num_elements_for_segments(&cmd, 1); + + itr->next = stroke_bw_next; + itr->has_next = stroke_bw_has_next; + itr->current_command = stroke_bw_current_command; + itr->current_coords = stroke_bw_itr_coords; +} + + + +static void stroke_flat_next(struct stroke_iterator *itr) +{ + VGubyte cmd; + + if (itr->curve_index >= 0) { + ++itr->curve_index; + if (itr->curve_index >= polygon_vertex_count(itr->curve_poly)) { + itr->curve_index = -1; + polygon_destroy(itr->curve_poly); + itr->curve_poly = 0; + } else + return; + } + debug_assert(stroke_fw_has_next(itr)); + + cmd = itr->cmds[itr->position]; + itr->coord_position += num_elements_for_segments(&cmd, 1); + ++itr->position; + + cmd = itr->cmds[itr->position]; + + if (cmd == VG_CUBIC_TO_ABS) { + struct bezier bezier; + VGfloat bez[8]; + + bez[0] = itr->coords[itr->coord_position - 2]; + bez[1] = itr->coords[itr->coord_position - 1]; + bez[2] = itr->coords[itr->coord_position]; + bez[3] = itr->coords[itr->coord_position + 1]; + bez[4] = itr->coords[itr->coord_position + 2]; + bez[5] = itr->coords[itr->coord_position + 3]; + bez[6] = itr->coords[itr->coord_position + 4]; + bez[7] = itr->coords[itr->coord_position + 5]; + + bezier_init(&bezier, + bez[0], bez[1], + bez[2], bez[3], + bez[4], bez[5], + bez[6], bez[7]); + /* skip the first one, it's the same as the prev point */ + itr->curve_index = 1; + if (itr->curve_poly) { + polygon_destroy(itr->curve_poly); + itr->curve_poly = 0; + } + itr->curve_poly = bezier_to_polygon(&bezier); + } +} + +static VGboolean stroke_flat_has_next(struct stroke_iterator *itr) +{ + return (itr->curve_index >= 0 && + itr->curve_index < (polygon_vertex_count(itr->curve_poly)-1)) + || itr->position < (itr->num_commands - 1); +} + +static VGPathCommand stroke_flat_current_command(struct stroke_iterator *it) +{ + if (it->cmds[it->position] == VG_CUBIC_TO_ABS) { + return VG_LINE_TO_ABS; + } + return it->cmds[it->position]; +} + +static void stroke_flat_itr_coords(struct stroke_iterator *itr, VGfloat *coords) +{ + if (itr->curve_index <= -1 && itr->position >= itr->num_commands) + return; + + if (itr->curve_index >= 0) { + polygon_vertex(itr->curve_poly, itr->curve_index, + coords); + return; + } + + switch (stroke_itr_command(itr)) { + case VG_MOVE_TO_ABS: + coords[0] = itr->coords[itr->coord_position]; + coords[1] = itr->coords[itr->coord_position + 1]; + break; + case VG_LINE_TO_ABS: + coords[0] = itr->coords[itr->coord_position]; + coords[1] = itr->coords[itr->coord_position + 1]; + break; + case VG_CUBIC_TO_ABS: + default: + debug_assert(!"invalid command!\n"); + } +} + +static void stroke_flat_iterator(struct stroke_iterator *itr, + struct array *cmds, + struct array *coords) +{ + stroke_itr_common_init(itr, cmds, coords); + itr->position = 0; + itr->coord_position = 0; + + itr->next = stroke_flat_next; + itr->has_next = stroke_flat_has_next; + itr->current_command = stroke_flat_current_command; + itr->current_coords = stroke_flat_itr_coords; + itr->curve_index = -1; + itr->curve_poly = 0; +} + + +static INLINE VGboolean finite_coords4(const VGfloat *c) +{ + return + isfinite(c[0]) && isfinite(c[1]) && + isfinite(c[2]) && isfinite(c[3]); +} + +/* from Graphics Gems II */ +#define SAME_SIGNS(a, b) ((a) * (b) >= 0) +static VGboolean do_lines_intersect(VGfloat x1, VGfloat y1, VGfloat x2, VGfloat y2, + VGfloat x3, VGfloat y3, VGfloat x4, VGfloat y4) +{ + VGfloat a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns */ + VGfloat r1, r2, r3, r4; /* 'sign' values */ + + a1 = y2 - y1; + b1 = x1 - x2; + c1 = x2 * y1 - x1 * y2; + + r3 = a1 * x3 + b1 * y3 + c1; + r4 = a1 * x4 + b1 * y4 + c1; + + if (r3 != 0 && r4 != 0 && SAME_SIGNS(r3, r4)) + return VG_FALSE; + + a2 = y4 - y3; + b2 = x3 - x4; + c2 = x4 * y3 - x3 * y4; + + r1 = a2 * x1 + b2 * y1 + c2; + r2 = a2 * x2 + b2 * y2 + c2; + + if (r1 != 0 && r2 != 0 && SAME_SIGNS(r1, r2)) + return VG_FALSE; + + return VG_TRUE; +} + +static INLINE VGfloat line_dx(const VGfloat *l) +{ + return l[2] - l[0]; +} + +static INLINE VGfloat line_dy(const VGfloat *l) +{ + return l[3] - l[1]; +} + +static INLINE VGfloat line_angle(const VGfloat *l) +{ + const VGfloat dx = line_dx(l); + const VGfloat dy = line_dy(l); + + const VGfloat theta = atan2(-dy, dx) * 360.0 / M_2PI; + + const VGfloat theta_normalized = theta < 0 ? theta + 360 : theta; + + if (floatsEqual(theta_normalized, 360.f)) + return 0; + else + return theta_normalized; +} + +static INLINE void line_set_length(VGfloat *l, VGfloat len) +{ + VGfloat uv[] = {l[0], l[1], l[2], l[3]}; + if (null_line(l)) + return; + line_normalize(uv); + l[2] = l[0] + line_dx(uv) * len; + l[3] = l[1] + line_dy(uv) * len; +} + +static INLINE void line_translate(VGfloat *l, VGfloat x, VGfloat y) +{ + l[0] += x; + l[1] += y; + l[2] += x; + l[3] += y; +} + +static INLINE VGfloat line_angle_to(const VGfloat *l1, + const VGfloat *l2) +{ + VGfloat a1, a2, delta, delta_normalized; + if (null_line(l1) || null_line(l1)) + return 0; + + a1 = line_angle(l1); + a2 = line_angle(l2); + + delta = a2 - a1; + delta_normalized = delta < 0 ? delta + 360 : delta; + + if (floatsEqual(delta, 360.f)) + return 0; + else + return delta_normalized; +} + +static INLINE VGfloat line_angles(const VGfloat *l1, + const VGfloat *l2) +{ + VGfloat cos_line, rad = 0; + + if (null_line(l1) || null_line(l2)) + return 0; + + cos_line = (line_dx(l1)*line_dx(l2) + line_dy(l1)*line_dy(l2)) / + (line_lengthv(l1)*line_lengthv(l2)); + rad = 0; + + if (cos_line >= -1.0 && cos_line <= 1.0) + rad = acos(cos_line); + return rad * 360 / M_2PI; +} + + +static INLINE VGfloat adapted_angle_on_x(const VGfloat *line) +{ + const VGfloat identity[] = {0, 0, 1, 0}; + VGfloat angle = line_angles(line, identity); + if (line_dy(line) > 0) + angle = 360 - angle; + return angle; +} + +static enum intersection_type line_intersect(const VGfloat *l1, + const VGfloat *l2, + float *intersection_point) +{ + VGfloat isect[2]; + enum intersection_type type; + VGboolean dx_zero, ldx_zero; + + if (null_line(l1) || null_line(l2) || + !finite_coords4(l1) || !finite_coords4(l2)) + return NoIntersections; + + type = do_lines_intersect(l1[0], l1[1], l1[2], l1[3], l2[0], l2[1], l2[2], l2[3]) + ? BoundedIntersection : UnboundedIntersection; + + dx_zero = floatsEqual(line_dx(l1) + 1, 1); + ldx_zero = floatsEqual(line_dx(l2) + 1, 1); + + /* one of the lines is vertical */ + if (dx_zero && ldx_zero) { + type = NoIntersections; + } else if (dx_zero) { + VGfloat la = line_dy(l2) / line_dx(l2); + isect[0] = l1[0]; + isect[1] = la * l1[0] + l2[1] - la * l2[0]; + } else if (ldx_zero) { + VGfloat ta = line_dy(l1) / line_dx(l1); + isect[0] = l2[0]; + isect[1] = ta * l2[0] + l1[1] - ta*l1[0]; + } else { + VGfloat x; + VGfloat ta = line_dy(l1) / line_dx(l1); + VGfloat la = line_dy(l2) / line_dx(l2); + if (ta == la) + return NoIntersections; + + x = ( - l2[1] + la * l2[0] + l1[1] - ta * l1[0] ) / (la - ta); + isect[0] = x; + isect[1] = ta*(x - l1[0]) + l1[1]; + } + if (intersection_point) { + intersection_point[0] = isect[0]; + intersection_point[1] = isect[1]; + } + return type; +} + +static INLINE enum line_join_mode stroker_join_mode(struct stroker *s) +{ + switch(s->join_style) { + case VG_JOIN_MITER: + return MiterJoin; + case VG_JOIN_ROUND: + return RoundJoin; + case VG_JOIN_BEVEL: + return FlatJoin; + default: + return FlatJoin; + } +} + +static INLINE enum line_join_mode stroker_cap_mode(struct stroker *s) +{ + switch(s->cap_style) { + case VG_CAP_BUTT: + return FlatJoin; + case VG_CAP_ROUND: + return RoundCap; + case VG_CAP_SQUARE: + return SquareJoin; + default: + return FlatJoin; + } +} + +void stroker_emit_move_to(struct stroker *stroker, VGfloat x, VGfloat y) +{ + VGubyte cmds = VG_MOVE_TO_ABS; + VGfloat coords[2] = {x, y}; +#if DEBUG_EMITS + debug_printf("emit move %f, %f\n", x, y); +#endif + stroker->back2_x = stroker->back1_x; + stroker->back2_y = stroker->back1_y; + stroker->back1_x = x; + stroker->back1_y = y; + + path_append_data(stroker->path, + 1, + &cmds, &coords); +} + +void stroker_emit_line_to(struct stroker *stroker, VGfloat x, VGfloat y) +{ + VGubyte cmds = VG_LINE_TO_ABS; + VGfloat coords[2] = {x, y}; +#if DEBUG_EMITS + debug_printf("emit line %f, %f\n", x, y); +#endif + stroker->back2_x = stroker->back1_x; + stroker->back2_y = stroker->back1_y; + stroker->back1_x = x; + stroker->back1_y = y; + path_append_data(stroker->path, + 1, + &cmds, &coords); +} + +void stroker_emit_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1, + VGfloat px2, VGfloat py2, + VGfloat x, VGfloat y) +{ + VGubyte cmds = VG_CUBIC_TO_ABS; + VGfloat coords[6] = {px1, py1, px2, py2, x, y}; +#if DEBUG_EMITS + debug_printf("emit curve %f, %f, %f, %f, %f, %f\n", px1, py1, + px2, py2, x, y); +#endif + + if (px2 == x && py2 == y) { + if (px1 == x && py1 == y) { + stroker->back2_x = stroker->back1_x; + stroker->back2_y = stroker->back1_y; + } else { + stroker->back2_x = px1; + stroker->back2_y = py1; + } + } else { + stroker->back2_x = px2; + stroker->back2_y = py2; + } + stroker->back1_x = x; + stroker->back1_y = y; + + path_append_data(stroker->path, + 1, + &cmds, &coords); +} + +static INLINE void create_round_join(struct stroker *stroker, + VGfloat x1, VGfloat y1, + VGfloat x2, VGfloat y2, + VGfloat width, VGfloat height) +{ + struct arc arc; + struct matrix matrix; + + matrix_load_identity(&matrix); + + /*stroker_emit_line_to(stroker, nx, ny);*/ + + arc_init(&arc, VG_SCCWARC_TO_ABS, + x1, y1, x2, y2, width/2, height/2, 0); + arc_stroker_emit(&arc, stroker, &matrix); +} + + +static void create_joins(struct stroker *stroker, + VGfloat focal_x, VGfloat focal_y, + const VGfloat *next_line, enum line_join_mode join) +{ +#if DEBUG_EMITS + debug_printf("create_joins: focal=[%f, %f], next_line=[%f, %f,%f, %f]\n", + focal_x, focal_y, + next_line[0], next_line[1], next_line[2], next_line[3]); +#endif + /* if we're alredy connected do nothing */ + if (floatsEqual(stroker->back1_x, next_line[0]) && + floatsEqual(stroker->back1_y, next_line[1])) + return; + + if (join == FlatJoin) { + stroker_emit_line_to(stroker, next_line[0], next_line[1]); + } else { + VGfloat prev_line[] = {stroker->back2_x, stroker->back2_y, + stroker->back1_x, stroker->back1_y}; + + VGfloat isect[2]; + enum intersection_type type = line_intersect(prev_line, next_line, isect); + + if (join == SquareJoin) { + VGfloat offset = stroker->stroke_width / 2; + VGfloat l1[4] = {prev_line[0], + prev_line[1], + prev_line[2], + prev_line[3]}; + VGfloat l2[4] = {next_line[2], + next_line[3], + next_line[0], + next_line[1]}; + + line_translate(l1, line_dx(l1), line_dy(l1)); + line_set_length(l1, offset); + + line_translate(l2, line_dx(l2), line_dy(l2)); + line_set_length(l2, offset); + + stroker_emit_line_to(stroker, l1[2], l1[3]); + stroker_emit_line_to(stroker, l2[2], l2[3]); + stroker_emit_line_to(stroker, l2[0], l2[1]); + } else if (join == RoundJoin) { + VGfloat offset = stroker->stroke_width / 2; + VGfloat short_cut[4] = {prev_line[2], prev_line[3], + next_line[0], next_line[1]}; + VGfloat angle = line_angles(prev_line, short_cut); + + if (type == BoundedIntersection || + (angle > 90 && !floatsEqual(angle, 90.f))) { + stroker_emit_line_to(stroker, next_line[0], next_line[1]); + return; + } + create_round_join(stroker, prev_line[2], prev_line[3], + next_line[0], next_line[1], + offset * 2, offset * 2); + + stroker_emit_line_to(stroker, next_line[0], next_line[1]); + } else if (join == RoundCap) { + VGfloat offset = stroker->stroke_width / 2; + VGfloat l1[4] = { prev_line[0], prev_line[1], + prev_line[2], prev_line[3] }; + VGfloat l2[4] = {focal_x, focal_y, + prev_line[2], prev_line[3]}; + + line_translate(l1, line_dx(l1), line_dy(l1)); + line_set_length(l1, KAPPA * offset); + + /* normal between prev_line and focal */ + line_translate(l2, -line_dy(l2), line_dx(l2)); + line_set_length(l2, KAPPA * offset); + + stroker_emit_curve_to(stroker, l1[2], l1[3], + l2[2], l2[3], + l2[0], l2[1]); + + l2[0] = l2[0]; + l2[1] = l2[1]; + l2[2] = l2[0] - line_dx(l2); + l2[3] = l2[1] - line_dy(l2); + + line_translate(l1, next_line[0] - l1[0], next_line[1] - l1[1]); + + stroker_emit_curve_to(stroker, + l2[2], l2[3], + l1[2], l1[3], + l1[0], l1[1]); + } else if (join == MiterJoin) { + VGfloat miter_line[4] = {stroker->back1_x, stroker->back1_y, + isect[0], isect[1]}; + VGfloat sl = (stroker->stroke_width * stroker->miter_limit); + VGfloat inside_line[4] = {prev_line[2], prev_line[3], + next_line[0], next_line[1]}; + VGfloat angle = line_angle_to(inside_line, prev_line); + + if (type == BoundedIntersection || + (angle > 90 && !floatsEqual(angle, 90.f))) { + /* + debug_printf("f = %f, nl = %f, pl = %f, is = %f\n", + focal_x, next_line[0], + prev_line[2], isect[0]);*/ + stroker_emit_line_to(stroker, next_line[0], next_line[1]); + return; + } + + if (type == NoIntersections || line_lengthv(miter_line) > sl) { + stroker_emit_line_to(stroker, next_line[0], next_line[1]); + } else { + stroker_emit_line_to(stroker, isect[0], isect[1]); + stroker_emit_line_to(stroker, next_line[0], next_line[1]); + } + } else { + debug_assert(!"create_joins bad join style"); + } + } +} + +static void stroker_add_segment(struct stroker *stroker, + VGPathCommand cmd, + const VGfloat *coords, + VGint num_coords) +{ + /* skip duplicated points */ + if (stroker->segments->num_elements && + stroker->last_cmd == cmd) { + VGfloat *data = stroker->control_points->data; + data += stroker->control_points->num_elements; + data -= num_coords; + switch (cmd) { + case VG_MOVE_TO_ABS: + if (floatsEqual(coords[0], data[0]) && + floatsEqual(coords[1], data[1])) + return; + break; + case VG_LINE_TO_ABS: + if (floatsEqual(coords[0], data[0]) && + floatsEqual(coords[1], data[1])) + return; + break; + case VG_CUBIC_TO_ABS: + if (floatsEqual(coords[0], data[0]) && + floatsEqual(coords[1], data[1]) && + floatsEqual(coords[2], data[2]) && + floatsEqual(coords[3], data[3]) && + floatsEqual(coords[4], data[4]) && + floatsEqual(coords[5], data[5])) + return; + break; + default: + debug_assert(!"Invalid stroke segment"); + } + } else if (stroker->last_cmd == VG_CUBIC_TO_ABS && + cmd == VG_LINE_TO_ABS) { + VGfloat *data = stroker->control_points->data; + data += stroker->control_points->num_elements; + data -= 2; + if (floatsEqual(coords[0], data[0]) && + floatsEqual(coords[1], data[1])) + return; + } + stroker->last_cmd = cmd; + array_append_data(stroker->segments, &cmd, 1); + array_append_data(stroker->control_points, coords, num_coords); +} + +void stroker_move_to(struct stroker *stroker, VGfloat x, VGfloat y) +{ + VGfloat coords[2] = {x, y}; +#if STROKE_SEGMENTS + debug_printf("stroker_move_to(%f, %f)\n", x, y); +#endif + + if (stroker->segments->num_elements > 0) + stroker->process_subpath(stroker); + + array_reset(stroker->segments); + array_reset(stroker->control_points); + + stroker_add_segment(stroker, VG_MOVE_TO_ABS, coords, 2); +} + +void stroker_line_to(struct stroker *stroker, VGfloat x, VGfloat y) +{ + VGfloat coords[] = {x, y}; + +#if STROKE_SEGMENTS + debug_printf("stroker_line_to(%f, %f)\n", x, y); +#endif + if (!stroker->segments->num_elements) + stroker_add_segment(stroker, VG_MOVE_TO_ABS, zero_coords, 2); + + stroker_add_segment(stroker, VG_LINE_TO_ABS, coords, 2); +} + +void stroker_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1, + VGfloat px2, VGfloat py2, + VGfloat x, VGfloat y) +{ + VGfloat coords[] = {px1, py1, + px2, py2, + x, y}; +#if STROKE_SEGMENTS + debug_printf("stroker_curve_to(%f, %f, %f, %f, %f, %f)\n", + px1, py1, px2, py2, x, y); +#endif + if (!stroker->segments->num_elements) + stroker_add_segment(stroker, VG_MOVE_TO_ABS, zero_coords, 2); + + stroker_add_segment(stroker, VG_CUBIC_TO_ABS, coords, 6); +} + +static INLINE VGboolean is_segment_null(VGPathCommand cmd, + VGfloat *coords, + VGfloat *res) +{ + switch(cmd) { + case VG_MOVE_TO_ABS: + case VG_LINE_TO_ABS: + return floatsEqual(coords[0], res[0]) && + floatsEqual(coords[1], res[1]); + break; + case VG_CUBIC_TO_ABS: + return floatsEqual(coords[0], res[0]) && + floatsEqual(coords[1], res[1]) && + floatsEqual(coords[2], res[0]) && + floatsEqual(coords[3], res[1]) && + floatsEqual(coords[4], res[0]) && + floatsEqual(coords[5], res[1]); + break; + default: + assert(0); + } + return VG_FALSE; +} + +static VGboolean vg_stroke_outline(struct stroke_iterator *it, + struct stroker *stroker, + VGboolean cap_first, + VGfloat *start_tangent) +{ + const int MAX_OFFSET = 16; + struct bezier offset_curves[MAX_OFFSET]; + VGPathCommand first_element; + VGfloat start[2], prev[2]; + VGboolean first = VG_TRUE; + VGfloat offset; + + first_element = stroke_itr_command(it); + if (first_element != VG_MOVE_TO_ABS) { + stroker_emit_move_to(stroker, 0.f, 0.f); + prev[0] = 0.f; + prev[1] = 0.f; + } + stroke_itr_coords(it, start); +#if STROKE_DEBUG + debug_printf(" -> (side) [%.2f, %.2f]\n", + start[0], + start[1]); +#endif + + prev[0] = start[0]; + prev[1] = start[1]; + + offset = stroker->stroke_width / 2; + + if (!it->has_next(it)) { + /* single point */ + + return VG_TRUE; + } + + while (it->has_next(it)) { + VGPathCommand cmd; + VGfloat coords[8]; + + it->next(it); + cmd = stroke_itr_command(it); + stroke_itr_coords(it, coords); + + if (cmd == VG_LINE_TO_ABS) { + VGfloat line[4] = {prev[0], prev[1], coords[0], coords[1]}; + VGfloat normal[4]; + line_normal(line, normal); + +#if STROKE_DEBUG + debug_printf("\n ---> (side) lineto [%.2f, %.2f]\n", coords[0], coords[1]); +#endif + line_set_length(normal, offset); + line_translate(line, line_dx(normal), line_dy(normal)); + + /* if we are starting a new subpath, move to correct starting point */ + if (first) { + if (cap_first) + create_joins(stroker, prev[0], prev[1], line, + stroker_cap_mode(stroker)); + else + stroker_emit_move_to(stroker, line[0], line[1]); + memcpy(start_tangent, line, + sizeof(VGfloat) * 4); + first = VG_FALSE; + } else { + create_joins(stroker, prev[0], prev[1], line, + stroker_join_mode(stroker)); + } + + /* add the stroke for this line */ + stroker_emit_line_to(stroker, line[2], line[3]); + prev[0] = coords[0]; + prev[1] = coords[1]; + } else if (cmd == VG_CUBIC_TO_ABS) { +#if STROKE_DEBUG + debug_printf("\n ---> (side) cubicTo [%.2f, %.2f]\n", + coords[4], + coords[5]); +#endif + struct bezier bezier; + int count; + + bezier_init(&bezier, + prev[0], prev[1], coords[0], coords[1], + coords[2], coords[3], coords[4], coords[5]); + + count = bezier_translate_by_normal(&bezier, + offset_curves, + MAX_OFFSET, + offset, + curve_threshold); + + if (count) { + /* if we are starting a new subpath, move to correct starting point */ + VGfloat tangent[4]; + VGint i; + + bezier_start_tangent(&bezier, tangent); + line_translate(tangent, + offset_curves[0].x1 - bezier.x1, + offset_curves[0].y1 - bezier.y1); + if (first) { + VGfloat pt[2] = {offset_curves[0].x1, + offset_curves[0].y1}; + + if (cap_first) { + create_joins(stroker, prev[0], prev[1], tangent, + stroker_cap_mode(stroker)); + } else { + stroker_emit_move_to(stroker, pt[0], pt[1]); + } + start_tangent[0] = tangent[0]; + start_tangent[1] = tangent[1]; + start_tangent[2] = tangent[2]; + start_tangent[3] = tangent[3]; + first = VG_FALSE; + } else { + create_joins(stroker, prev[0], prev[1], tangent, + stroker_join_mode(stroker)); + } + + /* add these beziers */ + for (i = 0; i < count; ++i) { + struct bezier *bez = &offset_curves[i]; + stroker_emit_curve_to(stroker, + bez->x2, bez->y2, + bez->x3, bez->y3, + bez->x4, bez->y4); + } + } + + prev[0] = coords[4]; + prev[1] = coords[5]; + } + } + + if (floatsEqual(start[0], prev[0]) && + floatsEqual(start[1], prev[1])) { + /* closed subpath, join first and last point */ +#if STROKE_DEBUG + debug_printf("\n stroker: closed subpath\n"); +#endif + create_joins(stroker, prev[0], prev[1], start_tangent, + stroker_join_mode(stroker)); + return VG_TRUE; + } else { +#if STROKE_DEBUG + debug_printf("\n stroker: open subpath\n"); +#endif + return VG_FALSE; + } +} + +static void stroker_process_subpath(struct stroker *stroker) +{ + VGboolean fwclosed, bwclosed; + VGfloat fw_start_tangent[4], bw_start_tangent[4]; + struct stroke_iterator fwit; + struct stroke_iterator bwit; + debug_assert(stroker->segments->num_elements > 0); + + memset(fw_start_tangent, 0, + sizeof(VGfloat)*4); + memset(bw_start_tangent, 0, + sizeof(VGfloat)*4); + + stroke_forward_iterator(&fwit, stroker->segments, + stroker->control_points); + stroke_backward_iterator(&bwit, stroker->segments, + stroker->control_points); + + debug_assert(fwit.cmds[0] == VG_MOVE_TO_ABS); + + fwclosed = vg_stroke_outline(&fwit, stroker, VG_FALSE, fw_start_tangent); + bwclosed = vg_stroke_outline(&bwit, stroker, !fwclosed, bw_start_tangent); + + if (!bwclosed) + create_joins(stroker, + fwit.coords[0], fwit.coords[1], fw_start_tangent, + stroker_cap_mode(stroker)); + else { + /* hack to handle the requirement of the VG spec that says that strokes + * of len==0 that have butt cap or round cap still need + * to be rendered. (8.7.4 Stroke Generation) */ + if (stroker->segments->num_elements <= 3) { + VGPathCommand cmd; + VGfloat data[8], coords[8]; + struct stroke_iterator *it = &fwit; + + stroke_forward_iterator(it, stroker->segments, + stroker->control_points); + cmd = stroke_itr_command(it); + stroke_itr_coords(it, coords); + if (cmd != VG_MOVE_TO_ABS) { + memset(data, 0, sizeof(VGfloat) * 8); + if (!is_segment_null(cmd, coords, data)) + return; + } else { + data[0] = coords[0]; + data[1] = coords[1]; + } + while (it->has_next(it)) { + it->next(it); + cmd = stroke_itr_command(it); + stroke_itr_coords(it, coords); + if (!is_segment_null(cmd, coords, data)) + return; + } + /* generate the square/round cap */ + if (stroker->cap_style == VG_CAP_SQUARE) { + VGfloat offset = stroker->stroke_width / 2; + stroker_emit_move_to(stroker, data[0] - offset, + data[1] - offset); + stroker_emit_line_to(stroker, data[0] + offset, + data[1] - offset); + stroker_emit_line_to(stroker, data[0] + offset, + data[1] + offset); + stroker_emit_line_to(stroker, data[0] - offset, + data[1] + offset); + stroker_emit_line_to(stroker, data[0] - offset, + data[1] - offset); + } else if (stroker->cap_style == VG_CAP_ROUND) { + VGfloat offset = stroker->stroke_width / 2; + VGfloat cx = data[0], cy = data[1]; + { /*circle */ + struct arc arc; + struct matrix matrix; + matrix_load_identity(&matrix); + + stroker_emit_move_to(stroker, cx + offset, cy); + arc_init(&arc, VG_SCCWARC_TO_ABS, + cx + offset, cy, + cx - offset, cy, + offset, offset, 0); + arc_stroker_emit(&arc, stroker, &matrix); + arc_init(&arc, VG_SCCWARC_TO_ABS, + cx - offset, cy, + cx + offset, cy, + offset, offset, 0); + arc_stroker_emit(&arc, stroker, &matrix); + } + } + } + } +} + +static INLINE VGfloat dash_pattern(struct dash_stroker *stroker, + VGint idx) +{ + if (stroker->dash_pattern[idx] < 0) + return 0.f; + return stroker->dash_pattern[idx]; +} + +static void dash_stroker_process_subpath(struct stroker *str) +{ + struct dash_stroker *stroker = (struct dash_stroker *)str; + VGfloat sum_length = 0; + VGint i; + VGint idash = 0; + VGfloat pos = 0; + VGfloat elen = 0; + VGfloat doffset = stroker->dash_phase; + VGfloat estart = 0; + VGfloat estop = 0; + VGfloat cline[4]; + struct stroke_iterator it; + VGfloat prev[2]; + VGfloat move_to_pos[2]; + VGfloat line_to_pos[2]; + + VGboolean has_move_to = VG_FALSE; + + stroke_flat_iterator(&it, stroker->base.segments, + stroker->base.control_points); + + stroke_itr_coords(&it, prev); + move_to_pos[0] = prev[0]; + move_to_pos[1] = prev[1]; + + debug_assert(stroker->dash_pattern_num > 0); + + for (i = 0; i < stroker->dash_pattern_num; ++i) { + sum_length += dash_pattern(stroker, i); + } + + if (floatIsZero(sum_length)) { + return; + } + + doffset -= floorf(doffset / sum_length) * sum_length; + + while (!floatIsZero(doffset) && doffset >= dash_pattern(stroker, idash)) { + doffset -= dash_pattern(stroker, idash); + idash = (idash + 1) % stroker->dash_pattern_num; + } + + while (it.has_next(&it)) { + VGPathCommand cmd; + VGfloat coords[8]; + VGboolean done; + + it.next(&it); + cmd = stroke_itr_command(&it); + stroke_itr_coords(&it, coords); + + debug_assert(cmd == VG_LINE_TO_ABS); + cline[0] = prev[0]; + cline[1] = prev[1]; + cline[2] = coords[0]; + cline[3] = coords[1]; + + elen = line_lengthv(cline); + + estop = estart + elen; + + done = pos >= estop; + while (!done) { + VGfloat p2[2]; + + VGint idash_incr = 0; + VGboolean has_offset = doffset > 0; + VGfloat dpos = pos + dash_pattern(stroker, idash) - doffset - estart; + + debug_assert(dpos >= 0); + + if (dpos > elen) { /* dash extends this line */ + doffset = dash_pattern(stroker, idash) - (dpos - elen); + pos = estop; + done = VG_TRUE; + p2[0] = cline[2]; + p2[1] = cline[3]; + } else { /* Dash is on this line */ + line_point_at(cline, dpos/elen, p2); + pos = dpos + estart; + done = pos >= estop; + idash_incr = 1; + doffset = 0; + } + + if (idash % 2 == 0) { + line_to_pos[0] = p2[0]; + line_to_pos[1] = p2[1]; + + if (!has_offset || !has_move_to) { + stroker_move_to(&stroker->stroker, move_to_pos[0], move_to_pos[1]); + has_move_to = VG_TRUE; + } + stroker_line_to(&stroker->stroker, line_to_pos[0], line_to_pos[1]); + } else { + move_to_pos[0] = p2[0]; + move_to_pos[1] = p2[1]; + } + + idash = (idash + idash_incr) % stroker->dash_pattern_num; + } + + estart = estop; + prev[0] = coords[0]; + prev[1] = coords[1]; + } + + if (it.curve_poly) { + polygon_destroy(it.curve_poly); + it.curve_poly = 0; + } + + stroker->base.path = stroker->stroker.path; +} + +static void default_begin(struct stroker *stroker) +{ + array_reset(stroker->segments); + array_reset(stroker->control_points); +} + +static void default_end(struct stroker *stroker) +{ + if (stroker->segments->num_elements > 0) + stroker->process_subpath(stroker); +} + + +static void dash_stroker_begin(struct stroker *stroker) +{ + struct dash_stroker *dasher = + (struct dash_stroker *)stroker; + + default_begin(&dasher->stroker); + default_begin(stroker); +} + +static void dash_stroker_end(struct stroker *stroker) +{ + struct dash_stroker *dasher = + (struct dash_stroker *)stroker; + + default_end(stroker); + default_end(&dasher->stroker); +} + +void stroker_init(struct stroker *stroker, + struct vg_state *state) +{ + stroker->stroke_width = state->stroke.line_width.f; + stroker->miter_limit = state->stroke.miter_limit.f; + stroker->cap_style = state->stroke.cap_style; + stroker->join_style = state->stroke.join_style; + + stroker->begin = default_begin; + stroker->process_subpath = stroker_process_subpath; + stroker->end = default_end; + + stroker->segments = array_create(sizeof(VGubyte)); + stroker->control_points = array_create(sizeof(VGfloat)); + + stroker->back1_x = 0; + stroker->back1_y = 0; + stroker->back2_x = 0; + stroker->back2_y = 0; + + stroker->path = path_create(VG_PATH_DATATYPE_F, 1.0f, 0.0f, + 0, 0, VG_PATH_CAPABILITY_ALL); + + stroker->last_cmd = VG_CLOSE_PATH; +} + +void dash_stroker_init(struct stroker *str, + struct vg_state *state) +{ + struct dash_stroker *stroker = (struct dash_stroker *)str; + int i; + + stroker_init(str, state); + stroker_init(&stroker->stroker, state); + + { + int real_num = state->stroke.dash_pattern_num; + if (real_num % 2)/* if odd, ignore the last one */ + --real_num; + for (i = 0; i < real_num; ++i) + stroker->dash_pattern[i] = state->stroke.dash_pattern[i].f; + stroker->dash_pattern_num = real_num; + } + + stroker->dash_phase = state->stroke.dash_phase.f; + stroker->dash_phase_reset = state->stroke.dash_phase_reset; + + stroker->base.begin = dash_stroker_begin; + stroker->base.process_subpath = dash_stroker_process_subpath; + stroker->base.end = dash_stroker_end; + path_destroy(stroker->base.path); + stroker->base.path = NULL; +} + +void stroker_begin(struct stroker *stroker) +{ + stroker->begin(stroker); +} + +void stroker_end(struct stroker *stroker) +{ + stroker->end(stroker); +} + +void stroker_cleanup(struct stroker *stroker) +{ + array_destroy(stroker->segments); + array_destroy(stroker->control_points); +} + +void dash_stroker_cleanup(struct dash_stroker *stroker) +{ + /* if stroker->base.path is null means we never + * processed a valid path so delete the temp one + * we already created */ + if (!stroker->base.path) + path_destroy(stroker->stroker.path); + stroker_cleanup(&stroker->stroker); + stroker_cleanup((struct stroker*)stroker); +} diff --git a/src/gallium/state_trackers/vega/stroker.h b/src/gallium/state_trackers/vega/stroker.h new file mode 100644 index 0000000000..36543cd923 --- /dev/null +++ b/src/gallium/state_trackers/vega/stroker.h @@ -0,0 +1,89 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STROKER_H +#define STROKER_H + +#include "VG/openvg.h" +#include "api_consts.h" + +struct path; +struct vg_state; +struct array; + +struct stroker { + void (*begin)(struct stroker *stroker); + void (*process_subpath)(struct stroker *stroker); + void (*end)(struct stroker *stroker); + + struct array *segments; + struct array *control_points; + struct path *path; + + VGfloat back1_x, back1_y; + VGfloat back2_x, back2_y; + + VGfloat stroke_width; + VGfloat miter_limit; + VGCapStyle cap_style; + VGJoinStyle join_style; + + VGPathCommand last_cmd; +}; + +struct dash_stroker { + struct stroker base; + + struct stroker stroker; + + VGfloat dash_pattern[VEGA_MAX_DASH_COUNT]; + VGint dash_pattern_num; + VGfloat dash_phase; + VGboolean dash_phase_reset; +}; + +void stroker_init(struct stroker *stroker, + struct vg_state *state); +void dash_stroker_init(struct stroker *stroker, + struct vg_state *state); +void dash_stroker_cleanup(struct dash_stroker *stroker); +void stroker_cleanup(struct stroker *stroker); + +void stroker_begin(struct stroker *stroker); +void stroker_move_to(struct stroker *stroker, VGfloat x, VGfloat y); +void stroker_line_to(struct stroker *stroker, VGfloat x, VGfloat y); +void stroker_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1, + VGfloat px2, VGfloat py2, + VGfloat x, VGfloat y); +void stroker_end(struct stroker *stroker); + +void stroker_emit_move_to(struct stroker *stroker, VGfloat x, VGfloat y); +void stroker_emit_line_to(struct stroker *stroker, VGfloat x, VGfloat y); +void stroker_emit_curve_to(struct stroker *stroker, VGfloat px1, VGfloat py1, + VGfloat px2, VGfloat py2, + VGfloat x, VGfloat y); + +#endif diff --git a/src/gallium/state_trackers/vega/util_array.h b/src/gallium/state_trackers/vega/util_array.h new file mode 100644 index 0000000000..4343dfe36e --- /dev/null +++ b/src/gallium/state_trackers/vega/util_array.h @@ -0,0 +1,122 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef UTIL_ARRAY_H +#define UTIL_ARRAY_H + +#include "util/u_memory.h" + +#define DEFAULT_ARRAY_SIZE 256 + +struct array { + VGint datatype_size; + void *data; + VGint size; + VGint num_elements; +}; + +static INLINE struct array *array_create(VGint datatype_size) +{ + struct array *array = CALLOC_STRUCT(array); + array->datatype_size = datatype_size; + + array->size = DEFAULT_ARRAY_SIZE; + array->data = malloc(array->size * array->datatype_size); + + return array; +} + + +static INLINE struct array *array_create_size(VGint datatype_size, VGint size) +{ + struct array *array = CALLOC_STRUCT(array); + array->datatype_size = datatype_size; + + array->size = size; + array->data = malloc(array->size * array->datatype_size); + + return array; +} + +static INLINE void array_destroy(struct array *array) +{ + if (array) + free(array->data); + free(array); +} + +static INLINE void array_resize(struct array *array, int num) +{ + VGint size = array->datatype_size * num; + void *data = malloc(size); + memcpy(data, array->data, array->size * array->datatype_size); + free(array->data); + array->data = data; + array->size = num; + array->num_elements = (array->num_elements > num) ? num : + array->num_elements; +} + +static INLINE void array_append_data(struct array *array, + const void *data, int num_elements) +{ + VGbyte *adata; + + while (array->num_elements + num_elements > array->size) { + array_resize(array, (array->num_elements + num_elements) * 1.5); + } + adata = (VGbyte *)array->data; + memcpy(adata + (array->num_elements * array->datatype_size), data, + num_elements * array->datatype_size); + array->num_elements += num_elements; +} + +static INLINE void array_change_data(struct array *array, + const void *data, + int start_idx, + int num_elements) +{ + VGbyte *adata = (VGbyte *)array->data; + memcpy(adata + (start_idx * array->datatype_size), data, + num_elements * array->datatype_size); +} + +static INLINE void array_remove_element(struct array *array, + int idx) +{ + VGbyte *adata = (VGbyte *)array->data; + memmove(adata + (idx * array->datatype_size), + adata + ((idx + 1) * array->datatype_size), + (array->num_elements - idx - 1) * array->datatype_size); + --array->num_elements; +} + +static INLINE void array_reset(struct array *array) +{ + array->num_elements = 0; +} + +#endif diff --git a/src/gallium/state_trackers/vega/vg_context.c b/src/gallium/state_trackers/vega/vg_context.c new file mode 100644 index 0000000000..e0ff02f3a9 --- /dev/null +++ b/src/gallium/state_trackers/vega/vg_context.c @@ -0,0 +1,543 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "vg_context.h" + +#include "paint.h" +#include "renderer.h" +#include "shaders_cache.h" +#include "shader.h" +#include "asm_util.h" +#include "st_inlines.h" + +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "pipe/p_shader_tokens.h" + +#include "cso_cache/cso_context.h" + +#include "util/u_simple_shaders.h" +#include "util/u_memory.h" +#include "util/u_blit.h" + +struct vg_context *_vg_context = 0; + +struct vg_context * vg_current_context(void) +{ + return _vg_context; +} + +static void init_clear(struct vg_context *st) +{ + struct pipe_context *pipe = st->pipe; + + /* rasterizer state: bypass clipping */ + memset(&st->clear.raster, 0, sizeof(st->clear.raster)); + st->clear.raster.gl_rasterization_rules = 1; + + /* fragment shader state: color pass-through program */ + st->clear.fs = + util_make_fragment_passthrough_shader(pipe); +} +void vg_set_current_context(struct vg_context *ctx) +{ + _vg_context = ctx; +} + +struct vg_context * vg_create_context(struct pipe_context *pipe, + const void *visual, + struct vg_context *share) +{ + struct vg_context *ctx; + + ctx = CALLOC_STRUCT(vg_context); + + ctx->pipe = pipe; + + vg_init_state(&ctx->state.vg); + ctx->state.dirty = ALL_DIRTY; + + ctx->cso_context = cso_create_context(pipe); + + init_clear(ctx); + + ctx->default_paint = paint_create(ctx); + ctx->state.vg.stroke_paint = ctx->default_paint; + ctx->state.vg.fill_paint = ctx->default_paint; + + + ctx->mask.sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + ctx->mask.sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + ctx->mask.sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + ctx->mask.sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + ctx->mask.sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + ctx->mask.sampler.normalized_coords = 0; + + ctx->blend_sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + ctx->blend_sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + ctx->blend_sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + ctx->blend_sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + ctx->blend_sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + ctx->blend_sampler.normalized_coords = 0; + + vg_set_error(ctx, VG_NO_ERROR); + + ctx->owned_objects[VG_OBJECT_PAINT] = cso_hash_create(); + ctx->owned_objects[VG_OBJECT_IMAGE] = cso_hash_create(); + ctx->owned_objects[VG_OBJECT_MASK] = cso_hash_create(); + ctx->owned_objects[VG_OBJECT_FONT] = cso_hash_create(); + ctx->owned_objects[VG_OBJECT_PATH] = cso_hash_create(); + + ctx->renderer = renderer_create(ctx); + ctx->sc = shaders_cache_create(ctx); + ctx->shader = shader_create(ctx); + + ctx->blit = util_create_blit(ctx->pipe, ctx->cso_context); + + return ctx; +} + +void vg_destroy_context(struct vg_context *ctx) +{ + struct pipe_constant_buffer *cbuf = &ctx->mask.cbuf; + struct pipe_constant_buffer *vsbuf = &ctx->vs_const_buffer; + + util_destroy_blit(ctx->blit); + renderer_destroy(ctx->renderer); + shaders_cache_destroy(ctx->sc); + shader_destroy(ctx->shader); + paint_destroy(ctx->default_paint); + + if (cbuf && cbuf->buffer) + pipe_buffer_reference(&cbuf->buffer, NULL); + + if (vsbuf && vsbuf->buffer) + pipe_buffer_reference(&vsbuf->buffer, NULL); + + if (ctx->clear.fs) { + cso_delete_fragment_shader(ctx->cso_context, ctx->clear.fs); + ctx->clear.fs = NULL; + } + + if (ctx->plain_vs) { + vg_shader_destroy(ctx, ctx->plain_vs); + ctx->plain_vs = NULL; + } + if (ctx->clear_vs) { + vg_shader_destroy(ctx, ctx->clear_vs); + ctx->clear_vs = NULL; + } + if (ctx->texture_vs) { + vg_shader_destroy(ctx, ctx->texture_vs); + ctx->texture_vs = NULL; + } + + if (ctx->pass_through_depth_fs) + vg_shader_destroy(ctx, ctx->pass_through_depth_fs); + if (ctx->mask.union_fs) + vg_shader_destroy(ctx, ctx->mask.union_fs); + if (ctx->mask.intersect_fs) + vg_shader_destroy(ctx, ctx->mask.intersect_fs); + if (ctx->mask.subtract_fs) + vg_shader_destroy(ctx, ctx->mask.subtract_fs); + if (ctx->mask.set_fs) + vg_shader_destroy(ctx, ctx->mask.set_fs); + + cso_release_all(ctx->cso_context); + cso_destroy_context(ctx->cso_context); + + cso_hash_delete(ctx->owned_objects[VG_OBJECT_PAINT]); + cso_hash_delete(ctx->owned_objects[VG_OBJECT_IMAGE]); + cso_hash_delete(ctx->owned_objects[VG_OBJECT_MASK]); + cso_hash_delete(ctx->owned_objects[VG_OBJECT_FONT]); + cso_hash_delete(ctx->owned_objects[VG_OBJECT_PATH]); + + free(ctx); +} + +void vg_init_object(struct vg_object *obj, struct vg_context *ctx, enum vg_object_type type) +{ + obj->type = type; + obj->ctx = ctx; +} + +VGboolean vg_context_is_object_valid(struct vg_context *ctx, + enum vg_object_type type, + void *ptr) +{ + if (ctx) { + struct cso_hash *hash = ctx->owned_objects[type]; + if (!hash) + return VG_FALSE; + return cso_hash_contains(hash, (unsigned)(long)ptr); + } + return VG_FALSE; +} + +void vg_context_add_object(struct vg_context *ctx, + enum vg_object_type type, + void *ptr) +{ + if (ctx) { + struct cso_hash *hash = ctx->owned_objects[type]; + if (!hash) + return; + cso_hash_insert(hash, (unsigned)(long)ptr, ptr); + } +} + +void vg_context_remove_object(struct vg_context *ctx, + enum vg_object_type type, + void *ptr) +{ + if (ctx) { + struct cso_hash *hash = ctx->owned_objects[type]; + if (!hash) + return; + cso_hash_take(hash, (unsigned)(long)ptr); + } +} + +static void update_clip_state(struct vg_context *ctx) +{ + struct pipe_depth_stencil_alpha_state *dsa = &ctx->state.g3d.dsa; + struct vg_state *state = &ctx->state.vg; + + memset(dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); + + if (state->scissoring) { + struct pipe_blend_state *blend = &ctx->state.g3d.blend; + struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; + dsa->depth.writemask = 1;/*glDepthMask(TRUE);*/ + dsa->depth.func = PIPE_FUNC_ALWAYS; + dsa->depth.enabled = 1; + + cso_save_blend(ctx->cso_context); + cso_save_fragment_shader(ctx->cso_context); + /* set a passthrough shader */ + if (!ctx->pass_through_depth_fs) + ctx->pass_through_depth_fs = shader_create_from_text(ctx->pipe, + pass_through_depth_asm, + 40, + PIPE_SHADER_FRAGMENT); + cso_set_fragment_shader_handle(ctx->cso_context, + ctx->pass_through_depth_fs->driver); + cso_set_depth_stencil_alpha(ctx->cso_context, dsa); + + ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, NULL, 1.0, 0); + + /* disable color writes */ + blend->colormask = 0; /*disable colorwrites*/ + cso_set_blend(ctx->cso_context, blend); + + /* enable scissoring */ + for (int i = 0; i < state->scissor_rects_num; ++i) { + const float x = state->scissor_rects[i * 4 + 0].f; + const float y = state->scissor_rects[i * 4 + 1].f; + const float width = state->scissor_rects[i * 4 + 2].f; + const float height = state->scissor_rects[i * 4 + 3].f; + VGfloat minx, miny, maxx, maxy; + + minx = 0; + miny = 0; + maxx = fb->width; + maxy = fb->height; + + if (x > minx) + minx = x; + if (y > miny) + miny = y; + + if (x + width < maxx) + maxx = x + width; + if (y + height < maxy) + maxy = y + height; + + /* check for null space */ + if (minx >= maxx || miny >= maxy) + minx = miny = maxx = maxy = 0; + + /*glClear(GL_DEPTH_BUFFER_BIT);*/ + renderer_draw_quad(ctx->renderer, minx, miny, maxx, maxy, 0.0f); + } + + blend->colormask = 1; /*enable colorwrites*/ + cso_restore_blend(ctx->cso_context); + cso_restore_fragment_shader(ctx->cso_context); + + dsa->depth.enabled = 1; /* glEnable(GL_DEPTH_TEST); */ + dsa->depth.writemask = 0;/*glDepthMask(FALSE);*/ + dsa->depth.func = PIPE_FUNC_GEQUAL; + } +} + +void vg_validate_state(struct vg_context *ctx) +{ + if ((ctx->state.dirty & BLEND_DIRTY)) { + struct pipe_blend_state *blend = &ctx->state.g3d.blend; + memset(blend, 0, sizeof(struct pipe_blend_state)); + blend->blend_enable = 1; + blend->colormask |= PIPE_MASK_R; + blend->colormask |= PIPE_MASK_G; + blend->colormask |= PIPE_MASK_B; + blend->colormask |= PIPE_MASK_A; + + switch (ctx->state.vg.blend_mode) { + case VG_BLEND_SRC: + blend->rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend->rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend->alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + break; + case VG_BLEND_SRC_OVER: + blend->rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend->rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; + blend->alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; + break; + case VG_BLEND_DST_OVER: + blend->rgb_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA; + blend->alpha_src_factor = PIPE_BLENDFACTOR_INV_DST_ALPHA; + blend->rgb_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA; + blend->alpha_dst_factor = PIPE_BLENDFACTOR_DST_ALPHA; + break; + case VG_BLEND_SRC_IN: + blend->rgb_src_factor = PIPE_BLENDFACTOR_DST_ALPHA; + blend->alpha_src_factor = PIPE_BLENDFACTOR_DST_ALPHA; + blend->rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend->alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + break; + case VG_BLEND_DST_IN: + blend->rgb_src_factor = PIPE_BLENDFACTOR_ZERO; + blend->alpha_src_factor = PIPE_BLENDFACTOR_ZERO; + blend->rgb_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + blend->alpha_dst_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + break; + case VG_BLEND_MULTIPLY: + case VG_BLEND_SCREEN: + case VG_BLEND_DARKEN: + case VG_BLEND_LIGHTEN: + blend->rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend->rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend->alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + break; + case VG_BLEND_ADDITIVE: + blend->rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend->alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend->rgb_dst_factor = PIPE_BLENDFACTOR_ONE; + blend->alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + break; + default: + assert(!"not implemented blend mode"); + } + cso_set_blend(ctx->cso_context, &ctx->state.g3d.blend); + } + if ((ctx->state.dirty & RASTERIZER_DIRTY)) { + struct pipe_rasterizer_state *raster = &ctx->state.g3d.rasterizer; + memset(raster, 0, sizeof(struct pipe_rasterizer_state)); + raster->gl_rasterization_rules = 1; + cso_set_rasterizer(ctx->cso_context, &ctx->state.g3d.rasterizer); + } + if ((ctx->state.dirty & VIEWPORT_DIRTY)) { + struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; + const VGint param_bytes = 8 * sizeof(VGfloat); + VGfloat vs_consts[8] = { + 2.f/fb->width, 2.f/fb->height, 1, 1, + -1, -1, 0, 0 + }; + struct pipe_constant_buffer *cbuf = &ctx->vs_const_buffer; + + vg_set_viewport(ctx, VEGA_Y0_BOTTOM); + + pipe_buffer_reference(&cbuf->buffer, NULL); + cbuf->buffer = pipe_buffer_create(ctx->pipe->screen, 16, + PIPE_BUFFER_USAGE_CONSTANT, + param_bytes); + + if (cbuf->buffer) { + st_no_flush_pipe_buffer_write(ctx, cbuf->buffer, + 0, param_bytes, vs_consts); + } + ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_VERTEX, 0, cbuf); + } + if ((ctx->state.dirty & VS_DIRTY)) { + cso_set_vertex_shader_handle(ctx->cso_context, + vg_plain_vs(ctx)); + } + + /* must be last because it renders to the depth buffer*/ + if ((ctx->state.dirty & DEPTH_STENCIL_DIRTY)) { + update_clip_state(ctx); + cso_set_depth_stencil_alpha(ctx->cso_context, &ctx->state.g3d.dsa); + } + + shader_set_masking(ctx->shader, ctx->state.vg.masking); + shader_set_image_mode(ctx->shader, ctx->state.vg.image_mode); + + ctx->state.dirty = NONE_DIRTY; +} + +VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type) +{ + struct vg_object *obj = ptr; + if (ptr && is_aligned(obj) && obj->type == type) + return VG_TRUE; + else + return VG_FALSE; +} + +void vg_set_error(struct vg_context *ctx, + VGErrorCode code) +{ + /*vgGetError returns the oldest error code provided by + * an API call on the current context since the previous + * call to vgGetError on that context (or since the creation + of the context).*/ + if (ctx->_error == VG_NO_ERROR) + ctx->_error = code; +} + +void vg_prepare_blend_surface(struct vg_context *ctx) +{ + struct pipe_surface *dest_surface = NULL; + struct pipe_context *pipe = ctx->pipe; + struct st_framebuffer *stfb = ctx->draw_buffer; + struct st_renderbuffer *strb = stfb->strb; + + /* first finish all pending rendering */ + vgFinish(); + + dest_surface = pipe->screen->get_tex_surface(pipe->screen, + stfb->blend_texture, + 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + /* flip it, because we want to use it as a sampler */ + util_blit_pixels_tex(ctx->blit, + strb->texture, + 0, strb->height, + strb->width, 0, + dest_surface, + 0, 0, + strb->width, strb->height, + 0.0, PIPE_TEX_MIPFILTER_NEAREST); + + if (dest_surface) + pipe_surface_reference(&dest_surface, NULL); + + /* make sure it's complete */ + vgFinish(); +} + + +void vg_prepare_blend_surface_from_mask(struct vg_context *ctx) +{ + struct pipe_surface *dest_surface = NULL; + struct pipe_context *pipe = ctx->pipe; + struct st_framebuffer *stfb = ctx->draw_buffer; + struct st_renderbuffer *strb = stfb->strb; + + vg_validate_state(ctx); + + /* first finish all pending rendering */ + vgFinish(); + + dest_surface = pipe->screen->get_tex_surface(pipe->screen, + stfb->blend_texture, + 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + + /* flip it, because we want to use it as a sampler */ + util_blit_pixels_tex(ctx->blit, + stfb->alpha_mask, + 0, strb->height, + strb->width, 0, + dest_surface, + 0, 0, + strb->width, strb->height, + 0.0, PIPE_TEX_MIPFILTER_NEAREST); + + /* make sure it's complete */ + vgFinish(); + + if (dest_surface) + pipe_surface_reference(&dest_surface, NULL); +} + +void * vg_plain_vs(struct vg_context *ctx) +{ + if (!ctx->plain_vs) { + ctx->plain_vs = shader_create_from_text(ctx->pipe, + vs_plain_asm, + 200, + PIPE_SHADER_VERTEX); + } + + return ctx->plain_vs->driver; +} + + +void * vg_clear_vs(struct vg_context *ctx) +{ + if (!ctx->clear_vs) { + ctx->clear_vs = shader_create_from_text(ctx->pipe, + vs_clear_asm, + 200, + PIPE_SHADER_VERTEX); + } + + return ctx->clear_vs->driver; +} + +void * vg_texture_vs(struct vg_context *ctx) +{ + if (!ctx->texture_vs) { + ctx->texture_vs = shader_create_from_text(ctx->pipe, + vs_texture_asm, + 200, + PIPE_SHADER_VERTEX); + } + + return ctx->texture_vs->driver; +} + +void vg_set_viewport(struct vg_context *ctx, VegaOrientation orientation) +{ + struct pipe_viewport_state viewport; + struct pipe_framebuffer_state *fb = &ctx->state.g3d.fb; + VGfloat y_scale = (orientation == VEGA_Y0_BOTTOM) ? -2.f : 2.f; + + viewport.scale[0] = fb->width / 2.f; + viewport.scale[1] = fb->height / y_scale; + viewport.scale[2] = 1.0; + viewport.scale[3] = 1.0; + viewport.translate[0] = fb->width / 2.f; + viewport.translate[1] = fb->height / 2.f; + viewport.translate[2] = 0.0; + viewport.translate[3] = 0.0; + + cso_set_viewport(ctx->cso_context, &viewport); +} diff --git a/src/gallium/state_trackers/vega/vg_context.h b/src/gallium/state_trackers/vega/vg_context.h new file mode 100644 index 0000000000..ccc8889c8c --- /dev/null +++ b/src/gallium/state_trackers/vega/vg_context.h @@ -0,0 +1,292 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef VG_CONTEXT_H +#define VG_CONTEXT_H + +#include "vg_state.h" + +#include "pipe/p_format.h" +#include "pipe/p_state.h" +#include "util/u_pointer.h" +#include "util/u_math.h" + +#include "cso_cache/cso_hash.h" +#include "cso_cache/cso_context.h" + +struct renderer; +struct shaders_cache; +struct shader; +struct vg_shader; + +struct st_renderbuffer { + enum pipe_format format; + struct pipe_surface *surface; + struct pipe_texture *texture; + VGint width, height; +}; + +struct st_framebuffer { + VGint init_width, init_height; + struct st_renderbuffer *strb; + struct st_renderbuffer *dsrb; + + struct pipe_texture *alpha_mask; + + struct pipe_texture *blend_texture; + + void *privateData; +}; + +enum vg_object_type { + VG_OBJECT_UNKNOWN = 0, + VG_OBJECT_PAINT, + VG_OBJECT_IMAGE, + VG_OBJECT_MASK, + VG_OBJECT_FONT, + VG_OBJECT_PATH, + + VG_OBJECT_LAST +}; +enum dirty_state { + NONE_DIRTY = 0<<0, + BLEND_DIRTY = 1<<1, + RASTERIZER_DIRTY = 1<<2, + VIEWPORT_DIRTY = 1<<3, + VS_DIRTY = 1<<4, + DEPTH_STENCIL_DIRTY = 1<<5, + ALL_DIRTY = BLEND_DIRTY | RASTERIZER_DIRTY | + VIEWPORT_DIRTY | VS_DIRTY | DEPTH_STENCIL_DIRTY +}; + +struct vg_context +{ + struct pipe_context *pipe; + + struct { + struct vg_state vg; + struct { + struct pipe_blend_state blend; + struct pipe_rasterizer_state rasterizer; + struct pipe_shader_state vs_state; + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_framebuffer_state fb; + } g3d; + VGbitfield dirty; + } state; + + VGErrorCode _error; + + struct st_framebuffer *draw_buffer; + + struct cso_hash *owned_objects[VG_OBJECT_LAST]; + + struct { + struct pipe_shader_state vert_shader; + struct pipe_shader_state frag_shader; + struct pipe_rasterizer_state raster; + void *fs; + float vertices[4][2][4]; /**< vertex pos + color */ + } clear; + + struct { + struct pipe_constant_buffer cbuf; + struct pipe_sampler_state sampler; + + struct vg_shader *union_fs; + struct vg_shader *intersect_fs; + struct vg_shader *subtract_fs; + struct vg_shader *set_fs; + } mask; + + struct vg_shader *pass_through_depth_fs; + + struct cso_context *cso_context; + + struct pipe_buffer *stencil_quad; + VGfloat stencil_vertices[4][2][4]; + + struct renderer *renderer; + struct shaders_cache *sc; + struct shader *shader; + + struct pipe_sampler_state blend_sampler; + struct { + struct pipe_constant_buffer buffer; + void *color_matrix_fs; + } filter; + struct vg_paint *default_paint; + + struct blit_state *blit; + + struct vg_shader *plain_vs; + struct vg_shader *clear_vs; + struct vg_shader *texture_vs; + struct pipe_constant_buffer vs_const_buffer; +}; + +struct vg_object { + enum vg_object_type type; + struct vg_context *ctx; +}; +void vg_init_object(struct vg_object *obj, struct vg_context *ctx, enum vg_object_type type); +VGboolean vg_object_is_valid(void *ptr, enum vg_object_type type); + +struct vg_context *vg_create_context(struct pipe_context *pipe, + const void *visual, + struct vg_context *share); +void vg_destroy_context(struct vg_context *ctx); +struct vg_context *vg_current_context(void); +void vg_set_current_context(struct vg_context *ctx); + +VGboolean vg_context_is_object_valid(struct vg_context *ctx, + enum vg_object_type type, + void *ptr); +void vg_context_add_object(struct vg_context *ctx, + enum vg_object_type type, + void *ptr); +void vg_context_remove_object(struct vg_context *ctx, + enum vg_object_type type, + void *ptr); + +void vg_validate_state(struct vg_context *ctx); + +void vg_set_error(struct vg_context *ctx, + VGErrorCode code); + +void vg_prepare_blend_surface(struct vg_context *ctx); +void vg_prepare_blend_surface_from_mask(struct vg_context *ctx); + + +static INLINE VGboolean is_aligned_to(const void *ptr, VGbyte alignment) +{ + void *aligned = align_pointer(ptr, alignment); + return (ptr == aligned) ? VG_TRUE : VG_FALSE; +} + +static INLINE VGboolean is_aligned(const void *ptr) +{ + return is_aligned_to(ptr, 4); +} + +static INLINE void vg_shift_rectx(VGfloat coords[4], + const VGfloat *bounds, + const VGfloat shift) +{ + coords[0] += shift; + coords[2] -= shift; + if (bounds) { + coords[2] = MIN2(coords[2], bounds[2]); + /* bound x/y + width/height */ + if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) { + coords[2] = (bounds[0] + bounds[2]) - coords[0]; + } + } +} + +static INLINE void vg_shift_recty(VGfloat coords[4], + const VGfloat *bounds, + const VGfloat shift) +{ + coords[1] += shift; + coords[3] -= shift; + if (bounds) { + coords[3] = MIN2(coords[3], bounds[3]); + if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) { + coords[3] = (bounds[1] + bounds[3]) - coords[1]; + } + } +} + +static INLINE void vg_bound_rect(VGfloat coords[4], + const VGfloat bounds[4], + VGfloat shift[4]) +{ + /* if outside the bounds */ + if (coords[0] > (bounds[0] + bounds[2]) || + coords[1] > (bounds[1] + bounds[3]) || + (coords[0] + coords[2]) < bounds[0] || + (coords[1] + coords[3]) < bounds[1]) { + coords[0] = 0.f; + coords[1] = 0.f; + coords[2] = 0.f; + coords[3] = 0.f; + shift[0] = 0.f; + shift[1] = 0.f; + return; + } + + /* bound x */ + if (coords[0] < bounds[0]) { + shift[0] = bounds[0] - coords[0]; + coords[2] -= shift[0]; + coords[0] = bounds[0]; + } else + shift[0] = 0.f; + + /* bound y */ + if (coords[1] < bounds[1]) { + shift[1] = bounds[1] - coords[1]; + coords[3] -= shift[1]; + coords[1] = bounds[1]; + } else + shift[1] = 0.f; + + shift[2] = bounds[2] - coords[2]; + shift[3] = bounds[3] - coords[3]; + /* bound width/height */ + coords[2] = MIN2(coords[2], bounds[2]); + coords[3] = MIN2(coords[3], bounds[3]); + + /* bound x/y + width/height */ + if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) { + coords[2] = (bounds[0] + bounds[2]) - coords[0]; + } + if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) { + coords[3] = (bounds[1] + bounds[3]) - coords[1]; + } + + /* if outside the bounds */ + if ((coords[0] + coords[2]) < bounds[0] || + (coords[1] + coords[3]) < bounds[1]) { + coords[0] = 0.f; + coords[1] = 0.f; + coords[2] = 0.f; + coords[3] = 0.f; + return; + } +} + +void *vg_plain_vs(struct vg_context *ctx); +void *vg_clear_vs(struct vg_context *ctx); +void *vg_texture_vs(struct vg_context *ctx); +typedef enum { + VEGA_Y0_TOP, + VEGA_Y0_BOTTOM +} VegaOrientation; +void vg_set_viewport(struct vg_context *ctx, VegaOrientation orientation); + +#endif diff --git a/src/gallium/state_trackers/vega/vg_state.c b/src/gallium/state_trackers/vega/vg_state.c new file mode 100644 index 0000000000..6f6bfdaf7a --- /dev/null +++ b/src/gallium/state_trackers/vega/vg_state.c @@ -0,0 +1,124 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "vg_state.h" + +#include <string.h> + +void vg_init_state(struct vg_state *state) +{ + state->matrix_mode = VG_MATRIX_PATH_USER_TO_SURFACE; + state->fill_rule = VG_EVEN_ODD; + state->image_quality = VG_IMAGE_QUALITY_FASTER; + state->rendering_quality = VG_RENDERING_QUALITY_BETTER; + state->blend_mode = VG_BLEND_SRC_OVER; + state->image_mode = VG_DRAW_IMAGE_NORMAL; + + memset(state->scissor_rects, 0, sizeof(state->scissor_rects)); + state->scissor_rects_num = 0; + + state->color_transform = VG_FALSE; + state->color_transform_values[0] = 1.0f; + state->color_transform_values[1] = 1.0f; + state->color_transform_values[2] = 1.0f; + state->color_transform_values[3] = 1.0f; + state->color_transform_values[4] = 0.0f; + state->color_transform_values[5] = 0.0f; + state->color_transform_values[6] = 0.0f; + state->color_transform_values[7] = 0.0f; + + /* Stroke parameters */ + state->stroke.line_width.f = 1.0f; + state->stroke.line_width.i = 1; + state->stroke.cap_style = VG_CAP_BUTT; + state->stroke.join_style = VG_JOIN_MITER; + state->stroke.miter_limit.f = 4.0f; + state->stroke.miter_limit.i = 4; + state->stroke.dash_pattern_num = 0; + state->stroke.dash_phase.f = 0.0f; + state->stroke.dash_phase.i = 0; + state->stroke.dash_phase_reset = VG_FALSE; + + /* Edge fill color for VG_TILE_FILL tiling mode */ + state->tile_fill_color[0] = 0.0f; + state->tile_fill_color[1] = 0.0f; + state->tile_fill_color[2] = 0.0f; + state->tile_fill_color[3] = 0.0f; + + /* Color for vgClear */ + state->clear_color[0] = 0.0f; + state->clear_color[1] = 0.0f; + state->clear_color[2] = 0.0f; + state->clear_color[3] = 0.0f; + + /* Glyph origin */ + state->glyph_origin[0].f = 0.0f; + state->glyph_origin[1].f = 0.0f; + state->glyph_origin[0].i = 0; + state->glyph_origin[1].i = 0; + + /* Enable/disable alpha masking and scissoring */ + state->masking = VG_FALSE; + state->scissoring = VG_FALSE; + + /* Pixel layout information */ + state->pixel_layout = VG_PIXEL_LAYOUT_UNKNOWN; + state->screen_layout = VG_PIXEL_LAYOUT_UNKNOWN; + + /* Source format selection for image filters */ + state->filter_format_linear = VG_FALSE; + state->filter_format_premultiplied = VG_FALSE; + + /* Destination write enable mask for image filters */ + state->filter_channel_mask = (VG_RED | VG_GREEN | VG_BLUE | VG_ALPHA); + + matrix_load_identity(&state->path_user_to_surface_matrix); + matrix_load_identity(&state->image_user_to_surface_matrix); + matrix_load_identity(&state->fill_paint_to_user_matrix); + matrix_load_identity(&state->stroke_paint_to_user_matrix); + matrix_load_identity(&state->glyph_user_to_surface_matrix); +} + +struct matrix *vg_state_matrix(struct vg_state *state) +{ + switch(state->matrix_mode) { + case VG_MATRIX_PATH_USER_TO_SURFACE: + return &state->path_user_to_surface_matrix; + case VG_MATRIX_IMAGE_USER_TO_SURFACE: + return &state->image_user_to_surface_matrix; + case VG_MATRIX_FILL_PAINT_TO_USER: + return &state->fill_paint_to_user_matrix; + case VG_MATRIX_STROKE_PAINT_TO_USER: + return &state->stroke_paint_to_user_matrix; +#ifdef OPENVG_VERSION_1_1 + case VG_MATRIX_GLYPH_USER_TO_SURFACE: + return &state->glyph_user_to_surface_matrix; +#endif + default: + break; + } + return NULL; +} diff --git a/src/gallium/state_trackers/vega/vg_state.h b/src/gallium/state_trackers/vega/vg_state.h new file mode 100644 index 0000000000..ed90689f91 --- /dev/null +++ b/src/gallium/state_trackers/vega/vg_state.h @@ -0,0 +1,109 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef VG_STATE_H +#define VG_STATE_H + +#include "VG/openvg.h" + +#include "api_consts.h" +#include "matrix.h" + +struct vg_value +{ + VGfloat f; + VGint i; +}; + +struct vg_state { + /* Mode settings */ + VGMatrixMode matrix_mode; + VGFillRule fill_rule; + VGImageQuality image_quality; + VGRenderingQuality rendering_quality; + VGBlendMode blend_mode; + VGImageMode image_mode; + + /* Scissoring rectangles */ + struct vg_value scissor_rects[32*4]; + VGint scissor_rects_num; + + /* Color Transformation */ + VGboolean color_transform; + VGfloat color_transform_values[8]; + + /* Stroke parameters */ + struct { + struct vg_value line_width; + VGCapStyle cap_style; + VGJoinStyle join_style; + struct vg_value miter_limit; + struct vg_value dash_pattern[VEGA_MAX_DASH_COUNT]; + VGint dash_pattern_num; + struct vg_value dash_phase; + VGboolean dash_phase_reset; + } stroke; + + /* Edge fill color for VG_TILE_FILL tiling mode */ + VGfloat tile_fill_color[4]; + VGint tile_fill_colori[4]; + + /* Color for vgClear */ + VGfloat clear_color[4]; + VGint clear_colori[4]; + + /* Glyph origin */ + struct vg_value glyph_origin[2]; + + /* Enable/disable alpha masking and scissoring */ + VGboolean masking; + VGboolean scissoring; + + /* Pixel layout information */ + VGPixelLayout pixel_layout; + VGPixelLayout screen_layout; + + /* Source format selection for image filters */ + VGboolean filter_format_linear; + VGboolean filter_format_premultiplied; + + /* Destination write enable mask for image filters */ + VGbitfield filter_channel_mask; + + struct matrix path_user_to_surface_matrix; + struct matrix image_user_to_surface_matrix; + struct matrix fill_paint_to_user_matrix; + struct matrix stroke_paint_to_user_matrix; + struct matrix glyph_user_to_surface_matrix; + + struct vg_paint *stroke_paint; + struct vg_paint *fill_paint; +}; + +void vg_init_state(struct vg_state *state); +struct matrix * vg_state_matrix(struct vg_state *state); + +#endif diff --git a/src/gallium/state_trackers/vega/vg_tracker.c b/src/gallium/state_trackers/vega/vg_tracker.c new file mode 100644 index 0000000000..56cc60aebe --- /dev/null +++ b/src/gallium/state_trackers/vega/vg_tracker.c @@ -0,0 +1,416 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "vg_context.h" +#include "vg_tracker.h" +#include "mask.h" + +#include "pipe/p_context.h" +#include "pipe/p_inlines.h" +#include "pipe/p_screen.h" +#include "util/u_memory.h" +#include "util/u_math.h" + +static struct pipe_texture * +create_texture(struct pipe_context *pipe, enum pipe_format format, + VGint width, VGint height) +{ + struct pipe_texture templ; + + memset(&templ, 0, sizeof(templ)); + + if (format != PIPE_FORMAT_NONE) { + templ.format = format; + } + else { + templ.format = PIPE_FORMAT_A8R8G8B8_UNORM; + } + + templ.target = PIPE_TEXTURE_2D; + pf_get_block(templ.format, &templ.block); + templ.width[0] = width; + templ.height[0] = height; + templ.depth[0] = 1; + templ.last_level = 0; + + if (pf_get_component_bits(format, PIPE_FORMAT_COMP_S)) { + templ.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL; + } else { + templ.tex_usage = (PIPE_TEXTURE_USAGE_DISPLAY_TARGET | + PIPE_TEXTURE_USAGE_RENDER_TARGET | + PIPE_TEXTURE_USAGE_SAMPLER); + } + + return pipe->screen->texture_create(pipe->screen, &templ); +} + +/** + * Allocate a renderbuffer for a an on-screen window (not a user-created + * renderbuffer). The window system code determines the format. + */ +static struct st_renderbuffer * +st_new_renderbuffer_fb(enum pipe_format format) +{ + struct st_renderbuffer *strb; + + strb = CALLOC_STRUCT(st_renderbuffer); + if (!strb) { + /*_vega_error(NULL, VG_OUT_OF_MEMORY, "creating renderbuffer");*/ + return NULL; + } + + strb->format = format; + + return strb; +} + + +/** + * This is called to allocate the original drawing surface, and + * during window resize. + */ +static VGboolean +st_renderbuffer_alloc_storage(struct vg_context * ctx, + struct st_renderbuffer *strb, + VGuint width, VGuint height) +{ + struct pipe_context *pipe = ctx->pipe; + unsigned surface_usage; + + /* Free the old surface and texture + */ + pipe_surface_reference(&strb->surface, NULL); + pipe_texture_reference(&strb->texture, NULL); + + + /* Probably need dedicated flags for surface usage too: + */ + surface_usage = (PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE); + + strb->texture = create_texture(pipe, strb->format, + width, height); + + if (!strb->texture) + return FALSE; + + strb->surface = pipe->screen->get_tex_surface(pipe->screen, + strb->texture, + 0, 0, 0, + surface_usage); + strb->width = width; + strb->height = height; + + assert(strb->surface->width == width); + assert(strb->surface->height == height); + + return strb->surface != NULL; +} + +struct vg_context * st_create_context(struct pipe_context *pipe, + const void *visual, + struct vg_context *share) +{ + struct vg_context *ctx = vg_create_context(pipe, visual, share); + /*debug_printf("--------- CREATE CONTEXT %p\n", ctx);*/ + return ctx; +} + +void st_destroy_context(struct vg_context *st) +{ + /*debug_printf("--------- DESTROY CONTEXT %p\n", st);*/ + vg_destroy_context(st); +} + +void st_copy_context_state(struct vg_context *dst, struct vg_context *src, + uint mask) +{ + fprintf(stderr, "FIXME: %s\n", __FUNCTION__); +} + +void st_get_framebuffer_dimensions(struct st_framebuffer *stfb, + uint *width, + uint *height) +{ + *width = stfb->strb->width; + *height = stfb->strb->height; +} + +struct st_framebuffer * st_create_framebuffer(const void *visual, + enum pipe_format colorFormat, + enum pipe_format depthFormat, + enum pipe_format stencilFormat, + uint width, uint height, + void *privateData) +{ + struct st_framebuffer *stfb = CALLOC_STRUCT(st_framebuffer); + if (stfb) { + struct st_renderbuffer *rb = + st_new_renderbuffer_fb(colorFormat); + stfb->strb = rb; +#if 0 + if (doubleBuffer) { + struct st_renderbuffer *rb = + st_new_renderbuffer_fb(colorFormat); + } +#endif + + /* we want to combine the depth/stencil */ + if (stencilFormat == depthFormat) + stfb->dsrb = st_new_renderbuffer_fb(stencilFormat); + else + stfb->dsrb = st_new_renderbuffer_fb(PIPE_FORMAT_S8Z24_UNORM); + + /*### currently we always allocate it but it's possible it's + not necessary if EGL_ALPHA_MASK_SIZE was 0 + */ + stfb->alpha_mask = 0; + + stfb->init_width = width; + stfb->init_height = height; + stfb->privateData = privateData; + } + + return stfb; +} + +static void setup_new_alpha_mask(struct vg_context *ctx, + struct st_framebuffer *stfb, + uint width, uint height) +{ + struct pipe_context *pipe = ctx->pipe; + struct pipe_texture *old_texture = stfb->alpha_mask; + + /* + we use PIPE_FORMAT_A8R8G8B8_UNORM because we want to render to + this texture and use it as a sampler, so while this wastes some + space it makes both of those a lot simpler + */ + stfb->alpha_mask = + create_texture(pipe, PIPE_FORMAT_A8R8G8B8_UNORM, width, height); + + if (!stfb->alpha_mask) { + if (old_texture) + pipe_texture_reference(&old_texture, NULL); + return; + } + + vg_validate_state(ctx); + + /* alpha mask starts with 1.f alpha */ + mask_fill(0, 0, width, height, 1.f); + + /* if we had an old surface copy it over */ + if (old_texture) { + struct pipe_surface *surface = pipe->screen->get_tex_surface( + pipe->screen, + stfb->alpha_mask, + 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + struct pipe_surface *old_surface = pipe->screen->get_tex_surface( + pipe->screen, + old_texture, + 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_READ); + pipe->surface_copy(pipe, + surface, + 0, 0, + old_surface, + 0, 0, + MIN2(old_surface->width, width), + MIN2(old_surface->height, height)); + if (surface) + pipe_surface_reference(&surface, NULL); + if (old_surface) + pipe_surface_reference(&old_surface, NULL); + } + + /* Free the old texture + */ + if (old_texture) + pipe_texture_reference(&old_texture, NULL); +} + +void st_resize_framebuffer(struct st_framebuffer *stfb, + uint width, uint height) +{ + struct vg_context *ctx = vg_current_context(); + struct st_renderbuffer *strb = stfb->strb; + struct pipe_framebuffer_state *state; + + if (!ctx) + return; + + state = &ctx->state.g3d.fb; + + /* If this is a noop, exit early and don't do the clear, etc below. + */ + if (strb->width == width && + strb->height == height && + state->zsbuf) + return; + + if (strb->width != width || strb->height != height) + st_renderbuffer_alloc_storage(ctx, strb, + width, height); + + if (stfb->dsrb->width != width || stfb->dsrb->height != height) + st_renderbuffer_alloc_storage(ctx, stfb->dsrb, + width, height); + + { + VGuint i; + + memset(state, 0, sizeof(struct pipe_framebuffer_state)); + + state->width = width; + state->height = height; + + state->nr_cbufs = 1; + state->cbufs[0] = strb->surface; + for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) + state->cbufs[i] = 0; + + state->zsbuf = stfb->dsrb->surface; + + cso_set_framebuffer(ctx->cso_context, state); + } + + ctx->state.dirty |= VIEWPORT_DIRTY; + ctx->state.dirty |= DEPTH_STENCIL_DIRTY;/*to reset the scissors*/ + + ctx->pipe->clear(ctx->pipe, PIPE_CLEAR_DEPTHSTENCIL, + NULL, 0.0, 0); + + /* we need all the other state already set */ + + setup_new_alpha_mask(ctx, stfb, width, height); + + pipe_texture_reference( &stfb->blend_texture, NULL ); + stfb->blend_texture = create_texture(ctx->pipe, PIPE_FORMAT_A8R8G8B8_UNORM, + width, height); +} + +void st_set_framebuffer_surface(struct st_framebuffer *stfb, + uint surfIndex, struct pipe_surface *surf) +{ + struct st_renderbuffer *rb = stfb->strb; + + /* unreference existing surfaces */ + pipe_surface_reference( &rb->surface, NULL ); + pipe_texture_reference( &rb->texture, NULL ); + + /* reference new ones */ + pipe_surface_reference( &rb->surface, surf ); + pipe_texture_reference( &rb->texture, surf->texture ); + + rb->width = surf->width; + rb->height = surf->height; +} + +int st_get_framebuffer_surface(struct st_framebuffer *stfb, + uint surfIndex, struct pipe_surface **surf) +{ + struct st_renderbuffer *rb = stfb->strb; + *surf = rb->surface; + return VG_TRUE; +} + +int st_get_framebuffer_texture(struct st_framebuffer *stfb, + uint surfIndex, struct pipe_texture **tex) +{ + struct st_renderbuffer *rb = stfb->strb; + *tex = rb->texture; + return VG_TRUE; +} + +void * st_framebuffer_private(struct st_framebuffer *stfb) +{ + return stfb->privateData; +} + +void st_unreference_framebuffer(struct st_framebuffer *stfb) +{ + /* FIXME */ +} + +void st_make_current(struct vg_context *st, + struct st_framebuffer *draw, + struct st_framebuffer *read) +{ + vg_set_current_context(st); + if (st) { + st->draw_buffer = draw; + } +} + +struct vg_context *st_get_current(void) +{ + return vg_current_context(); +} + +void st_flush(struct vg_context *st, uint pipeFlushFlags, + struct pipe_fence_handle **fence) +{ + st->pipe->flush(st->pipe, pipeFlushFlags, fence); +} + +void st_finish(struct vg_context *st) +{ + struct pipe_fence_handle *fence = NULL; + + st_flush(st, PIPE_FLUSH_RENDER_CACHE, &fence); + + st->pipe->screen->fence_finish(st->pipe->screen, fence, 0); + st->pipe->screen->fence_reference(st->pipe->screen, &fence, NULL); +} + +void st_notify_swapbuffers(struct st_framebuffer *stfb) +{ + struct vg_context *ctx = vg_current_context(); + if (ctx && ctx->draw_buffer == stfb) { + st_flush(ctx, + PIPE_FLUSH_RENDER_CACHE | + PIPE_FLUSH_SWAPBUFFERS | + PIPE_FLUSH_FRAME, + NULL); + } +} + +void st_notify_swapbuffers_complete(struct st_framebuffer *stfb) +{ +} + +int st_bind_texture_surface(struct pipe_surface *ps, int target, int level, + enum pipe_format format) +{ + return 0; +} + +int st_unbind_texture_surface(struct pipe_surface *ps, int target, int level) +{ + return 0; +} diff --git a/src/gallium/state_trackers/vega/vg_tracker.h b/src/gallium/state_trackers/vega/vg_tracker.h new file mode 100644 index 0000000000..5457631106 --- /dev/null +++ b/src/gallium/state_trackers/vega/vg_tracker.h @@ -0,0 +1,107 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef VG_TRACKER_H +#define VG_TRACKER_H + +#include "VG/openvg.h" + +#include "pipe/p_compiler.h" +#include "pipe/p_format.h" + +#define ST_SURFACE_FRONT_LEFT 0 +#define ST_SURFACE_BACK_LEFT 1 +#define ST_SURFACE_FRONT_RIGHT 2 +#define ST_SURFACE_BACK_RIGHT 3 +#define ST_SURFACE_DEPTH 8 + +struct vg_context; +struct st_framebuffer; +struct pipe_context; +struct pipe_fence_handle; +struct pipe_surface; + + +struct vg_context *st_create_context(struct pipe_context *pipe, + const void *visual, + struct vg_context *share); + +void st_destroy_context( struct vg_context *st ); + +void st_copy_context_state(struct vg_context *dst, struct vg_context *src, + uint mask); + +struct st_framebuffer *st_create_framebuffer(const void *visual, + enum pipe_format colorFormat, + enum pipe_format depthFormat, + enum pipe_format stencilFormat, + uint width, uint height, + void *privateData); + +void st_resize_framebuffer(struct st_framebuffer *stfb, + uint width, uint height); + +void st_set_framebuffer_surface(struct st_framebuffer *stfb, + uint surfIndex, struct pipe_surface *surf); + +void st_get_framebuffer_dimensions( struct st_framebuffer *stfb, + uint *width, uint *height); + +int st_bind_texture_surface(struct pipe_surface *ps, int target, int level, + enum pipe_format format); + +int st_unbind_texture_surface(struct pipe_surface *ps, int target, int level); + +int st_get_framebuffer_surface(struct st_framebuffer *stfb, + uint surfIndex, struct pipe_surface **surf); + +int st_get_framebuffer_texture(struct st_framebuffer *stfb, + uint surfIndex, struct pipe_texture **tex); + +void *st_framebuffer_private(struct st_framebuffer *stfb); + +void st_unreference_framebuffer(struct st_framebuffer *stfb); + +void st_make_current(struct vg_context *st, + struct st_framebuffer *draw, + struct st_framebuffer *read); + +struct vg_context *st_get_current(void); + +void st_flush(struct vg_context *st, uint pipeFlushFlags, + struct pipe_fence_handle **fence); +void st_finish(struct vg_context *st); + +void st_notify_swapbuffers(struct st_framebuffer *stfb); +void st_notify_swapbuffers_complete(struct st_framebuffer *stfb); + + +/** Generic function type */ +typedef void (*st_proc)(); + +st_proc st_get_proc_address(const char *procname); + +#endif diff --git a/src/gallium/state_trackers/vega/vg_translate.c b/src/gallium/state_trackers/vega/vg_translate.c new file mode 100644 index 0000000000..00e0764706 --- /dev/null +++ b/src/gallium/state_trackers/vega/vg_translate.c @@ -0,0 +1,1030 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "vg_translate.h" + +#include "pipe/p_format.h" +#include "util/u_pack_color.h" + +void _vega_pack_rgba_span_float(struct vg_context *ctx, + VGuint n, VGfloat rgba[][4], + VGImageFormat dstFormat, + void *dstAddr) +{ + VGint i; + + switch (dstFormat) { + case VG_sRGBX_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = 255; + dst[i] = r << 24 | g << 16 | b << 8 | a; + } + return; + } + break; + case VG_sRGBA_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = r << 24 | g << 16 | b << 8 | a; + } + return; + } + break; + case VG_sRGBA_8888_PRE: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = r << 24 | g << 16 | b << 8 | a; + } + return; + } + break; + case VG_sRGB_565: { + VGshort *dst = (VGshort *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + r = (r / 255.0) * 32; + g = (g / 255.0) * 32; + b = (b / 255.0) * 32; + + dst[i] = b | g << 5 | r << 11; + } + return; + } + break; + case VG_sRGBA_5551: { + VGshort *dst = (VGshort *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b, a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + r = (r / 255.0) * 32; + g = (g / 255.0) * 32; + b = (b / 255.0) * 32; + a = (a / 255.0); + + dst[i] = a | b << 1 | g << 6 | r << 11; + } + return; + } + break; + case VG_sRGBA_4444: { + VGshort *dst = (VGshort *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b, a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + r = (r / 255.0) * 16; + g = (g / 255.0) * 16; + b = (b / 255.0) * 16; + a = (a / 255.0) * 16; + + dst[i] = a | b << 4 | g << 8 | r << 12; + } + return; + } + break; + case VG_sL_8: { + VGubyte *dst = (VGubyte *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b, a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + + dst[i] = a; + } + return; + } + break; + case VG_lRGBX_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = 255; + dst[i] = r << 24 | g << 16 | b << 8 | a; + } + return; + } + break; + case VG_lRGBA_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = r << 24 | g << 16 | b << 8 | a; + } + return; + } + case VG_lRGBA_8888_PRE: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = r << 24 | g << 16 | b << 8 | a; + } + return; + } + break; + case VG_lL_8: { + VGubyte *dst = (VGubyte *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = a; + } + return; + } + break; + case VG_A_8: { + VGubyte *dst = (VGubyte *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b, a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + + dst[i] = a; + } + return; + } + break; + case VG_BW_1: { + VGshort *dst = (VGshort *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b, a; + VGubyte res; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + + res = (r + g + b + a)/4; + dst[i] = (res & (128)); + } + return; + } + break; +#ifdef OPENVG_VERSION_1_1 + case VG_A_1: { + VGshort *dst = (VGshort *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b, a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + + dst[i] = (a & (128)); + } + return; + } + break; + case VG_A_4: { + VGshort *dst = (VGshort *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b, a; + VGubyte res; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + + res = a/4; + dst[i] = (res & (128)); + } + return; + } + break; +#endif + case VG_sXRGB_8888: + break; + case VG_sARGB_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = a << 24 | r << 16 | g << 8 | b; + } + return; + } + break; + case VG_sARGB_8888_PRE: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = a << 24 | r << 16 | g << 8 | b; + } + return; + } + break; + case VG_sARGB_1555: + break; + case VG_sARGB_4444: + break; + case VG_lXRGB_8888: + break; + case VG_lARGB_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = a << 24 | r << 16 | g << 8 | b; + } + return; + } + break; + case VG_lARGB_8888_PRE: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = a << 24 | r << 16 | g << 8 | b; + } + return; + } + break; + case VG_sBGRX_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = 0xff; + dst[i] = b << 24 | g << 16 | r << 8 | a; + } + return; + } + break; + case VG_sBGRA_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = b << 24 | g << 16 | r << 8 | a; + } + return; + } + break; + case VG_sBGRA_8888_PRE: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = b << 24 | g << 16 | r << 8 | a; + } + return; + } + break; + case VG_sBGR_565: + break; + case VG_sBGRA_5551: + break; + case VG_sBGRA_4444: + break; + case VG_lBGRX_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = 0xff; + dst[i] = b << 24 | g << 16 | r << 8 | a; + } + return; + } + break; + case VG_lBGRA_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = b << 24 | g << 16 | r << 8 | a; + } + return; + } + break; + case VG_lBGRA_8888_PRE: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = b << 24 | g << 16 | r << 8 | a; + } + return; + } + break; + case VG_sXBGR_8888: + break; + case VG_sABGR_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = a << 24 | b << 16 | g << 8 | r; + } + return; + } + break; + case VG_sABGR_8888_PRE: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = a << 24 | b << 16 | g << 8 | r; + } + return; + } + break; + case VG_sABGR_1555: + break; + case VG_sABGR_4444: + break; + case VG_lXBGR_8888: + break; + case VG_lABGR_8888: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = a << 24 | b << 16 | g << 8 | r; + } + return; + } + break; + case VG_lABGR_8888_PRE: { + VGint *dst = (VGint *)dstAddr; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = float_to_ubyte(rgba[i][0]); + g = float_to_ubyte(rgba[i][1]); + b = float_to_ubyte(rgba[i][2]); + a = float_to_ubyte(rgba[i][3]); + dst[i] = a << 24 | b << 16 | g << 8 | r; + } + return; + } + break; + default: + assert(!"Unknown ReadPixels format"); + break; + } + assert(!"Not implemented ReadPixels format"); +} + +void _vega_unpack_float_span_rgba(struct vg_context *ctx, + VGuint n, + VGuint offset, + const void * data, + VGImageFormat dataFormat, + VGfloat rgba[][4]) +{ + VGint i; + + switch (dataFormat) { + case VG_sRGBX_8888: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = (*src >> 24) & 0xff; + g = (*src >> 16) & 0xff; + b = (*src >> 8) & 0xff; + a = 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + } + return; + case VG_sRGBA_8888: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = (*src >> 24) & 0xff; + g = (*src >> 16) & 0xff; + b = (*src >> 8) & 0xff; + a = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_sRGBA_8888_PRE: { + VGint *src = (VGint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = (*src >> 24) & 0xff; + g = (*src >> 16) & 0xff; + b = (*src >> 8) & 0xff; + a = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_sRGB_565: { + VGshort *src = (VGshort *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGfloat clr[4]; + clr[0] = ((*src >> 10) & 31)/31.; + clr[1] = ((*src >> 5) & 95)/95.; + clr[2] = ((*src >> 0) & 31)/31.; + clr[3] = 1.f; + + util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + } + return; + case VG_sRGBA_5551: { + VGshort *src = (VGshort *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGfloat clr[4]; + clr[0] = ((*src >> 10) & 31)/31.; + clr[1] = ((*src >> 5) & 31)/31.; + clr[2] = ((*src >> 1) & 31)/31.; + clr[3] = ((*src >> 0) & 1)/1.; + + util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + } + return; + case VG_sRGBA_4444: { + VGshort *src = (VGshort *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGfloat clr[4]; + clr[0] = ((*src >> 12) & 15)/15.; + clr[1] = ((*src >> 8) & 15)/15.; + clr[2] = ((*src >> 4) & 15)/15.; + clr[3] = ((*src >> 0) & 15)/15.; + + util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + } + return; + case VG_sL_8: { + VGubyte *src = (VGubyte *)data; + src += offset; + for (i = 0; i < n; ++i) { + util_pack_color_ub(0xff, 0xff, 0xff, *src, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + } + return; + case VG_lRGBX_8888: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = (*src >> 24) & 0xff; + g = (*src >> 16) & 0xff; + b = (*src >> 8) & 0xff; + a = 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + } + return; + case VG_lRGBA_8888: { + VGint *src = (VGint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = (*src >> 24) & 0xff; + g = (*src >> 16) & 0xff; + b = (*src >> 8) & 0xff; + a = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_lRGBA_8888_PRE: { + VGint *src = (VGint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + r = (*src >> 24) & 0xff; + g = (*src >> 16) & 0xff; + b = (*src >> 8) & 0xff; + a = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_lL_8: { + VGubyte *src = (VGubyte *)data; + src += offset; + for (i = 0; i < n; ++i) { + util_pack_color_ub(0xff, 0xff, 0xff, *src, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + } + return; + case VG_A_8: { + VGubyte *src = (VGubyte *)data; + src += offset; + for (i = 0; i < n; ++i) { + util_pack_color_ub(0xff, 0xff, 0xff, *src, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + } + return; + case VG_BW_1: { + VGubyte *src = (VGubyte *)data; + src += offset; + for (i = 0; i < n; i += 8) { + VGfloat clr[4]; + VGint j; + for (j = 0; j < 8 && j < n ; ++j) { + VGint shift = j; + clr[0] = (((*src) & (1<<shift)) >> shift); + clr[1] = clr[0]; + clr[2] = clr[0]; + clr[3] = 1.f; + + util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i+j]); + } + ++src; + } + } + return; +#ifdef OPENVG_VERSION_1_1 + case VG_A_1: { + VGubyte *src = (VGubyte *)data; + src += offset; + for (i = 0; i < n; i += 8) { + VGfloat clr[4]; + VGint j; + for (j = 0; j < 8 && j < n ; ++j) { + VGint shift = j; + clr[0] = 0.f; + clr[1] = 0.f; + clr[2] = 0.f; + clr[3] = (((*src) & (1<<shift)) >> shift); + + util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i+j]); + } + ++src; + } + } + return; + case VG_A_4: { + VGubyte *src = (VGubyte *)data; + src += offset/2; + for (i = 0; i < n; i += 2) { + VGfloat clr[4]; + VGint j; + for (j = 0; j < n && j < 2; ++j) { + VGint bitter, shift; + if (j == 0) { + bitter = 0x0f; + shift = 0; + } else { + bitter = 0xf0; + shift = 4; + } + clr[0] = 0.f; + clr[1] = 0.f; + clr[2] = 0.f; + clr[3] = ((*src) & (bitter)) >> shift; + + util_pack_color(clr, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i +j]); + } + ++src; + } + } + return; +#endif + case VG_sXRGB_8888: + break; + case VG_sARGB_8888: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + a = (*src >> 24) & 0xff; + r = (*src >> 16) & 0xff; + g = (*src >> 8) & 0xff; + b = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_sARGB_8888_PRE: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + a = (*src >> 24) & 0xff; + r = (*src >> 16) & 0xff; + g = (*src >> 8) & 0xff; + b = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_sARGB_1555: + break; + case VG_sARGB_4444: + break; + case VG_lXRGB_8888: + break; + case VG_lARGB_8888: { + VGint *src = (VGint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + a = (*src >> 24) & 0xff; + r = (*src >> 16) & 0xff; + g = (*src >> 8) & 0xff; + b = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_lARGB_8888_PRE: { + VGint *src = (VGint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + a = (*src >> 24) & 0xff; + r = (*src >> 16) & 0xff; + g = (*src >> 8) & 0xff; + b = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_sBGRX_8888: + break; + case VG_sBGRA_8888: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + b = (*src >> 24) & 0xff; + g = (*src >> 16) & 0xff; + r = (*src >> 8) & 0xff; + a = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_sBGRA_8888_PRE: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + b = (*src >> 24) & 0xff; + g = (*src >> 16) & 0xff; + r = (*src >> 8) & 0xff; + a = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_sBGR_565: + break; + case VG_sBGRA_5551: + break; + case VG_sBGRA_4444: + break; + case VG_lBGRX_8888: + break; + case VG_lBGRA_8888: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + b = (*src >> 24) & 0xff; + g = (*src >> 16) & 0xff; + r = (*src >> 8) & 0xff; + a = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_lBGRA_8888_PRE: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + b = (*src >> 24) & 0xff; + g = (*src >> 16) & 0xff; + r = (*src >> 8) & 0xff; + a = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_sXBGR_8888: + break; + case VG_sABGR_8888: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + a = (*src >> 24) & 0xff; + b = (*src >> 16) & 0xff; + g = (*src >> 8) & 0xff; + r = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_sABGR_8888_PRE: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + a = (*src >> 24) & 0xff; + b = (*src >> 16) & 0xff; + g = (*src >> 8) & 0xff; + r = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_sABGR_1555: + break; + case VG_sABGR_4444: + break; + case VG_lXBGR_8888: + break; + case VG_lABGR_8888: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + a = (*src >> 24) & 0xff; + b = (*src >> 16) & 0xff; + g = (*src >> 8) & 0xff; + r = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + case VG_lABGR_8888_PRE: { + VGuint *src = (VGuint *)data; + src += offset; + for (i = 0; i < n; ++i) { + VGubyte r, g, b ,a; + a = (*src >> 24) & 0xff; + b = (*src >> 16) & 0xff; + g = (*src >> 8) & 0xff; + r = (*src >> 0) & 0xff; + + util_pack_color_ub(r, g, b, a, PIPE_FORMAT_R32G32B32A32_FLOAT, + rgba[i]); + ++src; + } + return; + } + break; + default: + assert(!"Unknown ReadPixels format"); + break; + } + assert(!"Not implemented ReadPixels format"); +} + +VGint _vega_size_for_format(VGImageFormat dataFormat) +{ + switch (dataFormat) { + case VG_sRGBX_8888: + case VG_sRGBA_8888: + case VG_sRGBA_8888_PRE: + return 4; + case VG_sRGB_565: + case VG_sRGBA_5551: + case VG_sRGBA_4444: + return 2; + case VG_sL_8: + return 1; + case VG_lRGBX_8888: + case VG_lRGBA_8888: + case VG_lRGBA_8888_PRE: + return 4; + case VG_lL_8: + return 1; + case VG_A_8: + return 1; + case VG_BW_1: + return 1; +#ifdef OPENVG_VERSION_1_1 + case VG_A_1: + break; + case VG_A_4: + break; +#endif + case VG_sXRGB_8888: + case VG_sARGB_8888: + case VG_sARGB_8888_PRE: + return 4; + case VG_sARGB_1555: + case VG_sARGB_4444: + return 2; + case VG_lXRGB_8888: + case VG_lARGB_8888: + case VG_lARGB_8888_PRE: + case VG_sBGRX_8888: + case VG_sBGRA_8888: + case VG_sBGRA_8888_PRE: + return 4; + case VG_sBGR_565: + case VG_sBGRA_5551: + case VG_sBGRA_4444: + return 2; + case VG_lBGRX_8888: + case VG_lBGRA_8888: + case VG_lBGRA_8888_PRE: + case VG_sXBGR_8888: + case VG_sABGR_8888: + case VG_sABGR_8888_PRE: + return 4; + case VG_sABGR_1555: + case VG_sABGR_4444: + return 2; + case VG_lXBGR_8888: + case VG_lABGR_8888: + case VG_lABGR_8888_PRE: + return 4; + default: + assert(!"Unknown ReadPixels format"); + break; + } + assert(!"Not implemented ReadPixels format"); + return 0; +} diff --git a/src/gallium/state_trackers/vega/vg_translate.h b/src/gallium/state_trackers/vega/vg_translate.h new file mode 100644 index 0000000000..70815bacbc --- /dev/null +++ b/src/gallium/state_trackers/vega/vg_translate.h @@ -0,0 +1,49 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef VG_TRANSLATE_H +#define VG_TRANSLATE_H + +#include "VG/openvg.h" +#include "vg_context.h" + +/*FIXME: we really should be using translate module + * but pipe_format can't express some of the VG formats + * (the premultiplied ones) so currently it won't work */ + +void _vega_pack_rgba_span_float(struct vg_context *ctx, + VGuint n, VGfloat rgba[][4], + VGImageFormat dstFormat, + void *dstAddr); +void _vega_unpack_float_span_rgba(struct vg_context *ctx, + VGuint n, + VGuint offset, + const void * data, + VGImageFormat dataFormat, + VGfloat rgba[][4]); +VGint _vega_size_for_format(VGImageFormat format); + +#endif diff --git a/src/gallium/state_trackers/vega/vgu.c b/src/gallium/state_trackers/vega/vgu.c new file mode 100644 index 0000000000..7dc51c5599 --- /dev/null +++ b/src/gallium/state_trackers/vega/vgu.c @@ -0,0 +1,450 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "VG/openvg.h" +#include "VG/vgu.h" + +#include "matrix.h" +#include "path.h" + +#include "util/u_debug.h" +#include "util/u_pointer.h" + +#include <math.h> +#include <assert.h> + +static VGboolean is_aligned_to(const void *ptr, VGbyte alignment) +{ + void *aligned = align_pointer(ptr, alignment); + return (ptr == aligned) ? VG_TRUE : VG_FALSE; +} + +static VGboolean is_aligned(const void *ptr) +{ + return is_aligned_to(ptr, 4); +} + +static void vgu_append_float_coords(VGPath path, + const VGubyte *cmds, + VGint num_cmds, + const VGfloat *coords, + VGint num_coords) +{ + VGubyte common_data[40 * sizeof(VGfloat)]; + struct path *p = (struct path *)path; + + vg_float_to_datatype(path_datatype(p), common_data, coords, num_coords); + vgAppendPathData(path, num_cmds, cmds, common_data); +} + +VGUErrorCode vguLine(VGPath path, + VGfloat x0, VGfloat y0, + VGfloat x1, VGfloat y1) +{ + static const VGubyte cmds[] = {VG_MOVE_TO_ABS, VG_LINE_TO_ABS}; + VGfloat coords[4]; + VGbitfield caps; + + if (path == VG_INVALID_HANDLE) { + return VGU_BAD_HANDLE_ERROR; + } + caps = vgGetPathCapabilities(path); + if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) { + return VGU_PATH_CAPABILITY_ERROR; + } + + coords[0] = x0; + coords[1] = y0; + coords[2] = x1; + coords[3] = y1; + + vgu_append_float_coords(path, cmds, 2, coords, 4); + + return VGU_NO_ERROR; +} + +VGUErrorCode vguPolygon(VGPath path, + const VGfloat * points, + VGint count, + VGboolean closed) +{ + VGubyte *cmds; + VGfloat *coords; + VGbitfield caps; + VGint i; + + if (path == VG_INVALID_HANDLE) { + return VGU_BAD_HANDLE_ERROR; + } + + if (!points || count <= 0 || !is_aligned(points)) { + return VGU_ILLEGAL_ARGUMENT_ERROR; + } + + caps = vgGetPathCapabilities(path); + if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) { + return VGU_PATH_CAPABILITY_ERROR; + } + + cmds = malloc(sizeof(VGubyte) * count + 1); + coords = malloc(sizeof(VGfloat) * count * 2); + + cmds[0] = VG_MOVE_TO_ABS; + coords[0] = points[0]; + coords[1] = points[1]; + for (i = 1; i < count; ++i) { + cmds[i] = VG_LINE_TO_ABS; + coords[2*i + 0] = points[2*i + 0]; + coords[2*i + 1] = points[2*i + 1]; + } + + if (closed) { + cmds[i] = VG_CLOSE_PATH; + ++i; + } + + vgu_append_float_coords(path, cmds, i, coords, 2*i); + + free(cmds); + free(coords); + + return VGU_NO_ERROR; +} + +VGUErrorCode vguRect(VGPath path, + VGfloat x, VGfloat y, + VGfloat width, VGfloat height) +{ + static const VGubyte cmds[] = {VG_MOVE_TO_ABS, + VG_HLINE_TO_REL, + VG_VLINE_TO_REL, + VG_HLINE_TO_REL, + VG_CLOSE_PATH + }; + VGfloat coords[5]; + VGbitfield caps; + + if (path == VG_INVALID_HANDLE) { + return VGU_BAD_HANDLE_ERROR; + } + caps = vgGetPathCapabilities(path); + if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) { + return VGU_PATH_CAPABILITY_ERROR; + } + if (width <= 0 || height <= 0) { + return VGU_ILLEGAL_ARGUMENT_ERROR; + } + + coords[0] = x; + coords[1] = y; + coords[2] = width; + coords[3] = height; + coords[4] = -width; + + vgu_append_float_coords(path, cmds, 5, coords, 5); + + return VGU_NO_ERROR; +} + +VGUErrorCode vguRoundRect(VGPath path, + VGfloat x, VGfloat y, + VGfloat width, + VGfloat height, + VGfloat arcWidth, + VGfloat arcHeight) +{ + static const VGubyte cmds[] = {VG_MOVE_TO_ABS, + VG_HLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_VLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_HLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_VLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_CLOSE_PATH + }; + VGfloat c[26]; + VGbitfield caps; + + if (path == VG_INVALID_HANDLE) { + return VGU_BAD_HANDLE_ERROR; + } + caps = vgGetPathCapabilities(path); + if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) { + return VGU_PATH_CAPABILITY_ERROR; + } + if (width <= 0 || height <= 0) { + return VGU_ILLEGAL_ARGUMENT_ERROR; + } + + c[0] = x + arcWidth/2; c[1] = y; + + c[2] = width - arcWidth; + + c[3] = arcWidth/2; c[4] = arcHeight/2; c[5] = 0; + c[6] = arcWidth/2; c[7] = arcHeight/2; + + c[8] = height - arcHeight; + + c[9] = arcWidth/2; c[10] = arcHeight/2; c[11] = 0; + c[12] = -arcWidth/2; c[13] = arcHeight/2; + + c[14] = -(width - arcWidth); + + c[15] = arcWidth/2; c[16] = arcHeight/2; c[17] = 0; + c[18] = -arcWidth/2; c[19] = -arcHeight/2; + + c[20] = -(height - arcHeight); + + c[21] = arcWidth/2; c[22] = arcHeight/2; c[23] = 0; + c[24] = arcWidth/2; c[25] = -arcHeight/2; + + vgu_append_float_coords(path, cmds, 10, c, 26); + + return VGU_NO_ERROR; +} + +VGUErrorCode vguEllipse(VGPath path, + VGfloat cx, VGfloat cy, + VGfloat width, + VGfloat height) +{ + static const VGubyte cmds[] = {VG_MOVE_TO_ABS, + VG_SCCWARC_TO_REL, + VG_SCCWARC_TO_REL, + VG_CLOSE_PATH + }; + VGfloat coords[12]; + VGbitfield caps; + + if (path == VG_INVALID_HANDLE) { + return VGU_BAD_HANDLE_ERROR; + } + caps = vgGetPathCapabilities(path); + if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) { + return VGU_PATH_CAPABILITY_ERROR; + } + if (width <= 0 || height <= 0) { + return VGU_ILLEGAL_ARGUMENT_ERROR; + } + + coords[0] = cx + width/2; coords[1] = cy; + + coords[2] = width/2; coords[3] = height/2; coords[4] = 0; + coords[5] = -width; coords[6] = 0; + + coords[7] = width/2; coords[8] = height/2; coords[9] = 0; + coords[10] = width; coords[11] = 0; + + vgu_append_float_coords(path, cmds, 4, coords, 11); + + return VGU_NO_ERROR; +} + +VGUErrorCode vguArc(VGPath path, + VGfloat x, VGfloat y, + VGfloat width, VGfloat height, + VGfloat startAngle, + VGfloat angleExtent, + VGUArcType arcType) +{ + VGubyte cmds[11]; + VGfloat coords[40]; + VGbitfield caps; + VGfloat last = startAngle + angleExtent; + VGint i, c = 0; + + if (path == VG_INVALID_HANDLE) { + return VGU_BAD_HANDLE_ERROR; + } + caps = vgGetPathCapabilities(path); + if (!(caps & VG_PATH_CAPABILITY_APPEND_TO)) { + return VGU_PATH_CAPABILITY_ERROR; + } + if (width <= 0 || height <= 0) { + return VGU_ILLEGAL_ARGUMENT_ERROR; + } + if (arcType != VGU_ARC_OPEN && + arcType != VGU_ARC_CHORD && + arcType != VGU_ARC_PIE) { + return VGU_ILLEGAL_ARGUMENT_ERROR; + } + + cmds[c] = VG_MOVE_TO_ABS; ++c; + coords[0] = x+cos(DEGREES_TO_RADIANS(startAngle))*width/2; + coords[1] = y+sin(DEGREES_TO_RADIANS(startAngle))*height/2; +#ifdef DEBUG_VGUARC + debug_printf("start [%f, %f]\n", coords[0], coords[1]); +#endif + i = 2; + if (angleExtent > 0) { + VGfloat angle = startAngle + 180; + while (angle < last) { + cmds[c] = VG_SCCWARC_TO_ABS; ++c; + coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0; + coords[i+3] = x + cos(DEGREES_TO_RADIANS(angle))*width/2; + coords[i+4] = y + sin(DEGREES_TO_RADIANS(angle))*height/2; +#ifdef DEBUG_VGUARC + debug_printf("1 [%f, %f]\n", coords[i+3], + coords[i+4]); +#endif + i += 5; + angle += 180; + } + cmds[c] = VG_SCCWARC_TO_ABS; ++c; + coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0; + coords[i+3] = x+cos(DEGREES_TO_RADIANS(last))*width/2; + coords[i+4] = y+sin(DEGREES_TO_RADIANS(last))*height/2; +#ifdef DEBUG_VGUARC + debug_printf("2 [%f, %f]\n", coords[i+3], + coords[i+4]); +#endif + i += 5; + } else { + VGfloat angle = startAngle - 180; + while (angle > last) { + cmds[c] = VG_SCWARC_TO_ABS; ++c; + coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0; + coords[i+3] = x + cos(DEGREES_TO_RADIANS(angle)) * width/2; + coords[i+4] = y + sin(DEGREES_TO_RADIANS(angle)) * height/2; +#ifdef DEBUG_VGUARC + debug_printf("3 [%f, %f]\n", coords[i+3], + coords[i+4]); +#endif + angle -= 180; + i += 5; + } + cmds[c] = VG_SCWARC_TO_ABS; ++c; + coords[i] = width/2; coords[i+1] = height/2; coords[i+2] = 0; + coords[i+3] = x + cos(DEGREES_TO_RADIANS(last)) * width/2; + coords[i+4] = y + sin(DEGREES_TO_RADIANS(last)) * height/2; +#ifdef DEBUG_VGUARC + debug_printf("4 [%f, %f]\n", coords[i+3], + coords[i+4]); +#endif + i += 5; + } + + if (arcType == VGU_ARC_PIE) { + cmds[c] = VG_LINE_TO_ABS; ++c; + coords[i] = x; coords[i + 1] = y; + i += 2; + } + if (arcType == VGU_ARC_PIE || arcType == VGU_ARC_CHORD) { + cmds[c] = VG_CLOSE_PATH; + ++c; + } + + assert(c < 11); + + vgu_append_float_coords(path, cmds, c, coords, i); + + return VGU_NO_ERROR; +} + +VGUErrorCode vguComputeWarpQuadToSquare(VGfloat sx0, VGfloat sy0, + VGfloat sx1, VGfloat sy1, + VGfloat sx2, VGfloat sy2, + VGfloat sx3, VGfloat sy3, + VGfloat * matrix) +{ + struct matrix mat; + + if (!matrix || !is_aligned(matrix)) + return VGU_ILLEGAL_ARGUMENT_ERROR; + + if (!matrix_quad_to_square(sx0, sy0, + sx1, sy1, + sx2, sy2, + sx3, sy3, + &mat)) + return VGU_BAD_WARP_ERROR; + + if (!matrix_is_invertible(&mat)) + return VGU_BAD_WARP_ERROR; + + memcpy(matrix, mat.m, sizeof(VGfloat) * 9); + + return VGU_NO_ERROR; +} + +VGUErrorCode vguComputeWarpSquareToQuad(VGfloat dx0, VGfloat dy0, + VGfloat dx1, VGfloat dy1, + VGfloat dx2, VGfloat dy2, + VGfloat dx3, VGfloat dy3, + VGfloat * matrix) +{ + struct matrix mat; + + if (!matrix || !is_aligned(matrix)) + return VGU_ILLEGAL_ARGUMENT_ERROR; + + if (!matrix_square_to_quad(dx0, dy0, + dx1, dy1, + dx2, dy2, + dx3, dy3, + &mat)) + return VGU_BAD_WARP_ERROR; + + if (!matrix_is_invertible(&mat)) + return VGU_BAD_WARP_ERROR; + + memcpy(matrix, mat.m, sizeof(VGfloat) * 9); + + return VGU_NO_ERROR; +} + +VGUErrorCode vguComputeWarpQuadToQuad(VGfloat dx0, VGfloat dy0, + VGfloat dx1, VGfloat dy1, + VGfloat dx2, VGfloat dy2, + VGfloat dx3, VGfloat dy3, + VGfloat sx0, VGfloat sy0, + VGfloat sx1, VGfloat sy1, + VGfloat sx2, VGfloat sy2, + VGfloat sx3, VGfloat sy3, + VGfloat * matrix) +{ + struct matrix mat; + + if (!matrix || !is_aligned(matrix)) + return VGU_ILLEGAL_ARGUMENT_ERROR; + + if (!matrix_quad_to_quad(dx0, dy0, + dx1, dy1, + dx2, dy2, + dx3, dy3, + sx0, sy0, + sx1, sy1, + sx2, sy2, + sx3, sy3, + &mat)) + return VGU_BAD_WARP_ERROR; + + memcpy(matrix, mat.m, sizeof(VGfloat) * 9); + + return VGU_NO_ERROR; +} diff --git a/src/gallium/state_trackers/wgl/SConscript b/src/gallium/state_trackers/wgl/SConscript new file mode 100644 index 0000000000..69b88618ec --- /dev/null +++ b/src/gallium/state_trackers/wgl/SConscript @@ -0,0 +1,42 @@ +import os + +Import('*') + +if env['platform'] in ['windows']: + + env = env.Clone() + + env.Append(CPPPATH = [ + '#src/mesa', + '.', + ]) + + env.Append(CPPDEFINES = [ + '_GDI32_', # prevent wgl* being declared __declspec(dllimport) + 'BUILD_GL32', # declare gl* as __declspec(dllexport) in Mesa headers + 'WIN32_THREADS', # use Win32 thread API + ]) + + sources = [ + 'icd/stw_icd.c', + + 'wgl/stw_wgl.c', + + 'shared/stw_context.c', + 'shared/stw_device.c', + 'shared/stw_framebuffer.c', + 'shared/stw_pixelformat.c', + 'shared/stw_extensionsstring.c', + 'shared/stw_extswapinterval.c', + 'shared/stw_getprocaddress.c', + 'shared/stw_extgallium.c', + 'shared/stw_arbpixelformat.c', + 'shared/stw_tls.c', + ] + + wgl = env.ConvenienceLibrary( + target ='wgl', + source = sources, + ) + + Export('wgl') diff --git a/src/gallium/state_trackers/wgl/icd/stw_icd.c b/src/gallium/state_trackers/wgl/icd/stw_icd.c new file mode 100644 index 0000000000..347f40aa06 --- /dev/null +++ b/src/gallium/state_trackers/wgl/icd/stw_icd.c @@ -0,0 +1,617 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <windows.h> +#include <stdio.h> + +#include "GL/gl.h" + +#include "util/u_debug.h" +#include "pipe/p_thread.h" + +#include "shared/stw_public.h" +#include "icd/stw_icd.h" + +#define DBG 0 + + +BOOL APIENTRY +DrvCopyContext( + DHGLRC dhrcSource, + DHGLRC dhrcDest, + UINT fuMask ) +{ + return stw_copy_context(dhrcSource, dhrcDest, fuMask); +} + + +DHGLRC APIENTRY +DrvCreateLayerContext( + HDC hdc, + INT iLayerPlane ) +{ + DHGLRC r; + + r = stw_create_layer_context( hdc, iLayerPlane ); + + if (DBG) + debug_printf( "%s( %p, %i ) = %u\n", + __FUNCTION__, hdc, iLayerPlane, r ); + + return r; +} + +DHGLRC APIENTRY +DrvCreateContext( + HDC hdc ) +{ + return DrvCreateLayerContext( hdc, 0 ); +} + +BOOL APIENTRY +DrvDeleteContext( + DHGLRC dhglrc ) +{ + BOOL r; + + r = stw_delete_context( dhglrc ); + + if (DBG) + debug_printf( "%s( %u ) = %u\n", + __FUNCTION__, dhglrc, r ); + + return r; +} + +BOOL APIENTRY +DrvDescribeLayerPlane( + HDC hdc, + INT iPixelFormat, + INT iLayerPlane, + UINT nBytes, + LPLAYERPLANEDESCRIPTOR plpd ) +{ + if (DBG) + debug_printf( "%s\n", __FUNCTION__ ); + + return FALSE; +} + +LONG APIENTRY +DrvDescribePixelFormat( + HDC hdc, + INT iPixelFormat, + ULONG cjpfd, + PIXELFORMATDESCRIPTOR *ppfd ) +{ + LONG r; + + r = stw_pixelformat_describe( hdc, iPixelFormat, cjpfd, ppfd ); + + if (DBG) + debug_printf( "%s( %p, %d, %u, %p ) = %d\n", + __FUNCTION__, hdc, iPixelFormat, cjpfd, ppfd, r ); + + return r; +} + +int APIENTRY +DrvGetLayerPaletteEntries( + HDC hdc, + INT iLayerPlane, + INT iStart, + INT cEntries, + COLORREF *pcr ) +{ + if (DBG) + debug_printf( "%s\n", __FUNCTION__ ); + + return 0; +} + +PROC APIENTRY +DrvGetProcAddress( + LPCSTR lpszProc ) +{ + PROC r; + + r = stw_get_proc_address( lpszProc ); + + if (DBG) + debug_printf( "%s( \"%s\" ) = %p\n", __FUNCTION__, lpszProc, r ); + + return r; +} + +BOOL APIENTRY +DrvRealizeLayerPalette( + HDC hdc, + INT iLayerPlane, + BOOL bRealize ) +{ + if (DBG) + debug_printf( "%s\n", __FUNCTION__ ); + + return FALSE; +} + +BOOL APIENTRY +DrvReleaseContext( + DHGLRC dhglrc ) +{ + return stw_release_context(dhglrc); +} + +void APIENTRY +DrvSetCallbackProcs( + INT nProcs, + PROC *pProcs ) +{ + if (DBG) + debug_printf( "%s( %d, %p )\n", __FUNCTION__, nProcs, pProcs ); + + return; +} + + +/** + * Although WGL allows different dispatch entrypoints per context + */ +static const GLCLTPROCTABLE cpt = +{ + OPENGL_VERSION_110_ENTRIES, + { + &glNewList, + &glEndList, + &glCallList, + &glCallLists, + &glDeleteLists, + &glGenLists, + &glListBase, + &glBegin, + &glBitmap, + &glColor3b, + &glColor3bv, + &glColor3d, + &glColor3dv, + &glColor3f, + &glColor3fv, + &glColor3i, + &glColor3iv, + &glColor3s, + &glColor3sv, + &glColor3ub, + &glColor3ubv, + &glColor3ui, + &glColor3uiv, + &glColor3us, + &glColor3usv, + &glColor4b, + &glColor4bv, + &glColor4d, + &glColor4dv, + &glColor4f, + &glColor4fv, + &glColor4i, + &glColor4iv, + &glColor4s, + &glColor4sv, + &glColor4ub, + &glColor4ubv, + &glColor4ui, + &glColor4uiv, + &glColor4us, + &glColor4usv, + &glEdgeFlag, + &glEdgeFlagv, + &glEnd, + &glIndexd, + &glIndexdv, + &glIndexf, + &glIndexfv, + &glIndexi, + &glIndexiv, + &glIndexs, + &glIndexsv, + &glNormal3b, + &glNormal3bv, + &glNormal3d, + &glNormal3dv, + &glNormal3f, + &glNormal3fv, + &glNormal3i, + &glNormal3iv, + &glNormal3s, + &glNormal3sv, + &glRasterPos2d, + &glRasterPos2dv, + &glRasterPos2f, + &glRasterPos2fv, + &glRasterPos2i, + &glRasterPos2iv, + &glRasterPos2s, + &glRasterPos2sv, + &glRasterPos3d, + &glRasterPos3dv, + &glRasterPos3f, + &glRasterPos3fv, + &glRasterPos3i, + &glRasterPos3iv, + &glRasterPos3s, + &glRasterPos3sv, + &glRasterPos4d, + &glRasterPos4dv, + &glRasterPos4f, + &glRasterPos4fv, + &glRasterPos4i, + &glRasterPos4iv, + &glRasterPos4s, + &glRasterPos4sv, + &glRectd, + &glRectdv, + &glRectf, + &glRectfv, + &glRecti, + &glRectiv, + &glRects, + &glRectsv, + &glTexCoord1d, + &glTexCoord1dv, + &glTexCoord1f, + &glTexCoord1fv, + &glTexCoord1i, + &glTexCoord1iv, + &glTexCoord1s, + &glTexCoord1sv, + &glTexCoord2d, + &glTexCoord2dv, + &glTexCoord2f, + &glTexCoord2fv, + &glTexCoord2i, + &glTexCoord2iv, + &glTexCoord2s, + &glTexCoord2sv, + &glTexCoord3d, + &glTexCoord3dv, + &glTexCoord3f, + &glTexCoord3fv, + &glTexCoord3i, + &glTexCoord3iv, + &glTexCoord3s, + &glTexCoord3sv, + &glTexCoord4d, + &glTexCoord4dv, + &glTexCoord4f, + &glTexCoord4fv, + &glTexCoord4i, + &glTexCoord4iv, + &glTexCoord4s, + &glTexCoord4sv, + &glVertex2d, + &glVertex2dv, + &glVertex2f, + &glVertex2fv, + &glVertex2i, + &glVertex2iv, + &glVertex2s, + &glVertex2sv, + &glVertex3d, + &glVertex3dv, + &glVertex3f, + &glVertex3fv, + &glVertex3i, + &glVertex3iv, + &glVertex3s, + &glVertex3sv, + &glVertex4d, + &glVertex4dv, + &glVertex4f, + &glVertex4fv, + &glVertex4i, + &glVertex4iv, + &glVertex4s, + &glVertex4sv, + &glClipPlane, + &glColorMaterial, + &glCullFace, + &glFogf, + &glFogfv, + &glFogi, + &glFogiv, + &glFrontFace, + &glHint, + &glLightf, + &glLightfv, + &glLighti, + &glLightiv, + &glLightModelf, + &glLightModelfv, + &glLightModeli, + &glLightModeliv, + &glLineStipple, + &glLineWidth, + &glMaterialf, + &glMaterialfv, + &glMateriali, + &glMaterialiv, + &glPointSize, + &glPolygonMode, + &glPolygonStipple, + &glScissor, + &glShadeModel, + &glTexParameterf, + &glTexParameterfv, + &glTexParameteri, + &glTexParameteriv, + &glTexImage1D, + &glTexImage2D, + &glTexEnvf, + &glTexEnvfv, + &glTexEnvi, + &glTexEnviv, + &glTexGend, + &glTexGendv, + &glTexGenf, + &glTexGenfv, + &glTexGeni, + &glTexGeniv, + &glFeedbackBuffer, + &glSelectBuffer, + &glRenderMode, + &glInitNames, + &glLoadName, + &glPassThrough, + &glPopName, + &glPushName, + &glDrawBuffer, + &glClear, + &glClearAccum, + &glClearIndex, + &glClearColor, + &glClearStencil, + &glClearDepth, + &glStencilMask, + &glColorMask, + &glDepthMask, + &glIndexMask, + &glAccum, + &glDisable, + &glEnable, + &glFinish, + &glFlush, + &glPopAttrib, + &glPushAttrib, + &glMap1d, + &glMap1f, + &glMap2d, + &glMap2f, + &glMapGrid1d, + &glMapGrid1f, + &glMapGrid2d, + &glMapGrid2f, + &glEvalCoord1d, + &glEvalCoord1dv, + &glEvalCoord1f, + &glEvalCoord1fv, + &glEvalCoord2d, + &glEvalCoord2dv, + &glEvalCoord2f, + &glEvalCoord2fv, + &glEvalMesh1, + &glEvalPoint1, + &glEvalMesh2, + &glEvalPoint2, + &glAlphaFunc, + &glBlendFunc, + &glLogicOp, + &glStencilFunc, + &glStencilOp, + &glDepthFunc, + &glPixelZoom, + &glPixelTransferf, + &glPixelTransferi, + &glPixelStoref, + &glPixelStorei, + &glPixelMapfv, + &glPixelMapuiv, + &glPixelMapusv, + &glReadBuffer, + &glCopyPixels, + &glReadPixels, + &glDrawPixels, + &glGetBooleanv, + &glGetClipPlane, + &glGetDoublev, + &glGetError, + &glGetFloatv, + &glGetIntegerv, + &glGetLightfv, + &glGetLightiv, + &glGetMapdv, + &glGetMapfv, + &glGetMapiv, + &glGetMaterialfv, + &glGetMaterialiv, + &glGetPixelMapfv, + &glGetPixelMapuiv, + &glGetPixelMapusv, + &glGetPolygonStipple, + &glGetString, + &glGetTexEnvfv, + &glGetTexEnviv, + &glGetTexGendv, + &glGetTexGenfv, + &glGetTexGeniv, + &glGetTexImage, + &glGetTexParameterfv, + &glGetTexParameteriv, + &glGetTexLevelParameterfv, + &glGetTexLevelParameteriv, + &glIsEnabled, + &glIsList, + &glDepthRange, + &glFrustum, + &glLoadIdentity, + &glLoadMatrixf, + &glLoadMatrixd, + &glMatrixMode, + &glMultMatrixf, + &glMultMatrixd, + &glOrtho, + &glPopMatrix, + &glPushMatrix, + &glRotated, + &glRotatef, + &glScaled, + &glScalef, + &glTranslated, + &glTranslatef, + &glViewport, + &glArrayElement, + &glBindTexture, + &glColorPointer, + &glDisableClientState, + &glDrawArrays, + &glDrawElements, + &glEdgeFlagPointer, + &glEnableClientState, + &glIndexPointer, + &glIndexub, + &glIndexubv, + &glInterleavedArrays, + &glNormalPointer, + &glPolygonOffset, + &glTexCoordPointer, + &glVertexPointer, + &glAreTexturesResident, + &glCopyTexImage1D, + &glCopyTexImage2D, + &glCopyTexSubImage1D, + &glCopyTexSubImage2D, + &glDeleteTextures, + &glGenTextures, + &glGetPointerv, + &glIsTexture, + &glPrioritizeTextures, + &glTexSubImage1D, + &glTexSubImage2D, + &glPopClientAttrib, + &glPushClientAttrib + } +}; + + +PGLCLTPROCTABLE APIENTRY +DrvSetContext( + HDC hdc, + DHGLRC dhglrc, + PFN_SETPROCTABLE pfnSetProcTable ) +{ + PGLCLTPROCTABLE r = (PGLCLTPROCTABLE)&cpt; + + if (!stw_make_current( hdc, dhglrc )) + r = NULL; + + if (DBG) + debug_printf( "%s( 0x%p, %u, 0x%p ) = %p\n", + __FUNCTION__, hdc, dhglrc, pfnSetProcTable, r ); + + return r; +} + +int APIENTRY +DrvSetLayerPaletteEntries( + HDC hdc, + INT iLayerPlane, + INT iStart, + INT cEntries, + CONST COLORREF *pcr ) +{ + if (DBG) + debug_printf( "%s\n", __FUNCTION__ ); + + return 0; +} + +BOOL APIENTRY +DrvSetPixelFormat( + HDC hdc, + LONG iPixelFormat ) +{ + BOOL r; + + r = stw_pixelformat_set( hdc, iPixelFormat ); + + if (DBG) + debug_printf( "%s( %p, %d ) = %s\n", __FUNCTION__, hdc, iPixelFormat, r ? "TRUE" : "FALSE" ); + + return r; +} + +BOOL APIENTRY +DrvShareLists( + DHGLRC dhglrc1, + DHGLRC dhglrc2 ) +{ + if (DBG) + debug_printf( "%s\n", __FUNCTION__ ); + + return stw_share_lists(dhglrc1, dhglrc2); +} + +BOOL APIENTRY +DrvSwapBuffers( + HDC hdc ) +{ + if (DBG) + debug_printf( "%s( %p )\n", __FUNCTION__, hdc ); + + return stw_swap_buffers( hdc ); +} + +BOOL APIENTRY +DrvSwapLayerBuffers( + HDC hdc, + UINT fuPlanes ) +{ + if (DBG) + debug_printf( "%s\n", __FUNCTION__ ); + + return stw_swap_layer_buffers( hdc, fuPlanes ); +} + +BOOL APIENTRY +DrvValidateVersion( + ULONG ulVersion ) +{ + if (DBG) + debug_printf( "%s( %u )\n", __FUNCTION__, ulVersion ); + + /* TODO: get the expected version from the winsys */ + + return ulVersion == 1; +} diff --git a/src/gallium/state_trackers/wgl/icd/stw_icd.h b/src/gallium/state_trackers/wgl/icd/stw_icd.h new file mode 100644 index 0000000000..cbc1a66548 --- /dev/null +++ b/src/gallium/state_trackers/wgl/icd/stw_icd.h @@ -0,0 +1,489 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STW_ICD_H +#define STW_ICD_H + + +#include <windows.h> + +#include "GL/gl.h" + + +typedef ULONG DHGLRC; + +#define OPENGL_VERSION_110_ENTRIES 336 + +struct __GLdispatchTableRec +{ + void (GLAPIENTRY * NewList)(GLuint, GLenum); + void (GLAPIENTRY * EndList)(void); + void (GLAPIENTRY * CallList)(GLuint); + void (GLAPIENTRY * CallLists)(GLsizei, GLenum, const GLvoid *); + void (GLAPIENTRY * DeleteLists)(GLuint, GLsizei); + GLuint (GLAPIENTRY * GenLists)(GLsizei); + void (GLAPIENTRY * ListBase)(GLuint); + void (GLAPIENTRY * Begin)(GLenum); + void (GLAPIENTRY * Bitmap)(GLsizei, GLsizei, GLfloat, GLfloat, GLfloat, GLfloat, const GLubyte *); + void (GLAPIENTRY * Color3b)(GLbyte, GLbyte, GLbyte); + void (GLAPIENTRY * Color3bv)(const GLbyte *); + void (GLAPIENTRY * Color3d)(GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * Color3dv)(const GLdouble *); + void (GLAPIENTRY * Color3f)(GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * Color3fv)(const GLfloat *); + void (GLAPIENTRY * Color3i)(GLint, GLint, GLint); + void (GLAPIENTRY * Color3iv)(const GLint *); + void (GLAPIENTRY * Color3s)(GLshort, GLshort, GLshort); + void (GLAPIENTRY * Color3sv)(const GLshort *); + void (GLAPIENTRY * Color3ub)(GLubyte, GLubyte, GLubyte); + void (GLAPIENTRY * Color3ubv)(const GLubyte *); + void (GLAPIENTRY * Color3ui)(GLuint, GLuint, GLuint); + void (GLAPIENTRY * Color3uiv)(const GLuint *); + void (GLAPIENTRY * Color3us)(GLushort, GLushort, GLushort); + void (GLAPIENTRY * Color3usv)(const GLushort *); + void (GLAPIENTRY * Color4b)(GLbyte, GLbyte, GLbyte, GLbyte); + void (GLAPIENTRY * Color4bv)(const GLbyte *); + void (GLAPIENTRY * Color4d)(GLdouble, GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * Color4dv)(const GLdouble *); + void (GLAPIENTRY * Color4f)(GLfloat, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * Color4fv)(const GLfloat *); + void (GLAPIENTRY * Color4i)(GLint, GLint, GLint, GLint); + void (GLAPIENTRY * Color4iv)(const GLint *); + void (GLAPIENTRY * Color4s)(GLshort, GLshort, GLshort, GLshort); + void (GLAPIENTRY * Color4sv)(const GLshort *); + void (GLAPIENTRY * Color4ub)(GLubyte, GLubyte, GLubyte, GLubyte); + void (GLAPIENTRY * Color4ubv)(const GLubyte *); + void (GLAPIENTRY * Color4ui)(GLuint, GLuint, GLuint, GLuint); + void (GLAPIENTRY * Color4uiv)(const GLuint *); + void (GLAPIENTRY * Color4us)(GLushort, GLushort, GLushort, GLushort); + void (GLAPIENTRY * Color4usv)(const GLushort *); + void (GLAPIENTRY * EdgeFlag)(GLboolean); + void (GLAPIENTRY * EdgeFlagv)(const GLboolean *); + void (GLAPIENTRY * End)(void); + void (GLAPIENTRY * Indexd)(GLdouble); + void (GLAPIENTRY * Indexdv)(const GLdouble *); + void (GLAPIENTRY * Indexf)(GLfloat); + void (GLAPIENTRY * Indexfv)(const GLfloat *); + void (GLAPIENTRY * Indexi)(GLint); + void (GLAPIENTRY * Indexiv)(const GLint *); + void (GLAPIENTRY * Indexs)(GLshort); + void (GLAPIENTRY * Indexsv)(const GLshort *); + void (GLAPIENTRY * Normal3b)(GLbyte, GLbyte, GLbyte); + void (GLAPIENTRY * Normal3bv)(const GLbyte *); + void (GLAPIENTRY * Normal3d)(GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * Normal3dv)(const GLdouble *); + void (GLAPIENTRY * Normal3f)(GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * Normal3fv)(const GLfloat *); + void (GLAPIENTRY * Normal3i)(GLint, GLint, GLint); + void (GLAPIENTRY * Normal3iv)(const GLint *); + void (GLAPIENTRY * Normal3s)(GLshort, GLshort, GLshort); + void (GLAPIENTRY * Normal3sv)(const GLshort *); + void (GLAPIENTRY * RasterPos2d)(GLdouble, GLdouble); + void (GLAPIENTRY * RasterPos2dv)(const GLdouble *); + void (GLAPIENTRY * RasterPos2f)(GLfloat, GLfloat); + void (GLAPIENTRY * RasterPos2fv)(const GLfloat *); + void (GLAPIENTRY * RasterPos2i)(GLint, GLint); + void (GLAPIENTRY * RasterPos2iv)(const GLint *); + void (GLAPIENTRY * RasterPos2s)(GLshort, GLshort); + void (GLAPIENTRY * RasterPos2sv)(const GLshort *); + void (GLAPIENTRY * RasterPos3d)(GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * RasterPos3dv)(const GLdouble *); + void (GLAPIENTRY * RasterPos3f)(GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * RasterPos3fv)(const GLfloat *); + void (GLAPIENTRY * RasterPos3i)(GLint, GLint, GLint); + void (GLAPIENTRY * RasterPos3iv)(const GLint *); + void (GLAPIENTRY * RasterPos3s)(GLshort, GLshort, GLshort); + void (GLAPIENTRY * RasterPos3sv)(const GLshort *); + void (GLAPIENTRY * RasterPos4d)(GLdouble, GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * RasterPos4dv)(const GLdouble *); + void (GLAPIENTRY * RasterPos4f)(GLfloat, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * RasterPos4fv)(const GLfloat *); + void (GLAPIENTRY * RasterPos4i)(GLint, GLint, GLint, GLint); + void (GLAPIENTRY * RasterPos4iv)(const GLint *); + void (GLAPIENTRY * RasterPos4s)(GLshort, GLshort, GLshort, GLshort); + void (GLAPIENTRY * RasterPos4sv)(const GLshort *); + void (GLAPIENTRY * Rectd)(GLdouble, GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * Rectdv)(const GLdouble *, const GLdouble *); + void (GLAPIENTRY * Rectf)(GLfloat, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * Rectfv)(const GLfloat *, const GLfloat *); + void (GLAPIENTRY * Recti)(GLint, GLint, GLint, GLint); + void (GLAPIENTRY * Rectiv)(const GLint *, const GLint *); + void (GLAPIENTRY * Rects)(GLshort, GLshort, GLshort, GLshort); + void (GLAPIENTRY * Rectsv)(const GLshort *, const GLshort *); + void (GLAPIENTRY * TexCoord1d)(GLdouble); + void (GLAPIENTRY * TexCoord1dv)(const GLdouble *); + void (GLAPIENTRY * TexCoord1f)(GLfloat); + void (GLAPIENTRY * TexCoord1fv)(const GLfloat *); + void (GLAPIENTRY * TexCoord1i)(GLint); + void (GLAPIENTRY * TexCoord1iv)(const GLint *); + void (GLAPIENTRY * TexCoord1s)(GLshort); + void (GLAPIENTRY * TexCoord1sv)(const GLshort *); + void (GLAPIENTRY * TexCoord2d)(GLdouble, GLdouble); + void (GLAPIENTRY * TexCoord2dv)(const GLdouble *); + void (GLAPIENTRY * TexCoord2f)(GLfloat, GLfloat); + void (GLAPIENTRY * TexCoord2fv)(const GLfloat *); + void (GLAPIENTRY * TexCoord2i)(GLint, GLint); + void (GLAPIENTRY * TexCoord2iv)(const GLint *); + void (GLAPIENTRY * TexCoord2s)(GLshort, GLshort); + void (GLAPIENTRY * TexCoord2sv)(const GLshort *); + void (GLAPIENTRY * TexCoord3d)(GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * TexCoord3dv)(const GLdouble *); + void (GLAPIENTRY * TexCoord3f)(GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * TexCoord3fv)(const GLfloat *); + void (GLAPIENTRY * TexCoord3i)(GLint, GLint, GLint); + void (GLAPIENTRY * TexCoord3iv)(const GLint *); + void (GLAPIENTRY * TexCoord3s)(GLshort, GLshort, GLshort); + void (GLAPIENTRY * TexCoord3sv)(const GLshort *); + void (GLAPIENTRY * TexCoord4d)(GLdouble, GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * TexCoord4dv)(const GLdouble *); + void (GLAPIENTRY * TexCoord4f)(GLfloat, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * TexCoord4fv)(const GLfloat *); + void (GLAPIENTRY * TexCoord4i)(GLint, GLint, GLint, GLint); + void (GLAPIENTRY * TexCoord4iv)(const GLint *); + void (GLAPIENTRY * TexCoord4s)(GLshort, GLshort, GLshort, GLshort); + void (GLAPIENTRY * TexCoord4sv)(const GLshort *); + void (GLAPIENTRY * Vertex2d)(GLdouble, GLdouble); + void (GLAPIENTRY * Vertex2dv)(const GLdouble *); + void (GLAPIENTRY * Vertex2f)(GLfloat, GLfloat); + void (GLAPIENTRY * Vertex2fv)(const GLfloat *); + void (GLAPIENTRY * Vertex2i)(GLint, GLint); + void (GLAPIENTRY * Vertex2iv)(const GLint *); + void (GLAPIENTRY * Vertex2s)(GLshort, GLshort); + void (GLAPIENTRY * Vertex2sv)(const GLshort *); + void (GLAPIENTRY * Vertex3d)(GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * Vertex3dv)(const GLdouble *); + void (GLAPIENTRY * Vertex3f)(GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * Vertex3fv)(const GLfloat *); + void (GLAPIENTRY * Vertex3i)(GLint, GLint, GLint); + void (GLAPIENTRY * Vertex3iv)(const GLint *); + void (GLAPIENTRY * Vertex3s)(GLshort, GLshort, GLshort); + void (GLAPIENTRY * Vertex3sv)(const GLshort *); + void (GLAPIENTRY * Vertex4d)(GLdouble, GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * Vertex4dv)(const GLdouble *); + void (GLAPIENTRY * Vertex4f)(GLfloat, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * Vertex4fv)(const GLfloat *); + void (GLAPIENTRY * Vertex4i)(GLint, GLint, GLint, GLint); + void (GLAPIENTRY * Vertex4iv)(const GLint *); + void (GLAPIENTRY * Vertex4s)(GLshort, GLshort, GLshort, GLshort); + void (GLAPIENTRY * Vertex4sv)(const GLshort *); + void (GLAPIENTRY * ClipPlane)(GLenum, const GLdouble *); + void (GLAPIENTRY * ColorMaterial)(GLenum, GLenum); + void (GLAPIENTRY * CullFace)(GLenum); + void (GLAPIENTRY * Fogf)(GLenum, GLfloat); + void (GLAPIENTRY * Fogfv)(GLenum, const GLfloat *); + void (GLAPIENTRY * Fogi)(GLenum, GLint); + void (GLAPIENTRY * Fogiv)(GLenum, const GLint *); + void (GLAPIENTRY * FrontFace)(GLenum); + void (GLAPIENTRY * Hint)(GLenum, GLenum); + void (GLAPIENTRY * Lightf)(GLenum, GLenum, GLfloat); + void (GLAPIENTRY * Lightfv)(GLenum, GLenum, const GLfloat *); + void (GLAPIENTRY * Lighti)(GLenum, GLenum, GLint); + void (GLAPIENTRY * Lightiv)(GLenum, GLenum, const GLint *); + void (GLAPIENTRY * LightModelf)(GLenum, GLfloat); + void (GLAPIENTRY * LightModelfv)(GLenum, const GLfloat *); + void (GLAPIENTRY * LightModeli)(GLenum, GLint); + void (GLAPIENTRY * LightModeliv)(GLenum, const GLint *); + void (GLAPIENTRY * LineStipple)(GLint, GLushort); + void (GLAPIENTRY * LineWidth)(GLfloat); + void (GLAPIENTRY * Materialf)(GLenum, GLenum, GLfloat); + void (GLAPIENTRY * Materialfv)(GLenum, GLenum, const GLfloat *); + void (GLAPIENTRY * Materiali)(GLenum, GLenum, GLint); + void (GLAPIENTRY * Materialiv)(GLenum, GLenum, const GLint *); + void (GLAPIENTRY * PointSize)(GLfloat); + void (GLAPIENTRY * PolygonMode)(GLenum, GLenum); + void (GLAPIENTRY * PolygonStipple)(const GLubyte *); + void (GLAPIENTRY * Scissor)(GLint, GLint, GLsizei, GLsizei); + void (GLAPIENTRY * ShadeModel)(GLenum); + void (GLAPIENTRY * TexParameterf)(GLenum, GLenum, GLfloat); + void (GLAPIENTRY * TexParameterfv)(GLenum, GLenum, const GLfloat *); + void (GLAPIENTRY * TexParameteri)(GLenum, GLenum, GLint); + void (GLAPIENTRY * TexParameteriv)(GLenum, GLenum, const GLint *); + void (GLAPIENTRY * TexImage1D)(GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, const GLvoid *); + void (GLAPIENTRY * TexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *); + void (GLAPIENTRY * TexEnvf)(GLenum, GLenum, GLfloat); + void (GLAPIENTRY * TexEnvfv)(GLenum, GLenum, const GLfloat *); + void (GLAPIENTRY * TexEnvi)(GLenum, GLenum, GLint); + void (GLAPIENTRY * TexEnviv)(GLenum, GLenum, const GLint *); + void (GLAPIENTRY * TexGend)(GLenum, GLenum, GLdouble); + void (GLAPIENTRY * TexGendv)(GLenum, GLenum, const GLdouble *); + void (GLAPIENTRY * TexGenf)(GLenum, GLenum, GLfloat); + void (GLAPIENTRY * TexGenfv)(GLenum, GLenum, const GLfloat *); + void (GLAPIENTRY * TexGeni)(GLenum, GLenum, GLint); + void (GLAPIENTRY * TexGeniv)(GLenum, GLenum, const GLint *); + void (GLAPIENTRY * FeedbackBuffer)(GLsizei, GLenum, GLfloat *); + void (GLAPIENTRY * SelectBuffer)(GLsizei, GLuint *); + GLint (GLAPIENTRY * RenderMode)(GLenum); + void (GLAPIENTRY * InitNames)(void); + void (GLAPIENTRY * LoadName)(GLuint); + void (GLAPIENTRY * PassThrough)(GLfloat); + void (GLAPIENTRY * PopName)(void); + void (GLAPIENTRY * PushName)(GLuint); + void (GLAPIENTRY * DrawBuffer)(GLenum); + void (GLAPIENTRY * Clear)(GLbitfield); + void (GLAPIENTRY * ClearAccum)(GLfloat, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * ClearIndex)(GLfloat); + void (GLAPIENTRY * ClearColor)(GLclampf, GLclampf, GLclampf, GLclampf); + void (GLAPIENTRY * ClearStencil)(GLint); + void (GLAPIENTRY * ClearDepth)(GLclampd); + void (GLAPIENTRY * StencilMask)(GLuint); + void (GLAPIENTRY * ColorMask)(GLboolean, GLboolean, GLboolean, GLboolean); + void (GLAPIENTRY * DepthMask)(GLboolean); + void (GLAPIENTRY * IndexMask)(GLuint); + void (GLAPIENTRY * Accum)(GLenum, GLfloat); + void (GLAPIENTRY * Disable)(GLenum); + void (GLAPIENTRY * Enable)(GLenum); + void (GLAPIENTRY * Finish)(void); + void (GLAPIENTRY * Flush)(void); + void (GLAPIENTRY * PopAttrib)(void); + void (GLAPIENTRY * PushAttrib)(GLbitfield); + void (GLAPIENTRY * Map1d)(GLenum, GLdouble, GLdouble, GLint, GLint, const GLdouble *); + void (GLAPIENTRY * Map1f)(GLenum, GLfloat, GLfloat, GLint, GLint, const GLfloat *); + void (GLAPIENTRY * Map2d)(GLenum, GLdouble, GLdouble, GLint, GLint, GLdouble, GLdouble, GLint, GLint, const GLdouble *); + void (GLAPIENTRY * Map2f)(GLenum, GLfloat, GLfloat, GLint, GLint, GLfloat, GLfloat, GLint, GLint, const GLfloat *); + void (GLAPIENTRY * MapGrid1d)(GLint, GLdouble, GLdouble); + void (GLAPIENTRY * MapGrid1f)(GLint, GLfloat, GLfloat); + void (GLAPIENTRY * MapGrid2d)(GLint, GLdouble, GLdouble, GLint, GLdouble, GLdouble); + void (GLAPIENTRY * MapGrid2f)(GLint, GLfloat, GLfloat, GLint, GLfloat, GLfloat); + void (GLAPIENTRY * EvalCoord1d)(GLdouble); + void (GLAPIENTRY * EvalCoord1dv)(const GLdouble *); + void (GLAPIENTRY * EvalCoord1f)(GLfloat); + void (GLAPIENTRY * EvalCoord1fv)(const GLfloat *); + void (GLAPIENTRY * EvalCoord2d)(GLdouble, GLdouble); + void (GLAPIENTRY * EvalCoord2dv)(const GLdouble *); + void (GLAPIENTRY * EvalCoord2f)(GLfloat, GLfloat); + void (GLAPIENTRY * EvalCoord2fv)(const GLfloat *); + void (GLAPIENTRY * EvalMesh1)(GLenum, GLint, GLint); + void (GLAPIENTRY * EvalPoint1)(GLint); + void (GLAPIENTRY * EvalMesh2)(GLenum, GLint, GLint, GLint, GLint); + void (GLAPIENTRY * EvalPoint2)(GLint, GLint); + void (GLAPIENTRY * AlphaFunc)(GLenum, GLclampf); + void (GLAPIENTRY * BlendFunc)(GLenum, GLenum); + void (GLAPIENTRY * LogicOp)(GLenum); + void (GLAPIENTRY * StencilFunc)(GLenum, GLint, GLuint); + void (GLAPIENTRY * StencilOp)(GLenum, GLenum, GLenum); + void (GLAPIENTRY * DepthFunc)(GLenum); + void (GLAPIENTRY * PixelZoom)(GLfloat, GLfloat); + void (GLAPIENTRY * PixelTransferf)(GLenum, GLfloat); + void (GLAPIENTRY * PixelTransferi)(GLenum, GLint); + void (GLAPIENTRY * PixelStoref)(GLenum, GLfloat); + void (GLAPIENTRY * PixelStorei)(GLenum, GLint); + void (GLAPIENTRY * PixelMapfv)(GLenum, GLint, const GLfloat *); + void (GLAPIENTRY * PixelMapuiv)(GLenum, GLint, const GLuint *); + void (GLAPIENTRY * PixelMapusv)(GLenum, GLint, const GLushort *); + void (GLAPIENTRY * ReadBuffer)(GLenum); + void (GLAPIENTRY * CopyPixels)(GLint, GLint, GLsizei, GLsizei, GLenum); + void (GLAPIENTRY * ReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *); + void (GLAPIENTRY * DrawPixels)(GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); + void (GLAPIENTRY * GetBooleanv)(GLenum, GLboolean *); + void (GLAPIENTRY * GetClipPlane)(GLenum, GLdouble *); + void (GLAPIENTRY * GetDoublev)(GLenum, GLdouble *); + GLenum (GLAPIENTRY * GetError)(void); + void (GLAPIENTRY * GetFloatv)(GLenum, GLfloat *); + void (GLAPIENTRY * GetIntegerv)(GLenum, GLint *); + void (GLAPIENTRY * GetLightfv)(GLenum, GLenum, GLfloat *); + void (GLAPIENTRY * GetLightiv)(GLenum, GLenum, GLint *); + void (GLAPIENTRY * GetMapdv)(GLenum, GLenum, GLdouble *); + void (GLAPIENTRY * GetMapfv)(GLenum, GLenum, GLfloat *); + void (GLAPIENTRY * GetMapiv)(GLenum, GLenum, GLint *); + void (GLAPIENTRY * GetMaterialfv)(GLenum, GLenum, GLfloat *); + void (GLAPIENTRY * GetMaterialiv)(GLenum, GLenum, GLint *); + void (GLAPIENTRY * GetPixelMapfv)(GLenum, GLfloat *); + void (GLAPIENTRY * GetPixelMapuiv)(GLenum, GLuint *); + void (GLAPIENTRY * GetPixelMapusv)(GLenum, GLushort *); + void (GLAPIENTRY * GetPolygonStipple)(GLubyte *); + const GLubyte * (GLAPIENTRY * GetString)(GLenum); + void (GLAPIENTRY * GetTexEnvfv)(GLenum, GLenum, GLfloat *); + void (GLAPIENTRY * GetTexEnviv)(GLenum, GLenum, GLint *); + void (GLAPIENTRY * GetTexGendv)(GLenum, GLenum, GLdouble *); + void (GLAPIENTRY * GetTexGenfv)(GLenum, GLenum, GLfloat *); + void (GLAPIENTRY * GetTexGeniv)(GLenum, GLenum, GLint *); + void (GLAPIENTRY * GetTexImage)(GLenum, GLint, GLenum, GLenum, GLvoid *); + void (GLAPIENTRY * GetTexParameterfv)(GLenum, GLenum, GLfloat *); + void (GLAPIENTRY * GetTexParameteriv)(GLenum, GLenum, GLint *); + void (GLAPIENTRY * GetTexLevelParameterfv)(GLenum, GLint, GLenum, GLfloat *); + void (GLAPIENTRY * GetTexLevelParameteriv)(GLenum, GLint, GLenum, GLint *); + GLboolean (GLAPIENTRY * IsEnabled)(GLenum); + GLboolean (GLAPIENTRY * IsList)(GLuint); + void (GLAPIENTRY * DepthRange)(GLclampd, GLclampd); + void (GLAPIENTRY * Frustum)(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * LoadIdentity)(void); + void (GLAPIENTRY * LoadMatrixf)(const GLfloat *); + void (GLAPIENTRY * LoadMatrixd)(const GLdouble *); + void (GLAPIENTRY * MatrixMode)(GLenum); + void (GLAPIENTRY * MultMatrixf)(const GLfloat *); + void (GLAPIENTRY * MultMatrixd)(const GLdouble *); + void (GLAPIENTRY * Ortho)(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * PopMatrix)(void); + void (GLAPIENTRY * PushMatrix)(void); + void (GLAPIENTRY * Rotated)(GLdouble, GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * Rotatef)(GLfloat, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * Scaled)(GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * Scalef)(GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * Translated)(GLdouble, GLdouble, GLdouble); + void (GLAPIENTRY * Translatef)(GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY * Viewport)(GLint, GLint, GLsizei, GLsizei); + void (GLAPIENTRY * ArrayElement)(GLint); + void (GLAPIENTRY * BindTexture)(GLenum, GLuint); + void (GLAPIENTRY * ColorPointer)(GLint, GLenum, GLsizei, const GLvoid *); + void (GLAPIENTRY * DisableClientState)(GLenum); + void (GLAPIENTRY * DrawArrays)(GLenum, GLint, GLsizei); + void (GLAPIENTRY * DrawElements)(GLenum, GLsizei, GLenum, const GLvoid *); + void (GLAPIENTRY * EdgeFlagPointer)(GLsizei, const GLvoid *); + void (GLAPIENTRY * EnableClientState)(GLenum); + void (GLAPIENTRY * IndexPointer)(GLenum, GLsizei, const GLvoid *); + void (GLAPIENTRY * Indexub)(GLubyte); + void (GLAPIENTRY * Indexubv)(const GLubyte *); + void (GLAPIENTRY * InterleavedArrays)(GLenum, GLsizei, const GLvoid *); + void (GLAPIENTRY * NormalPointer)(GLenum, GLsizei, const GLvoid *); + void (GLAPIENTRY * PolygonOffset)(GLfloat, GLfloat); + void (GLAPIENTRY * TexCoordPointer)(GLint, GLenum, GLsizei, const GLvoid *); + void (GLAPIENTRY * VertexPointer)(GLint, GLenum, GLsizei, const GLvoid *); + GLboolean (GLAPIENTRY * AreTexturesResident)(GLsizei, const GLuint *, GLboolean *); + void (GLAPIENTRY * CopyTexImage1D)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint); + void (GLAPIENTRY * CopyTexImage2D)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint); + void (GLAPIENTRY * CopyTexSubImage1D)(GLenum, GLint, GLint, GLint, GLint, GLsizei); + void (GLAPIENTRY * CopyTexSubImage2D)(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); + void (GLAPIENTRY * DeleteTextures)(GLsizei, const GLuint *); + void (GLAPIENTRY * GenTextures)(GLsizei, GLuint *); + void (GLAPIENTRY * GetPointerv)(GLenum, GLvoid **); + GLboolean (GLAPIENTRY * IsTexture)(GLuint); + void (GLAPIENTRY * PrioritizeTextures)(GLsizei, const GLuint *, const GLclampf *); + void (GLAPIENTRY * TexSubImage1D)(GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const GLvoid *); + void (GLAPIENTRY * TexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); + void (GLAPIENTRY * PopClientAttrib)(void); + void (GLAPIENTRY * PushClientAttrib)(GLbitfield); +}; + +typedef struct __GLdispatchTableRec GLDISPATCHTABLE; + +typedef struct _GLCLTPROCTABLE +{ + int cEntries; + GLDISPATCHTABLE glDispatchTable; +} GLCLTPROCTABLE, * PGLCLTPROCTABLE; + +typedef VOID (APIENTRY * PFN_SETPROCTABLE)(PGLCLTPROCTABLE); + +BOOL APIENTRY +DrvCopyContext( + DHGLRC dhrcSource, + DHGLRC dhrcDest, + UINT fuMask ); + +DHGLRC APIENTRY +DrvCreateLayerContext( + HDC hdc, + INT iLayerPlane ); + +DHGLRC APIENTRY +DrvCreateContext( + HDC hdc ); + +BOOL APIENTRY +DrvDeleteContext( + DHGLRC dhglrc ); + +BOOL APIENTRY +DrvDescribeLayerPlane( + HDC hdc, + INT iPixelFormat, + INT iLayerPlane, + UINT nBytes, + LPLAYERPLANEDESCRIPTOR plpd ); + +LONG APIENTRY +DrvDescribePixelFormat( + HDC hdc, + INT iPixelFormat, + ULONG cjpfd, + PIXELFORMATDESCRIPTOR *ppfd ); + +int APIENTRY +DrvGetLayerPaletteEntries( + HDC hdc, + INT iLayerPlane, + INT iStart, + INT cEntries, + COLORREF *pcr ); + +PROC APIENTRY +DrvGetProcAddress( + LPCSTR lpszProc ); + +BOOL APIENTRY +DrvRealizeLayerPalette( + HDC hdc, + INT iLayerPlane, + BOOL bRealize ); + +BOOL APIENTRY +DrvReleaseContext( + DHGLRC dhglrc ); + +void APIENTRY +DrvSetCallbackProcs( + INT nProcs, + PROC *pProcs ); + +PGLCLTPROCTABLE APIENTRY +DrvSetContext( + HDC hdc, + DHGLRC dhglrc, + PFN_SETPROCTABLE pfnSetProcTable ); + +int APIENTRY +DrvSetLayerPaletteEntries( + HDC hdc, + INT iLayerPlane, + INT iStart, + INT cEntries, + CONST COLORREF *pcr ); + +BOOL APIENTRY +DrvSetPixelFormat( + HDC hdc, + LONG iPixelFormat ); + +BOOL APIENTRY +DrvShareLists( + DHGLRC dhglrc1, + DHGLRC dhglrc2 ); + +BOOL APIENTRY +DrvSwapBuffers( + HDC hdc ); + +BOOL APIENTRY +DrvSwapLayerBuffers( + HDC hdc, + UINT fuPlanes ); + +BOOL APIENTRY +DrvValidateVersion( + ULONG ulVersion ); + +#endif /* STW_ICD_H */ diff --git a/src/gallium/state_trackers/wgl/opengl32.def b/src/gallium/state_trackers/wgl/opengl32.def new file mode 100644 index 0000000000..596417ed84 --- /dev/null +++ b/src/gallium/state_trackers/wgl/opengl32.def @@ -0,0 +1,388 @@ +EXPORTS +; GlmfBeginGlsBlock +; GlmfCloseMetaFile +; GlmfEndGlsBlock +; GlmfEndPlayback +; GlmfInitPlayback +; GlmfPlayGlsRecord + glAccum + glAlphaFunc + glAreTexturesResident + glArrayElement + glBegin + glBindTexture + glBitmap + glBlendFunc + glCallList + glCallLists + glClear + glClearAccum + glClearColor + glClearDepth + glClearIndex + glClearStencil + glClipPlane + glColor3b + glColor3bv + glColor3d + glColor3dv + glColor3f + glColor3fv + glColor3i + glColor3iv + glColor3s + glColor3sv + glColor3ub + glColor3ubv + glColor3ui + glColor3uiv + glColor3us + glColor3usv + glColor4b + glColor4bv + glColor4d + glColor4dv + glColor4f + glColor4fv + glColor4i + glColor4iv + glColor4s + glColor4sv + glColor4ub + glColor4ubv + glColor4ui + glColor4uiv + glColor4us + glColor4usv + glColorMask + glColorMaterial + glColorPointer + glCopyPixels + glCopyTexImage1D + glCopyTexImage2D + glCopyTexSubImage1D + glCopyTexSubImage2D + glCullFace +; glDebugEntry + glDeleteLists + glDeleteTextures + glDepthFunc + glDepthMask + glDepthRange + glDisable + glDisableClientState + glDrawArrays + glDrawBuffer + glDrawElements + glDrawPixels + glEdgeFlag + glEdgeFlagPointer + glEdgeFlagv + glEnable + glEnableClientState + glEnd + glEndList + glEvalCoord1d + glEvalCoord1dv + glEvalCoord1f + glEvalCoord1fv + glEvalCoord2d + glEvalCoord2dv + glEvalCoord2f + glEvalCoord2fv + glEvalMesh1 + glEvalMesh2 + glEvalPoint1 + glEvalPoint2 + glFeedbackBuffer + glFinish + glFlush + glFogf + glFogfv + glFogi + glFogiv + glFrontFace + glFrustum + glGenLists + glGenTextures + glGetBooleanv + glGetClipPlane + glGetDoublev + glGetError + glGetFloatv + glGetIntegerv + glGetLightfv + glGetLightiv + glGetMapdv + glGetMapfv + glGetMapiv + glGetMaterialfv + glGetMaterialiv + glGetPixelMapfv + glGetPixelMapuiv + glGetPixelMapusv + glGetPointerv + glGetPolygonStipple + glGetString + glGetTexEnvfv + glGetTexEnviv + glGetTexGendv + glGetTexGenfv + glGetTexGeniv + glGetTexImage + glGetTexLevelParameterfv + glGetTexLevelParameteriv + glGetTexParameterfv + glGetTexParameteriv + glHint + glIndexMask + glIndexPointer + glIndexd + glIndexdv + glIndexf + glIndexfv + glIndexi + glIndexiv + glIndexs + glIndexsv + glIndexub + glIndexubv + glInitNames + glInterleavedArrays + glIsEnabled + glIsList + glIsTexture + glLightModelf + glLightModelfv + glLightModeli + glLightModeliv + glLightf + glLightfv + glLighti + glLightiv + glLineStipple + glLineWidth + glListBase + glLoadIdentity + glLoadMatrixd + glLoadMatrixf + glLoadName + glLogicOp + glMap1d + glMap1f + glMap2d + glMap2f + glMapGrid1d + glMapGrid1f + glMapGrid2d + glMapGrid2f + glMaterialf + glMaterialfv + glMateriali + glMaterialiv + glMatrixMode + glMultMatrixd + glMultMatrixf + glNewList + glNormal3b + glNormal3bv + glNormal3d + glNormal3dv + glNormal3f + glNormal3fv + glNormal3i + glNormal3iv + glNormal3s + glNormal3sv + glNormalPointer + glOrtho + glPassThrough + glPixelMapfv + glPixelMapuiv + glPixelMapusv + glPixelStoref + glPixelStorei + glPixelTransferf + glPixelTransferi + glPixelZoom + glPointSize + glPolygonMode + glPolygonOffset + glPolygonStipple + glPopAttrib + glPopClientAttrib + glPopMatrix + glPopName + glPrioritizeTextures + glPushAttrib + glPushClientAttrib + glPushMatrix + glPushName + glRasterPos2d + glRasterPos2dv + glRasterPos2f + glRasterPos2fv + glRasterPos2i + glRasterPos2iv + glRasterPos2s + glRasterPos2sv + glRasterPos3d + glRasterPos3dv + glRasterPos3f + glRasterPos3fv + glRasterPos3i + glRasterPos3iv + glRasterPos3s + glRasterPos3sv + glRasterPos4d + glRasterPos4dv + glRasterPos4f + glRasterPos4fv + glRasterPos4i + glRasterPos4iv + glRasterPos4s + glRasterPos4sv + glReadBuffer + glReadPixels + glRectd + glRectdv + glRectf + glRectfv + glRecti + glRectiv + glRects + glRectsv + glRenderMode + glRotated + glRotatef + glScaled + glScalef + glScissor + glSelectBuffer + glShadeModel + glStencilFunc + glStencilMask + glStencilOp + glTexCoord1d + glTexCoord1dv + glTexCoord1f + glTexCoord1fv + glTexCoord1i + glTexCoord1iv + glTexCoord1s + glTexCoord1sv + glTexCoord2d + glTexCoord2dv + glTexCoord2f + glTexCoord2fv + glTexCoord2i + glTexCoord2iv + glTexCoord2s + glTexCoord2sv + glTexCoord3d + glTexCoord3dv + glTexCoord3f + glTexCoord3fv + glTexCoord3i + glTexCoord3iv + glTexCoord3s + glTexCoord3sv + glTexCoord4d + glTexCoord4dv + glTexCoord4f + glTexCoord4fv + glTexCoord4i + glTexCoord4iv + glTexCoord4s + glTexCoord4sv + glTexCoordPointer + glTexEnvf + glTexEnvfv + glTexEnvi + glTexEnviv + glTexGend + glTexGendv + glTexGenf + glTexGenfv + glTexGeni + glTexGeniv + glTexImage1D + glTexImage2D + glTexParameterf + glTexParameterfv + glTexParameteri + glTexParameteriv + glTexSubImage1D + glTexSubImage2D + glTranslated + glTranslatef + glVertex2d + glVertex2dv + glVertex2f + glVertex2fv + glVertex2i + glVertex2iv + glVertex2s + glVertex2sv + glVertex3d + glVertex3dv + glVertex3f + glVertex3fv + glVertex3i + glVertex3iv + glVertex3s + glVertex3sv + glVertex4d + glVertex4dv + glVertex4f + glVertex4fv + glVertex4i + glVertex4iv + glVertex4s + glVertex4sv + glVertexPointer + glViewport + wglChoosePixelFormat + wglCopyContext + wglCreateContext + wglCreateLayerContext + wglDeleteContext + wglDescribeLayerPlane + wglDescribePixelFormat + wglGetCurrentContext + wglGetCurrentDC +; wglGetDefaultProcAddress + wglGetLayerPaletteEntries + wglGetPixelFormat + wglGetProcAddress + wglMakeCurrent + wglRealizeLayerPalette + wglSetLayerPaletteEntries + wglSetPixelFormat + wglShareLists + wglSwapBuffers + wglSwapLayerBuffers +; wglSwapMultipleBuffers + wglUseFontBitmapsA + wglUseFontBitmapsW + wglUseFontOutlinesA + wglUseFontOutlinesW + wglGetExtensionsStringARB + DrvCopyContext + DrvCreateContext + DrvCreateLayerContext + DrvDeleteContext + DrvDescribeLayerPlane + DrvDescribePixelFormat + DrvGetLayerPaletteEntries + DrvGetProcAddress + DrvRealizeLayerPalette + DrvReleaseContext + DrvSetCallbackProcs + DrvSetContext + DrvSetLayerPaletteEntries + DrvSetPixelFormat + DrvShareLists + DrvSwapBuffers + DrvSwapLayerBuffers + DrvValidateVersion diff --git a/src/gallium/state_trackers/wgl/opengl32.mingw.def b/src/gallium/state_trackers/wgl/opengl32.mingw.def new file mode 100644 index 0000000000..1f03ea3b37 --- /dev/null +++ b/src/gallium/state_trackers/wgl/opengl32.mingw.def @@ -0,0 +1,387 @@ +EXPORTS +; GlmfBeginGlsBlock = GlmfBeginGlsBlock@4 +; GlmfCloseMetaFile = GlmfCloseMetaFile@4 +; GlmfEndGlsBlock = GlmfEndGlsBlock@4 +; GlmfEndPlayback = GlmfEndPlayback@4 +; GlmfInitPlayback = GlmfInitPlayback@12 +; GlmfPlayGlsRecord = GlmfPlayGlsRecord@16 + glAccum = glAccum@8 + glAlphaFunc = glAlphaFunc@8 + glAreTexturesResident = glAreTexturesResident@12 + glArrayElement = glArrayElement@4 + glBegin = glBegin@4 + glBindTexture = glBindTexture@8 + glBitmap = glBitmap@28 + glBlendFunc = glBlendFunc@8 + glCallList = glCallList@4 + glCallLists = glCallLists@12 + glClear = glClear@4 + glClearAccum = glClearAccum@16 + glClearColor = glClearColor@16 + glClearDepth = glClearDepth@8 + glClearIndex = glClearIndex@4 + glClearStencil = glClearStencil@4 + glClipPlane = glClipPlane@8 + glColor3b = glColor3b@12 + glColor3bv = glColor3bv@4 + glColor3d = glColor3d@24 + glColor3dv = glColor3dv@4 + glColor3f = glColor3f@12 + glColor3fv = glColor3fv@4 + glColor3i = glColor3i@12 + glColor3iv = glColor3iv@4 + glColor3s = glColor3s@12 + glColor3sv = glColor3sv@4 + glColor3ub = glColor3ub@12 + glColor3ubv = glColor3ubv@4 + glColor3ui = glColor3ui@12 + glColor3uiv = glColor3uiv@4 + glColor3us = glColor3us@12 + glColor3usv = glColor3usv@4 + glColor4b = glColor4b@16 + glColor4bv = glColor4bv@4 + glColor4d = glColor4d@32 + glColor4dv = glColor4dv@4 + glColor4f = glColor4f@16 + glColor4fv = glColor4fv@4 + glColor4i = glColor4i@16 + glColor4iv = glColor4iv@4 + glColor4s = glColor4s@16 + glColor4sv = glColor4sv@4 + glColor4ub = glColor4ub@16 + glColor4ubv = glColor4ubv@4 + glColor4ui = glColor4ui@16 + glColor4uiv = glColor4uiv@4 + glColor4us = glColor4us@16 + glColor4usv = glColor4usv@4 + glColorMask = glColorMask@16 + glColorMaterial = glColorMaterial@8 + glColorPointer = glColorPointer@16 + glCopyPixels = glCopyPixels@20 + glCopyTexImage1D = glCopyTexImage1D@28 + glCopyTexImage2D = glCopyTexImage2D@32 + glCopyTexSubImage1D = glCopyTexSubImage1D@24 + glCopyTexSubImage2D = glCopyTexSubImage2D@32 + glCullFace = glCullFace@4 +; glDebugEntry = glDebugEntry@8 + glDeleteLists = glDeleteLists@8 + glDeleteTextures = glDeleteTextures@8 + glDepthFunc = glDepthFunc@4 + glDepthMask = glDepthMask@4 + glDepthRange = glDepthRange@16 + glDisable = glDisable@4 + glDisableClientState = glDisableClientState@4 + glDrawArrays = glDrawArrays@12 + glDrawBuffer = glDrawBuffer@4 + glDrawElements = glDrawElements@16 + glDrawPixels = glDrawPixels@20 + glEdgeFlag = glEdgeFlag@4 + glEdgeFlagPointer = glEdgeFlagPointer@8 + glEdgeFlagv = glEdgeFlagv@4 + glEnable = glEnable@4 + glEnableClientState = glEnableClientState@4 + glEnd = glEnd@0 + glEndList = glEndList@0 + glEvalCoord1d = glEvalCoord1d@8 + glEvalCoord1dv = glEvalCoord1dv@4 + glEvalCoord1f = glEvalCoord1f@4 + glEvalCoord1fv = glEvalCoord1fv@4 + glEvalCoord2d = glEvalCoord2d@16 + glEvalCoord2dv = glEvalCoord2dv@4 + glEvalCoord2f = glEvalCoord2f@8 + glEvalCoord2fv = glEvalCoord2fv@4 + glEvalMesh1 = glEvalMesh1@12 + glEvalMesh2 = glEvalMesh2@20 + glEvalPoint1 = glEvalPoint1@4 + glEvalPoint2 = glEvalPoint2@8 + glFeedbackBuffer = glFeedbackBuffer@12 + glFinish = glFinish@0 + glFlush = glFlush@0 + glFogf = glFogf@8 + glFogfv = glFogfv@8 + glFogi = glFogi@8 + glFogiv = glFogiv@8 + glFrontFace = glFrontFace@4 + glFrustum = glFrustum@48 + glGenLists = glGenLists@4 + glGenTextures = glGenTextures@8 + glGetBooleanv = glGetBooleanv@8 + glGetClipPlane = glGetClipPlane@8 + glGetDoublev = glGetDoublev@8 + glGetError = glGetError@0 + glGetFloatv = glGetFloatv@8 + glGetIntegerv = glGetIntegerv@8 + glGetLightfv = glGetLightfv@12 + glGetLightiv = glGetLightiv@12 + glGetMapdv = glGetMapdv@12 + glGetMapfv = glGetMapfv@12 + glGetMapiv = glGetMapiv@12 + glGetMaterialfv = glGetMaterialfv@12 + glGetMaterialiv = glGetMaterialiv@12 + glGetPixelMapfv = glGetPixelMapfv@8 + glGetPixelMapuiv = glGetPixelMapuiv@8 + glGetPixelMapusv = glGetPixelMapusv@8 + glGetPointerv = glGetPointerv@8 + glGetPolygonStipple = glGetPolygonStipple@4 + glGetString = glGetString@4 + glGetTexEnvfv = glGetTexEnvfv@12 + glGetTexEnviv = glGetTexEnviv@12 + glGetTexGendv = glGetTexGendv@12 + glGetTexGenfv = glGetTexGenfv@12 + glGetTexGeniv = glGetTexGeniv@12 + glGetTexImage = glGetTexImage@20 + glGetTexLevelParameterfv = glGetTexLevelParameterfv@16 + glGetTexLevelParameteriv = glGetTexLevelParameteriv@16 + glGetTexParameterfv = glGetTexParameterfv@12 + glGetTexParameteriv = glGetTexParameteriv@12 + glHint = glHint@8 + glIndexMask = glIndexMask@4 + glIndexPointer = glIndexPointer@12 + glIndexd = glIndexd@8 + glIndexdv = glIndexdv@4 + glIndexf = glIndexf@4 + glIndexfv = glIndexfv@4 + glIndexi = glIndexi@4 + glIndexiv = glIndexiv@4 + glIndexs = glIndexs@4 + glIndexsv = glIndexsv@4 + glIndexub = glIndexub@4 + glIndexubv = glIndexubv@4 + glInitNames = glInitNames@0 + glInterleavedArrays = glInterleavedArrays@12 + glIsEnabled = glIsEnabled@4 + glIsList = glIsList@4 + glIsTexture = glIsTexture@4 + glLightModelf = glLightModelf@8 + glLightModelfv = glLightModelfv@8 + glLightModeli = glLightModeli@8 + glLightModeliv = glLightModeliv@8 + glLightf = glLightf@12 + glLightfv = glLightfv@12 + glLighti = glLighti@12 + glLightiv = glLightiv@12 + glLineStipple = glLineStipple@8 + glLineWidth = glLineWidth@4 + glListBase = glListBase@4 + glLoadIdentity = glLoadIdentity@0 + glLoadMatrixd = glLoadMatrixd@4 + glLoadMatrixf = glLoadMatrixf@4 + glLoadName = glLoadName@4 + glLogicOp = glLogicOp@4 + glMap1d = glMap1d@32 + glMap1f = glMap1f@24 + glMap2d = glMap2d@56 + glMap2f = glMap2f@40 + glMapGrid1d = glMapGrid1d@20 + glMapGrid1f = glMapGrid1f@12 + glMapGrid2d = glMapGrid2d@40 + glMapGrid2f = glMapGrid2f@24 + glMaterialf = glMaterialf@12 + glMaterialfv = glMaterialfv@12 + glMateriali = glMateriali@12 + glMaterialiv = glMaterialiv@12 + glMatrixMode = glMatrixMode@4 + glMultMatrixd = glMultMatrixd@4 + glMultMatrixf = glMultMatrixf@4 + glNewList = glNewList@8 + glNormal3b = glNormal3b@12 + glNormal3bv = glNormal3bv@4 + glNormal3d = glNormal3d@24 + glNormal3dv = glNormal3dv@4 + glNormal3f = glNormal3f@12 + glNormal3fv = glNormal3fv@4 + glNormal3i = glNormal3i@12 + glNormal3iv = glNormal3iv@4 + glNormal3s = glNormal3s@12 + glNormal3sv = glNormal3sv@4 + glNormalPointer = glNormalPointer@12 + glOrtho = glOrtho@48 + glPassThrough = glPassThrough@4 + glPixelMapfv = glPixelMapfv@12 + glPixelMapuiv = glPixelMapuiv@12 + glPixelMapusv = glPixelMapusv@12 + glPixelStoref = glPixelStoref@8 + glPixelStorei = glPixelStorei@8 + glPixelTransferf = glPixelTransferf@8 + glPixelTransferi = glPixelTransferi@8 + glPixelZoom = glPixelZoom@8 + glPointSize = glPointSize@4 + glPolygonMode = glPolygonMode@8 + glPolygonOffset = glPolygonOffset@8 + glPolygonStipple = glPolygonStipple@4 + glPopAttrib = glPopAttrib@0 + glPopClientAttrib = glPopClientAttrib@0 + glPopMatrix = glPopMatrix@0 + glPopName = glPopName@0 + glPrioritizeTextures = glPrioritizeTextures@12 + glPushAttrib = glPushAttrib@4 + glPushClientAttrib = glPushClientAttrib@4 + glPushMatrix = glPushMatrix@0 + glPushName = glPushName@4 + glRasterPos2d = glRasterPos2d@16 + glRasterPos2dv = glRasterPos2dv@4 + glRasterPos2f = glRasterPos2f@8 + glRasterPos2fv = glRasterPos2fv@4 + glRasterPos2i = glRasterPos2i@8 + glRasterPos2iv = glRasterPos2iv@4 + glRasterPos2s = glRasterPos2s@8 + glRasterPos2sv = glRasterPos2sv@4 + glRasterPos3d = glRasterPos3d@24 + glRasterPos3dv = glRasterPos3dv@4 + glRasterPos3f = glRasterPos3f@12 + glRasterPos3fv = glRasterPos3fv@4 + glRasterPos3i = glRasterPos3i@12 + glRasterPos3iv = glRasterPos3iv@4 + glRasterPos3s = glRasterPos3s@12 + glRasterPos3sv = glRasterPos3sv@4 + glRasterPos4d = glRasterPos4d@32 + glRasterPos4dv = glRasterPos4dv@4 + glRasterPos4f = glRasterPos4f@16 + glRasterPos4fv = glRasterPos4fv@4 + glRasterPos4i = glRasterPos4i@16 + glRasterPos4iv = glRasterPos4iv@4 + glRasterPos4s = glRasterPos4s@16 + glRasterPos4sv = glRasterPos4sv@4 + glReadBuffer = glReadBuffer@4 + glReadPixels = glReadPixels@28 + glRectd = glRectd@32 + glRectdv = glRectdv@8 + glRectf = glRectf@16 + glRectfv = glRectfv@8 + glRecti = glRecti@16 + glRectiv = glRectiv@8 + glRects = glRects@16 + glRectsv = glRectsv@8 + glRenderMode = glRenderMode@4 + glRotated = glRotated@32 + glRotatef = glRotatef@16 + glScaled = glScaled@24 + glScalef = glScalef@12 + glScissor = glScissor@16 + glSelectBuffer = glSelectBuffer@8 + glShadeModel = glShadeModel@4 + glStencilFunc = glStencilFunc@12 + glStencilMask = glStencilMask@4 + glStencilOp = glStencilOp@12 + glTexCoord1d = glTexCoord1d@8 + glTexCoord1dv = glTexCoord1dv@4 + glTexCoord1f = glTexCoord1f@4 + glTexCoord1fv = glTexCoord1fv@4 + glTexCoord1i = glTexCoord1i@4 + glTexCoord1iv = glTexCoord1iv@4 + glTexCoord1s = glTexCoord1s@4 + glTexCoord1sv = glTexCoord1sv@4 + glTexCoord2d = glTexCoord2d@16 + glTexCoord2dv = glTexCoord2dv@4 + glTexCoord2f = glTexCoord2f@8 + glTexCoord2fv = glTexCoord2fv@4 + glTexCoord2i = glTexCoord2i@8 + glTexCoord2iv = glTexCoord2iv@4 + glTexCoord2s = glTexCoord2s@8 + glTexCoord2sv = glTexCoord2sv@4 + glTexCoord3d = glTexCoord3d@24 + glTexCoord3dv = glTexCoord3dv@4 + glTexCoord3f = glTexCoord3f@12 + glTexCoord3fv = glTexCoord3fv@4 + glTexCoord3i = glTexCoord3i@12 + glTexCoord3iv = glTexCoord3iv@4 + glTexCoord3s = glTexCoord3s@12 + glTexCoord3sv = glTexCoord3sv@4 + glTexCoord4d = glTexCoord4d@32 + glTexCoord4dv = glTexCoord4dv@4 + glTexCoord4f = glTexCoord4f@16 + glTexCoord4fv = glTexCoord4fv@4 + glTexCoord4i = glTexCoord4i@16 + glTexCoord4iv = glTexCoord4iv@4 + glTexCoord4s = glTexCoord4s@16 + glTexCoord4sv = glTexCoord4sv@4 + glTexCoordPointer = glTexCoordPointer@16 + glTexEnvf = glTexEnvf@12 + glTexEnvfv = glTexEnvfv@12 + glTexEnvi = glTexEnvi@12 + glTexEnviv = glTexEnviv@12 + glTexGend = glTexGend@16 + glTexGendv = glTexGendv@12 + glTexGenf = glTexGenf@12 + glTexGenfv = glTexGenfv@12 + glTexGeni = glTexGeni@12 + glTexGeniv = glTexGeniv@12 + glTexImage1D = glTexImage1D@32 + glTexImage2D = glTexImage2D@36 + glTexParameterf = glTexParameterf@12 + glTexParameterfv = glTexParameterfv@12 + glTexParameteri = glTexParameteri@12 + glTexParameteriv = glTexParameteriv@12 + glTexSubImage1D = glTexSubImage1D@28 + glTexSubImage2D = glTexSubImage2D@36 + glTranslated = glTranslated@24 + glTranslatef = glTranslatef@12 + glVertex2d = glVertex2d@16 + glVertex2dv = glVertex2dv@4 + glVertex2f = glVertex2f@8 + glVertex2fv = glVertex2fv@4 + glVertex2i = glVertex2i@8 + glVertex2iv = glVertex2iv@4 + glVertex2s = glVertex2s@8 + glVertex2sv = glVertex2sv@4 + glVertex3d = glVertex3d@24 + glVertex3dv = glVertex3dv@4 + glVertex3f = glVertex3f@12 + glVertex3fv = glVertex3fv@4 + glVertex3i = glVertex3i@12 + glVertex3iv = glVertex3iv@4 + glVertex3s = glVertex3s@12 + glVertex3sv = glVertex3sv@4 + glVertex4d = glVertex4d@32 + glVertex4dv = glVertex4dv@4 + glVertex4f = glVertex4f@16 + glVertex4fv = glVertex4fv@4 + glVertex4i = glVertex4i@16 + glVertex4iv = glVertex4iv@4 + glVertex4s = glVertex4s@16 + glVertex4sv = glVertex4sv@4 + glVertexPointer = glVertexPointer@16 + glViewport = glViewport@16 + wglChoosePixelFormat = wglChoosePixelFormat@8 + wglCopyContext = wglCopyContext@12 + wglCreateContext = wglCreateContext@4 + wglCreateLayerContext = wglCreateLayerContext@8 + wglDeleteContext = wglDeleteContext@4 + wglDescribeLayerPlane = wglDescribeLayerPlane@20 + wglDescribePixelFormat = wglDescribePixelFormat@16 + wglGetCurrentContext = wglGetCurrentContext@0 + wglGetCurrentDC = wglGetCurrentDC@0 +; wglGetDefaultProcAddress = wglGetDefaultProcAddress@4 + wglGetLayerPaletteEntries = wglGetLayerPaletteEntries@20 + wglGetPixelFormat = wglGetPixelFormat@4 + wglGetProcAddress = wglGetProcAddress@4 + wglMakeCurrent = wglMakeCurrent@8 + wglRealizeLayerPalette = wglRealizeLayerPalette@12 + wglSetLayerPaletteEntries = wglSetLayerPaletteEntries@20 + wglSetPixelFormat = wglSetPixelFormat@12 + wglShareLists = wglShareLists@8 + wglSwapBuffers = wglSwapBuffers@4 + wglSwapLayerBuffers = wglSwapLayerBuffers@8 +; wglSwapMultipleBuffers = wglSwapMultipleBuffers@8 + wglUseFontBitmapsA = wglUseFontBitmapsA@16 + wglUseFontBitmapsW = wglUseFontBitmapsW@16 + wglUseFontOutlinesA = wglUseFontOutlinesA@32 + wglUseFontOutlinesW = wglUseFontOutlinesW@32 + DrvCopyContext = DrvCopyContext@12 + DrvCreateContext = DrvCreateContext@4 + DrvCreateLayerContext = DrvCreateLayerContext@8 + DrvDeleteContext = DrvDeleteContext@4 + DrvDescribeLayerPlane = DrvDescribeLayerPlane@20 + DrvDescribePixelFormat = DrvDescribePixelFormat@16 + DrvGetLayerPaletteEntries = DrvGetLayerPaletteEntries@20 + DrvGetProcAddress = DrvGetProcAddress@4 + DrvRealizeLayerPalette = DrvRealizeLayerPalette@12 + DrvReleaseContext = DrvReleaseContext@4 + DrvSetCallbackProcs = DrvSetCallbackProcs@8 + DrvSetContext = DrvSetContext@12 + DrvSetLayerPaletteEntries = DrvSetLayerPaletteEntries@20 + DrvSetPixelFormat = DrvSetPixelFormat@8 + DrvShareLists = DrvShareLists@8 + DrvSwapBuffers = DrvSwapBuffers@4 + DrvSwapLayerBuffers = DrvSwapLayerBuffers@8 + DrvValidateVersion = DrvValidateVersion@4 diff --git a/src/gallium/state_trackers/wgl/shared/stw_arbpixelformat.c b/src/gallium/state_trackers/wgl/shared/stw_arbpixelformat.c new file mode 100644 index 0000000000..0e2d407699 --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_arbpixelformat.c @@ -0,0 +1,483 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/** + * @file + * + * WGL_ARB_pixel_format extension implementation. + * + * @sa http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt + */ + + +#include <windows.h> + +#define WGL_WGLEXT_PROTOTYPES + +#include <GL/gl.h> +#include <GL/wglext.h> + +#include "pipe/p_compiler.h" +#include "util/u_memory.h" +#include "stw_public.h" +#include "stw_pixelformat.h" + + +static boolean +stw_query_attrib( + int iPixelFormat, + int iLayerPlane, + int attrib, + int *pvalue ) +{ + uint count; + uint index; + const struct stw_pixelformat_info *pfi; + + count = stw_pixelformat_get_extended_count(); + + if (attrib == WGL_NUMBER_PIXEL_FORMATS_ARB) { + *pvalue = (int) count; + return TRUE; + } + + index = (uint) iPixelFormat - 1; + if (index >= count) + return FALSE; + + pfi = stw_pixelformat_get_info( index ); + + switch (attrib) { + case WGL_DRAW_TO_WINDOW_ARB: + *pvalue = pfi->pfd.dwFlags & PFD_DRAW_TO_WINDOW ? TRUE : FALSE; + return TRUE; + + case WGL_DRAW_TO_BITMAP_ARB: + *pvalue = pfi->pfd.dwFlags & PFD_DRAW_TO_BITMAP ? TRUE : FALSE; + return TRUE; + + case WGL_NEED_PALETTE_ARB: + *pvalue = pfi->pfd.dwFlags & PFD_NEED_PALETTE ? TRUE : FALSE; + return TRUE; + + case WGL_NEED_SYSTEM_PALETTE_ARB: + *pvalue = pfi->pfd.dwFlags & PFD_NEED_SYSTEM_PALETTE ? TRUE : FALSE; + return TRUE; + + case WGL_SWAP_METHOD_ARB: + *pvalue = pfi->pfd.dwFlags & PFD_SWAP_COPY ? WGL_SWAP_COPY_ARB : WGL_SWAP_UNDEFINED_ARB; + return TRUE; + + case WGL_SWAP_LAYER_BUFFERS_ARB: + *pvalue = FALSE; + return TRUE; + + case WGL_NUMBER_OVERLAYS_ARB: + *pvalue = 0; + return TRUE; + + case WGL_NUMBER_UNDERLAYS_ARB: + *pvalue = 0; + return TRUE; + } + + if (iLayerPlane != 0) + return FALSE; + + switch (attrib) { + case WGL_ACCELERATION_ARB: + *pvalue = WGL_FULL_ACCELERATION_ARB; + break; + + case WGL_TRANSPARENT_ARB: + *pvalue = FALSE; + break; + + case WGL_TRANSPARENT_RED_VALUE_ARB: + case WGL_TRANSPARENT_GREEN_VALUE_ARB: + case WGL_TRANSPARENT_BLUE_VALUE_ARB: + case WGL_TRANSPARENT_ALPHA_VALUE_ARB: + case WGL_TRANSPARENT_INDEX_VALUE_ARB: + break; + + case WGL_SHARE_DEPTH_ARB: + case WGL_SHARE_STENCIL_ARB: + case WGL_SHARE_ACCUM_ARB: + *pvalue = TRUE; + break; + + case WGL_SUPPORT_GDI_ARB: + *pvalue = pfi->pfd.dwFlags & PFD_SUPPORT_GDI ? TRUE : FALSE; + break; + + case WGL_SUPPORT_OPENGL_ARB: + *pvalue = pfi->pfd.dwFlags & PFD_SUPPORT_OPENGL ? TRUE : FALSE; + break; + + case WGL_DOUBLE_BUFFER_ARB: + *pvalue = pfi->pfd.dwFlags & PFD_DOUBLEBUFFER ? TRUE : FALSE; + break; + + case WGL_STEREO_ARB: + *pvalue = pfi->pfd.dwFlags & PFD_STEREO ? TRUE : FALSE; + break; + + case WGL_PIXEL_TYPE_ARB: + switch (pfi->pfd.iPixelType) { + case PFD_TYPE_RGBA: + *pvalue = WGL_TYPE_RGBA_ARB; + break; + case PFD_TYPE_COLORINDEX: + *pvalue = WGL_TYPE_COLORINDEX_ARB; + break; + default: + return FALSE; + } + break; + + case WGL_COLOR_BITS_ARB: + *pvalue = pfi->pfd.cColorBits; + break; + + case WGL_RED_BITS_ARB: + *pvalue = pfi->pfd.cRedBits; + break; + + case WGL_RED_SHIFT_ARB: + *pvalue = pfi->pfd.cRedShift; + break; + + case WGL_GREEN_BITS_ARB: + *pvalue = pfi->pfd.cGreenBits; + break; + + case WGL_GREEN_SHIFT_ARB: + *pvalue = pfi->pfd.cGreenShift; + break; + + case WGL_BLUE_BITS_ARB: + *pvalue = pfi->pfd.cBlueBits; + break; + + case WGL_BLUE_SHIFT_ARB: + *pvalue = pfi->pfd.cBlueShift; + break; + + case WGL_ALPHA_BITS_ARB: + *pvalue = pfi->pfd.cAlphaBits; + break; + + case WGL_ALPHA_SHIFT_ARB: + *pvalue = pfi->pfd.cAlphaShift; + break; + + case WGL_ACCUM_BITS_ARB: + *pvalue = pfi->pfd.cAccumBits; + break; + + case WGL_ACCUM_RED_BITS_ARB: + *pvalue = pfi->pfd.cAccumRedBits; + break; + + case WGL_ACCUM_GREEN_BITS_ARB: + *pvalue = pfi->pfd.cAccumGreenBits; + break; + + case WGL_ACCUM_BLUE_BITS_ARB: + *pvalue = pfi->pfd.cAccumBlueBits; + break; + + case WGL_ACCUM_ALPHA_BITS_ARB: + *pvalue = pfi->pfd.cAccumAlphaBits; + break; + + case WGL_DEPTH_BITS_ARB: + *pvalue = pfi->pfd.cDepthBits; + break; + + case WGL_STENCIL_BITS_ARB: + *pvalue = pfi->pfd.cStencilBits; + break; + + case WGL_AUX_BUFFERS_ARB: + *pvalue = pfi->pfd.cAuxBuffers; + break; + + case WGL_SAMPLE_BUFFERS_ARB: + *pvalue = pfi->numSampleBuffers; + break; + + case WGL_SAMPLES_ARB: + *pvalue = pfi->numSamples; + break; + + default: + return FALSE; + } + + return TRUE; +} + +struct attrib_match_info +{ + int attribute; + int weight; + BOOL exact; +}; + +static const struct attrib_match_info attrib_match[] = { + + /* WGL_ARB_pixel_format */ + { WGL_DRAW_TO_WINDOW_ARB, 0, TRUE }, + { WGL_DRAW_TO_BITMAP_ARB, 0, TRUE }, + { WGL_ACCELERATION_ARB, 0, TRUE }, + { WGL_NEED_PALETTE_ARB, 0, TRUE }, + { WGL_NEED_SYSTEM_PALETTE_ARB, 0, TRUE }, + { WGL_SWAP_LAYER_BUFFERS_ARB, 0, TRUE }, + { WGL_SWAP_METHOD_ARB, 0, TRUE }, + { WGL_NUMBER_OVERLAYS_ARB, 4, FALSE }, + { WGL_NUMBER_UNDERLAYS_ARB, 4, FALSE }, + /*{ WGL_SHARE_DEPTH_ARB, 0, TRUE },*/ /* no overlays -- ignore */ + /*{ WGL_SHARE_STENCIL_ARB, 0, TRUE },*/ /* no overlays -- ignore */ + /*{ WGL_SHARE_ACCUM_ARB, 0, TRUE },*/ /* no overlays -- ignore */ + { WGL_SUPPORT_GDI_ARB, 0, TRUE }, + { WGL_SUPPORT_OPENGL_ARB, 0, TRUE }, + { WGL_DOUBLE_BUFFER_ARB, 0, TRUE }, + { WGL_STEREO_ARB, 0, TRUE }, + { WGL_PIXEL_TYPE_ARB, 0, TRUE }, + { WGL_COLOR_BITS_ARB, 1, FALSE }, + { WGL_RED_BITS_ARB, 1, FALSE }, + { WGL_GREEN_BITS_ARB, 1, FALSE }, + { WGL_BLUE_BITS_ARB, 1, FALSE }, + { WGL_ALPHA_BITS_ARB, 1, FALSE }, + { WGL_ACCUM_BITS_ARB, 1, FALSE }, + { WGL_ACCUM_RED_BITS_ARB, 1, FALSE }, + { WGL_ACCUM_GREEN_BITS_ARB, 1, FALSE }, + { WGL_ACCUM_BLUE_BITS_ARB, 1, FALSE }, + { WGL_ACCUM_ALPHA_BITS_ARB, 1, FALSE }, + { WGL_DEPTH_BITS_ARB, 1, FALSE }, + { WGL_STENCIL_BITS_ARB, 1, FALSE }, + { WGL_AUX_BUFFERS_ARB, 2, FALSE }, + + /* WGL_ARB_multisample */ + { WGL_SAMPLE_BUFFERS_ARB, 2, FALSE }, + { WGL_SAMPLES_ARB, 2, FALSE } +}; + +struct stw_pixelformat_score +{ + int points; + uint index; +}; + +static BOOL +score_pixelformats( + struct stw_pixelformat_score *scores, + uint count, + int attribute, + int expected_value ) +{ + uint i; + const struct attrib_match_info *ami = NULL; + uint index; + + /* Find out if a given attribute should be considered for score calculation. + */ + for (i = 0; i < sizeof( attrib_match ) / sizeof( attrib_match[0] ); i++) { + if (attrib_match[i].attribute == attribute) { + ami = &attrib_match[i]; + break; + } + } + if (ami == NULL) + return TRUE; + + /* Iterate all pixelformats, query the requested attribute and calculate + * score points. + */ + for (index = 0; index < count; index++) { + int actual_value; + + if (!stw_query_attrib( index + 1, 0, attribute, &actual_value )) + return FALSE; + + if (ami->exact) { + /* For an exact match criteria, if the actual and expected values differ, + * the score is set to 0 points, effectively removing the pixelformat + * from a list of matching pixelformats. + */ + if (actual_value != expected_value) + scores[index].points = 0; + } + else { + /* For a minimum match criteria, if the actual value is smaller than the expected + * value, the pixelformat is rejected (score set to 0). However, if the actual + * value is bigger, the pixelformat is given a penalty to favour pixelformats that + * more closely match the expected values. + */ + if (actual_value < expected_value) + scores[index].points = 0; + else if (actual_value > expected_value) + scores[index].points -= (actual_value - expected_value) * ami->weight; + } + } + + return TRUE; +} + +WINGDIAPI BOOL APIENTRY +wglChoosePixelFormatARB( + HDC hdc, + const int *piAttribIList, + const FLOAT *pfAttribFList, + UINT nMaxFormats, + int *piFormats, + UINT *nNumFormats ) +{ + uint count; + struct stw_pixelformat_score *scores; + uint i; + + *nNumFormats = 0; + + /* Allocate and initialize pixelformat score table -- better matches + * have higher scores. Start with a high score and take out penalty + * points for a mismatch when the match does not have to be exact. + * Set a score to 0 if there is a mismatch for an exact match criteria. + */ + count = stw_pixelformat_get_extended_count(); + scores = (struct stw_pixelformat_score *) MALLOC( count * sizeof( struct stw_pixelformat_score ) ); + if (scores == NULL) + return FALSE; + for (i = 0; i < count; i++) { + scores[i].points = 0x7fffffff; + scores[i].index = i; + } + + /* Given the attribute list calculate a score for each pixelformat. + */ + if (piAttribIList != NULL) { + while (*piAttribIList != 0) { + if (!score_pixelformats( scores, count, piAttribIList[0], piAttribIList[1] )) { + FREE( scores ); + return FALSE; + } + piAttribIList += 2; + } + } + if (pfAttribFList != NULL) { + while (*pfAttribFList != 0) { + if (!score_pixelformats( scores, count, (int) pfAttribFList[0], (int) pfAttribFList[1] )) { + FREE( scores ); + return FALSE; + } + pfAttribFList += 2; + } + } + + /* Bubble-sort the resulting scores. Pixelformats with higher scores go first. + * TODO: Find out if there are any patent issues with it. + */ + if (count > 1) { + uint n = count; + boolean swapped; + + do { + swapped = FALSE; + for (i = 1; i < n; i++) { + if (scores[i - 1].points < scores[i].points) { + struct stw_pixelformat_score score = scores[i - 1]; + + scores[i - 1] = scores[i]; + scores[i] = score; + swapped = TRUE; + } + } + n--; + } + while (swapped); + } + + /* Return a list of pixelformats that are the best match. + * Reject pixelformats with non-positive scores. + */ + for (i = 0; i < count; i++) { + if (scores[i].points > 0) { + if (*nNumFormats < nMaxFormats) + piFormats[*nNumFormats] = scores[i].index + 1; + (*nNumFormats)++; + } + } + + FREE( scores ); + return TRUE; +} + +WINGDIAPI BOOL APIENTRY +wglGetPixelFormatAttribfvARB( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nAttributes, + const int *piAttributes, + FLOAT *pfValues ) +{ + UINT i; + + (void) hdc; + + for (i = 0; i < nAttributes; i++) { + int value; + + if (!stw_query_attrib( iPixelFormat, iLayerPlane, piAttributes[i], &value )) + return FALSE; + pfValues[i] = (FLOAT) value; + } + + return TRUE; +} + +WINGDIAPI BOOL APIENTRY +wglGetPixelFormatAttribivARB( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nAttributes, + const int *piAttributes, + int *piValues ) +{ + UINT i; + + (void) hdc; + + for (i = 0; i < nAttributes; i++) { + if (!stw_query_attrib( iPixelFormat, iLayerPlane, piAttributes[i], &piValues[i] )) + return FALSE; + } + + return TRUE; +} diff --git a/src/gallium/state_trackers/wgl/shared/stw_context.c b/src/gallium/state_trackers/wgl/shared/stw_context.c new file mode 100644 index 0000000000..4968ecc692 --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_context.c @@ -0,0 +1,382 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <windows.h> + +#include "main/mtypes.h" +#include "main/context.h" +#include "pipe/p_compiler.h" +#include "pipe/p_context.h" +#include "state_tracker/st_context.h" +#include "state_tracker/st_public.h" + +#ifdef DEBUG +#include "trace/tr_screen.h" +#include "trace/tr_context.h" +#endif + +#include "shared/stw_device.h" +#include "shared/stw_winsys.h" +#include "shared/stw_framebuffer.h" +#include "shared/stw_pixelformat.h" +#include "stw_public.h" +#include "stw_context.h" +#include "stw_tls.h" + + +static INLINE struct stw_context * +stw_context(GLcontext *glctx) +{ + if(!glctx) + return NULL; + assert(glctx->DriverCtx); + return (struct stw_context *)glctx->DriverCtx; +} + +static INLINE struct stw_context * +stw_current_context(void) +{ + /* We must check if multiple threads are being used or GET_CURRENT_CONTEXT + * might return the current context of the thread first seen. */ + _glapi_check_multithread(); + + { + GET_CURRENT_CONTEXT( glctx ); + return stw_context(glctx); + } +} + +BOOL +stw_copy_context( + UINT_PTR hglrcSrc, + UINT_PTR hglrcDst, + UINT mask ) +{ + struct stw_context *src; + struct stw_context *dst; + BOOL ret = FALSE; + + pipe_mutex_lock( stw_dev->ctx_mutex ); + + src = stw_lookup_context_locked( hglrcSrc ); + dst = stw_lookup_context_locked( hglrcDst ); + + if (src && dst) { + /* FIXME */ + assert(0); + (void) src; + (void) dst; + (void) mask; + } + + pipe_mutex_unlock( stw_dev->ctx_mutex ); + + return ret; +} + +BOOL +stw_share_lists( + UINT_PTR hglrc1, + UINT_PTR hglrc2 ) +{ + struct stw_context *ctx1; + struct stw_context *ctx2; + BOOL ret = FALSE; + + pipe_mutex_lock( stw_dev->ctx_mutex ); + + ctx1 = stw_lookup_context_locked( hglrc1 ); + ctx2 = stw_lookup_context_locked( hglrc2 ); + + if (ctx1 && ctx2 && + ctx1->iPixelFormat == ctx2->iPixelFormat) { + ret = _mesa_share_state(ctx2->st->ctx, ctx1->st->ctx); + } + + pipe_mutex_unlock( stw_dev->ctx_mutex ); + + return ret; +} + +static void +stw_viewport(GLcontext * glctx, GLint x, GLint y, + GLsizei width, GLsizei height) +{ + struct stw_context *ctx = (struct stw_context *)glctx->DriverCtx; + struct stw_framebuffer *fb; + + fb = stw_framebuffer_from_hdc( ctx->hdc ); + if(fb) { + stw_framebuffer_update(fb); + stw_framebuffer_release(fb); + } +} + +UINT_PTR +stw_create_layer_context( + HDC hdc, + int iLayerPlane ) +{ + int iPixelFormat; + const struct stw_pixelformat_info *pfi; + GLvisual visual; + struct stw_context *ctx = NULL; + struct pipe_screen *screen = NULL; + struct pipe_context *pipe = NULL; + + if(!stw_dev) + return 0; + + if (iLayerPlane != 0) + return 0; + + iPixelFormat = GetPixelFormat(hdc); + if(!iPixelFormat) + return 0; + + pfi = stw_pixelformat_get_info( iPixelFormat - 1 ); + stw_pixelformat_visual(&visual, pfi); + + ctx = CALLOC_STRUCT( stw_context ); + if (ctx == NULL) + goto no_ctx; + + ctx->hdc = hdc; + ctx->iPixelFormat = iPixelFormat; + + screen = stw_dev->screen; + +#ifdef DEBUG + /* Unwrap screen */ + if(stw_dev->trace_running) + screen = trace_screen(screen)->screen; +#endif + + pipe = stw_dev->stw_winsys->create_context( screen ); + if (pipe == NULL) + goto no_pipe; + +#ifdef DEBUG + /* Wrap context */ + if(stw_dev->trace_running) + pipe = trace_context_create(stw_dev->screen, pipe); +#endif + + /* pass to stw_flush_frontbuffer as context_private */ + assert(!pipe->priv); + pipe->priv = hdc; + + ctx->st = st_create_context( pipe, &visual, NULL ); + if (ctx->st == NULL) + goto no_st_ctx; + + ctx->st->ctx->DriverCtx = ctx; + ctx->st->ctx->Driver.Viewport = stw_viewport; + + pipe_mutex_lock( stw_dev->ctx_mutex ); + ctx->hglrc = handle_table_add(stw_dev->ctx_table, ctx); + pipe_mutex_unlock( stw_dev->ctx_mutex ); + if (!ctx->hglrc) + goto no_hglrc; + + return ctx->hglrc; + +no_hglrc: + st_destroy_context(ctx->st); + goto no_pipe; /* st_context_destroy already destroys pipe */ +no_st_ctx: + pipe->destroy( pipe ); +no_pipe: + FREE(ctx); +no_ctx: + return 0; +} + +BOOL +stw_delete_context( + UINT_PTR hglrc ) +{ + struct stw_context *ctx ; + BOOL ret = FALSE; + + if (!stw_dev) + return FALSE; + + pipe_mutex_lock( stw_dev->ctx_mutex ); + ctx = stw_lookup_context_locked(hglrc); + handle_table_remove(stw_dev->ctx_table, hglrc); + pipe_mutex_unlock( stw_dev->ctx_mutex ); + + if (ctx) { + struct stw_context *curctx = stw_current_context(); + + /* Unbind current if deleting current context. */ + if (curctx == ctx) + st_make_current( NULL, NULL, NULL ); + + st_destroy_context(ctx->st); + FREE(ctx); + + ret = TRUE; + } + + return ret; +} + +BOOL +stw_release_context( + UINT_PTR hglrc ) +{ + struct stw_context *ctx; + + if (!stw_dev) + return FALSE; + + pipe_mutex_lock( stw_dev->ctx_mutex ); + ctx = stw_lookup_context_locked( hglrc ); + pipe_mutex_unlock( stw_dev->ctx_mutex ); + + if (!ctx) + return FALSE; + + /* The expectation is that ctx is the same context which is + * current for this thread. We should check that and return False + * if not the case. + */ + if (ctx != stw_current_context()) + return FALSE; + + if (stw_make_current( NULL, 0 ) == FALSE) + return FALSE; + + return TRUE; +} + + +UINT_PTR +stw_get_current_context( void ) +{ + struct stw_context *ctx; + + ctx = stw_current_context(); + if(!ctx) + return 0; + + return ctx->hglrc; +} + +HDC +stw_get_current_dc( void ) +{ + struct stw_context *ctx; + + ctx = stw_current_context(); + if(!ctx) + return NULL; + + return ctx->hdc; +} + +BOOL +stw_make_current( + HDC hdc, + UINT_PTR hglrc ) +{ + struct stw_context *curctx = NULL; + struct stw_context *ctx = NULL; + struct stw_framebuffer *fb = NULL; + + if (!stw_dev) + goto fail; + + curctx = stw_current_context(); + if (curctx != NULL) { + if (curctx->hglrc != hglrc) + st_flush(curctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); + + /* Return if already current. */ + if (curctx->hglrc == hglrc && curctx->hdc == hdc) { + ctx = curctx; + fb = stw_framebuffer_from_hdc( hdc ); + goto success; + } + } + + if (hdc == NULL || hglrc == 0) { + return st_make_current( NULL, NULL, NULL ); + } + + pipe_mutex_lock( stw_dev->ctx_mutex ); + ctx = stw_lookup_context_locked( hglrc ); + pipe_mutex_unlock( stw_dev->ctx_mutex ); + if(!ctx) + goto fail; + + fb = stw_framebuffer_from_hdc( hdc ); + if(!fb) { + /* Applications should call SetPixelFormat before creating a context, + * but not all do, and the opengl32 runtime seems to use a default pixel + * format in some cases, so we must create a framebuffer for those here + */ + int iPixelFormat = GetPixelFormat(hdc); + if(iPixelFormat) + fb = stw_framebuffer_create( hdc, iPixelFormat ); + if(!fb) + goto fail; + } + + if(fb->iPixelFormat != ctx->iPixelFormat) + goto fail; + + /* Lazy allocation of the frame buffer */ + if(!stw_framebuffer_allocate(fb)) + goto fail; + + /* Bind the new framebuffer */ + ctx->hdc = hdc; + + /* pass to stw_flush_frontbuffer as context_private */ + ctx->st->pipe->priv = hdc; + + if(!st_make_current( ctx->st, fb->stfb, fb->stfb )) + goto fail; + +success: + assert(fb); + if(fb) { + stw_framebuffer_update(fb); + stw_framebuffer_release(fb); + } + + return TRUE; + +fail: + if(fb) + stw_framebuffer_release(fb); + st_make_current( NULL, NULL, NULL ); + return FALSE; +} diff --git a/src/gallium/state_trackers/wgl/shared/stw_context.h b/src/gallium/state_trackers/wgl/shared/stw_context.h new file mode 100644 index 0000000000..166471de5e --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_context.h @@ -0,0 +1,43 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STW_CONTEXT_H +#define STW_CONTEXT_H + +#include <windows.h> + +struct st_context; + +struct stw_context +{ + struct st_context *st; + UINT_PTR hglrc; + int iPixelFormat; + HDC hdc; +}; + +#endif /* STW_CONTEXT_H */ diff --git a/src/gallium/state_trackers/wgl/shared/stw_device.c b/src/gallium/state_trackers/wgl/shared/stw_device.c new file mode 100644 index 0000000000..0b6954915a --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_device.c @@ -0,0 +1,225 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <windows.h> + +#include "glapi/glthread.h" +#include "util/u_debug.h" +#include "pipe/p_screen.h" +#include "state_tracker/st_public.h" + +#ifdef DEBUG +#include "trace/tr_screen.h" +#include "trace/tr_texture.h" +#endif + +#include "shared/stw_device.h" +#include "shared/stw_winsys.h" +#include "shared/stw_pixelformat.h" +#include "shared/stw_public.h" +#include "shared/stw_tls.h" +#include "shared/stw_framebuffer.h" + +#ifdef WIN32_THREADS +extern _glthread_Mutex OneTimeLock; +extern void FreeAllTSD(void); +#endif + + +struct stw_device *stw_dev = NULL; + + +/** + * XXX: Dispatch pipe_screen::flush_front_buffer to our + * stw_winsys::flush_front_buffer. + */ +static void +stw_flush_frontbuffer(struct pipe_screen *screen, + struct pipe_surface *surface, + void *context_private ) +{ + const struct stw_winsys *stw_winsys = stw_dev->stw_winsys; + HDC hdc = (HDC)context_private; + struct stw_framebuffer *fb; + + fb = stw_framebuffer_from_hdc( hdc ); + /* fb can be NULL if window was destroyed already */ + if (fb) { +#if DEBUG + { + struct pipe_surface *surface2; + + if(!st_get_framebuffer_surface( fb->stfb, ST_SURFACE_FRONT_LEFT, &surface2 )) + assert(0); + else + assert(surface2 == surface); + } +#endif + +#ifdef DEBUG + if(stw_dev->trace_running) { + screen = trace_screen(screen)->screen; + surface = trace_surface(surface)->surface; + } +#endif + } + + stw_winsys->flush_frontbuffer(screen, surface, hdc); + + if(fb) { + stw_framebuffer_update(fb); + stw_framebuffer_release(fb); + } +} + + +boolean +stw_init(const struct stw_winsys *stw_winsys) +{ + static struct stw_device stw_dev_storage; + struct pipe_screen *screen; + + debug_printf("%s\n", __FUNCTION__); + + assert(!stw_dev); + + stw_tls_init(); + + stw_dev = &stw_dev_storage; + memset(stw_dev, 0, sizeof(*stw_dev)); + +#ifdef DEBUG + stw_dev->memdbg_no = debug_memory_begin(); +#endif + + stw_dev->stw_winsys = stw_winsys; + +#ifdef WIN32_THREADS + _glthread_INIT_MUTEX(OneTimeLock); +#endif + + screen = stw_winsys->create_screen(); + if(!screen) + goto error1; + +#ifdef DEBUG + stw_dev->screen = trace_screen_create(screen); + stw_dev->trace_running = stw_dev->screen != screen ? TRUE : FALSE; +#else + stw_dev->screen = screen; +#endif + + stw_dev->screen->flush_frontbuffer = &stw_flush_frontbuffer; + + pipe_mutex_init( stw_dev->ctx_mutex ); + pipe_mutex_init( stw_dev->fb_mutex ); + + stw_dev->ctx_table = handle_table_create(); + if (!stw_dev->ctx_table) { + goto error1; + } + + stw_pixelformat_init(); + + return TRUE; + +error1: + stw_dev = NULL; + return FALSE; +} + + +boolean +stw_init_thread(void) +{ + return stw_tls_init_thread(); +} + + +void +stw_cleanup_thread(void) +{ + stw_tls_cleanup_thread(); +} + + +void +stw_cleanup(void) +{ + unsigned i; + + debug_printf("%s\n", __FUNCTION__); + + if (!stw_dev) + return; + + pipe_mutex_lock( stw_dev->ctx_mutex ); + { + /* Ensure all contexts are destroyed */ + i = handle_table_get_first_handle(stw_dev->ctx_table); + while (i) { + stw_delete_context(i); + i = handle_table_get_next_handle(stw_dev->ctx_table, i); + } + handle_table_destroy(stw_dev->ctx_table); + } + pipe_mutex_unlock( stw_dev->ctx_mutex ); + + stw_framebuffer_cleanup(); + + pipe_mutex_destroy( stw_dev->fb_mutex ); + pipe_mutex_destroy( stw_dev->ctx_mutex ); + + stw_dev->screen->destroy(stw_dev->screen); + +#ifdef WIN32_THREADS + _glthread_DESTROY_MUTEX(OneTimeLock); + FreeAllTSD(); +#endif + +#ifdef DEBUG + debug_memory_end(stw_dev->memdbg_no); +#endif + + stw_tls_cleanup(); + + stw_dev = NULL; +} + + +struct stw_context * +stw_lookup_context_locked( UINT_PTR dhglrc ) +{ + if (dhglrc == 0) + return NULL; + + if (stw_dev == NULL) + return NULL; + + return (struct stw_context *) handle_table_get(stw_dev->ctx_table, dhglrc); +} + diff --git a/src/gallium/state_trackers/wgl/shared/stw_device.h b/src/gallium/state_trackers/wgl/shared/stw_device.h new file mode 100644 index 0000000000..e1bb9518dd --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_device.h @@ -0,0 +1,77 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STW_DEVICE_H_ +#define STW_DEVICE_H_ + + +#include <windows.h> + +#include "pipe/p_compiler.h" +#include "pipe/p_thread.h" +#include "util/u_handle_table.h" +#include "stw_pixelformat.h" + + +#define STW_MAX_PIXELFORMATS 256 + + +struct pipe_screen; +struct stw_framebuffer; + +struct stw_device +{ + const struct stw_winsys *stw_winsys; + + struct pipe_screen *screen; + +#ifdef DEBUG + boolean trace_running; +#endif + + struct stw_pixelformat_info pixelformats[STW_MAX_PIXELFORMATS]; + unsigned pixelformat_count; + unsigned pixelformat_extended_count; + + pipe_mutex ctx_mutex; + struct handle_table *ctx_table; + + pipe_mutex fb_mutex; + struct stw_framebuffer *fb_head; + +#ifdef DEBUG + unsigned long memdbg_no; +#endif +}; + +struct stw_context * +stw_lookup_context_locked( UINT_PTR hglrc ); + +extern struct stw_device *stw_dev; + + +#endif /* STW_DEVICE_H_ */ diff --git a/src/gallium/state_trackers/wgl/shared/stw_extensionsstring.c b/src/gallium/state_trackers/wgl/shared/stw_extensionsstring.c new file mode 100644 index 0000000000..62c859e1f9 --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_extensionsstring.c @@ -0,0 +1,59 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <windows.h> + +#define WGL_WGLEXT_PROTOTYPES + +#include <GL/gl.h> +#include <GL/wglext.h> + + +static const char *stw_extension_string = + "WGL_ARB_extensions_string " + "WGL_ARB_multisample " + "WGL_ARB_pixel_format " +/* "WGL_EXT_swap_interval " */ + "WGL_EXT_extensions_string"; + + +WINGDIAPI const char * APIENTRY +wglGetExtensionsStringARB( + HDC hdc ) +{ + (void) hdc; + + return stw_extension_string; +} + + +WINGDIAPI const char * APIENTRY +wglGetExtensionsStringEXT( void ) +{ + return stw_extension_string; +} diff --git a/src/gallium/state_trackers/wgl/shared/stw_extgallium.c b/src/gallium/state_trackers/wgl/shared/stw_extgallium.c new file mode 100644 index 0000000000..fc22737d7e --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_extgallium.c @@ -0,0 +1,79 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "pipe/p_screen.h" +#include "stw_public.h" +#include "stw_device.h" +#include "stw_winsys.h" + +#ifdef DEBUG +#include "trace/tr_screen.h" +#include "trace/tr_context.h" +#endif + + +struct pipe_screen * APIENTRY +wglGetGalliumScreenMESA(void) +{ + return stw_dev ? stw_dev->screen : NULL; +} + + +/* XXX: Unify with stw_create_layer_context */ +struct pipe_context * APIENTRY +wglCreateGalliumContextMESA(void) +{ + struct pipe_screen *screen = NULL; + struct pipe_context *pipe = NULL; + + if(!stw_dev) + return NULL; + + screen = stw_dev->screen; + +#ifdef DEBUG + /* Unwrap screen */ + if(stw_dev->trace_running) + screen = trace_screen(screen)->screen; +#endif + + pipe = stw_dev->stw_winsys->create_context( screen ); + if (pipe == NULL) + goto no_pipe; + +#ifdef DEBUG + /* Wrap context */ + if(stw_dev->trace_running) + pipe = trace_context_create(stw_dev->screen, pipe); +#endif + + return pipe; + +no_pipe: + return NULL; +} diff --git a/src/gallium/state_trackers/wgl/shared/stw_extgallium.h b/src/gallium/state_trackers/wgl/shared/stw_extgallium.h new file mode 100644 index 0000000000..cc35f2bb7f --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_extgallium.h @@ -0,0 +1,47 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STW_EXTGALLIUM_H_ +#define STW_EXTGALLIUM_H_ + + +#include <windows.h> + + +struct pipe_screen; +struct pipe_context; + + +struct pipe_screen * APIENTRY +wglGetGalliumScreenMESA(void); + + +struct pipe_context * APIENTRY +wglCreateGalliumContextMESA(void); + + +#endif /* STW_EXTGALLIUM_H_ */ diff --git a/src/gallium/state_trackers/wgl/shared/stw_extswapinterval.c b/src/gallium/state_trackers/wgl/shared/stw_extswapinterval.c new file mode 100644 index 0000000000..9eac6a1d09 --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_extswapinterval.c @@ -0,0 +1,57 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <windows.h> + +#define WGL_WGLEXT_PROTOTYPES + +#include <GL/gl.h> +#include <GL/wglext.h> +#include "util/u_debug.h" + +/* A dummy implementation of this extension. + * + * Required as some applications retrieve and call these functions + * regardless of the fact that we don't advertise the extension and + * further more the results of wglGetProcAddress are NULL. + */ +WINGDIAPI BOOL APIENTRY +wglSwapIntervalEXT(int interval) +{ + (void) interval; + debug_printf("%s: %d\n", __FUNCTION__, interval); + return TRUE; +} + +WINGDIAPI int APIENTRY +wglGetSwapIntervalEXT(void) +{ + return 0; +} + + diff --git a/src/gallium/state_trackers/wgl/shared/stw_framebuffer.c b/src/gallium/state_trackers/wgl/shared/stw_framebuffer.c new file mode 100644 index 0000000000..b8956bb550 --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_framebuffer.c @@ -0,0 +1,493 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <windows.h> + +#include "main/context.h" +#include "pipe/p_format.h" +#include "pipe/p_screen.h" +#include "state_tracker/st_context.h" +#include "state_tracker/st_public.h" + +#ifdef DEBUG +#include "trace/tr_screen.h" +#include "trace/tr_texture.h" +#endif + +#include "stw_framebuffer.h" +#include "stw_device.h" +#include "stw_public.h" +#include "stw_winsys.h" +#include "stw_tls.h" + + +/** + * Search the framebuffer with the matching HWND while holding the + * stw_dev::fb_mutex global lock. + */ +static INLINE struct stw_framebuffer * +stw_framebuffer_from_hwnd_locked( + HWND hwnd ) +{ + struct stw_framebuffer *fb; + + for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next) + if (fb->hWnd == hwnd) { + pipe_mutex_lock(fb->mutex); + break; + } + + return fb; +} + + +/** + * Destroy this framebuffer. Both stw_dev::fb_mutex and stw_framebuffer::mutex + * must be held, by this order. Obviously no further access to fb can be done + * after this. + */ +static INLINE void +stw_framebuffer_destroy_locked( + struct stw_framebuffer *fb ) +{ + struct stw_framebuffer **link; + + link = &stw_dev->fb_head; + while (*link != fb) + link = &(*link)->next; + assert(*link); + *link = fb->next; + fb->next = NULL; + + st_unreference_framebuffer(fb->stfb); + + pipe_mutex_unlock( fb->mutex ); + + pipe_mutex_destroy( fb->mutex ); + + FREE( fb ); +} + + +void +stw_framebuffer_release( + struct stw_framebuffer *fb) +{ + assert(fb); + pipe_mutex_unlock( fb->mutex ); +} + + +static INLINE void +stw_framebuffer_get_size( struct stw_framebuffer *fb ) +{ + unsigned width, height; + RECT rect; + + assert(fb->hWnd); + + GetClientRect( fb->hWnd, &rect ); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + if(width < 1) + width = 1; + if(height < 1) + height = 1; + + if(width != fb->width || height != fb->height) { + fb->must_resize = TRUE; + fb->width = width; + fb->height = height; + } +} + + +/** + * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx + * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx + */ +LRESULT CALLBACK +stw_call_window_proc( + int nCode, + WPARAM wParam, + LPARAM lParam ) +{ + struct stw_tls_data *tls_data; + PCWPSTRUCT pParams = (PCWPSTRUCT)lParam; + struct stw_framebuffer *fb; + + tls_data = stw_tls_get_data(); + if(!tls_data) + return 0; + + if (nCode < 0) + return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam); + + if (pParams->message == WM_WINDOWPOSCHANGED) { + /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to + * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx + * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it + * can be masked out by the application. */ + LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam; + if((lpWindowPos->flags & SWP_SHOWWINDOW) || + !(lpWindowPos->flags & SWP_NOSIZE)) { + fb = stw_framebuffer_from_hwnd( pParams->hwnd ); + if(fb) { + /* Size in WINDOWPOS includes the window frame, so get the size + * of the client area via GetClientRect. */ + stw_framebuffer_get_size(fb); + stw_framebuffer_release(fb); + } + } + } + else if (pParams->message == WM_DESTROY) { + pipe_mutex_lock( stw_dev->fb_mutex ); + fb = stw_framebuffer_from_hwnd_locked( pParams->hwnd ); + if(fb) + stw_framebuffer_destroy_locked(fb); + pipe_mutex_unlock( stw_dev->fb_mutex ); + } + + return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam); +} + + +struct stw_framebuffer * +stw_framebuffer_create( + HDC hdc, + int iPixelFormat ) +{ + HWND hWnd; + struct stw_framebuffer *fb; + const struct stw_pixelformat_info *pfi; + + /* We only support drawing to a window. */ + hWnd = WindowFromDC( hdc ); + if(!hWnd) + return NULL; + + fb = CALLOC_STRUCT( stw_framebuffer ); + if (fb == NULL) + return NULL; + + fb->hDC = hdc; + fb->hWnd = hWnd; + fb->iPixelFormat = iPixelFormat; + + fb->pfi = pfi = stw_pixelformat_get_info( iPixelFormat - 1 ); + + stw_pixelformat_visual(&fb->visual, pfi); + + stw_framebuffer_get_size(fb); + + pipe_mutex_init( fb->mutex ); + + /* This is the only case where we lock the stw_framebuffer::mutex before + * stw_dev::fb_mutex, since no other thread can know about this framebuffer + * and we must prevent any other thread from destroying it before we return. + */ + pipe_mutex_lock( fb->mutex ); + + pipe_mutex_lock( stw_dev->fb_mutex ); + fb->next = stw_dev->fb_head; + stw_dev->fb_head = fb; + pipe_mutex_unlock( stw_dev->fb_mutex ); + + return fb; +} + + +BOOL +stw_framebuffer_allocate( + struct stw_framebuffer *fb) +{ + assert(fb); + + if(!fb->stfb) { + const struct stw_pixelformat_info *pfi = fb->pfi; + enum pipe_format colorFormat, depthFormat, stencilFormat; + + colorFormat = pfi->color_format; + + assert(pf_layout( pfi->depth_stencil_format ) == PIPE_FORMAT_LAYOUT_RGBAZS ); + + if(pf_get_component_bits( pfi->depth_stencil_format, PIPE_FORMAT_COMP_Z )) + depthFormat = pfi->depth_stencil_format; + else + depthFormat = PIPE_FORMAT_NONE; + + if(pf_get_component_bits( pfi->depth_stencil_format, PIPE_FORMAT_COMP_S )) + stencilFormat = pfi->depth_stencil_format; + else + stencilFormat = PIPE_FORMAT_NONE; + + assert(fb->must_resize); + assert(fb->width); + assert(fb->height); + + fb->stfb = st_create_framebuffer( + &fb->visual, + colorFormat, + depthFormat, + stencilFormat, + fb->width, + fb->height, + (void *) fb ); + + // to notify the context + fb->must_resize = TRUE; + } + + return fb->stfb ? TRUE : FALSE; +} + + +/** + * Update the framebuffer's size if necessary. + */ +void +stw_framebuffer_update( + struct stw_framebuffer *fb) +{ + assert(fb->stfb); + assert(fb->height); + assert(fb->width); + + /* XXX: It would be nice to avoid checking the size again -- in theory + * stw_call_window_proc would have cought the resize and stored the right + * size already, but unfortunately threads created before the DllMain is + * called don't get a DLL_THREAD_ATTACH notification, and there is no way + * to know of their existing without using the not very portable PSAPI. + */ + stw_framebuffer_get_size(fb); + + if(fb->must_resize) { + st_resize_framebuffer(fb->stfb, fb->width, fb->height); + fb->must_resize = FALSE; + } +} + + +void +stw_framebuffer_cleanup( void ) +{ + struct stw_framebuffer *fb; + struct stw_framebuffer *next; + + pipe_mutex_lock( stw_dev->fb_mutex ); + + fb = stw_dev->fb_head; + while (fb) { + next = fb->next; + + pipe_mutex_lock(fb->mutex); + stw_framebuffer_destroy_locked(fb); + + fb = next; + } + stw_dev->fb_head = NULL; + + pipe_mutex_unlock( stw_dev->fb_mutex ); +} + + +/** + * Given an hdc, return the corresponding stw_framebuffer. + */ +static INLINE struct stw_framebuffer * +stw_framebuffer_from_hdc_locked( + HDC hdc ) +{ + HWND hwnd; + struct stw_framebuffer *fb; + + /* + * Some applications create and use several HDCs for the same window, so + * looking up the framebuffer by the HDC is not reliable. Use HWND whenever + * possible. + */ + hwnd = WindowFromDC(hdc); + if(hwnd) + return stw_framebuffer_from_hwnd_locked(hwnd); + + for (fb = stw_dev->fb_head; fb != NULL; fb = fb->next) + if (fb->hDC == hdc) { + pipe_mutex_lock(fb->mutex); + break; + } + + return fb; +} + + +/** + * Given an hdc, return the corresponding stw_framebuffer. + */ +struct stw_framebuffer * +stw_framebuffer_from_hdc( + HDC hdc ) +{ + struct stw_framebuffer *fb; + + pipe_mutex_lock( stw_dev->fb_mutex ); + fb = stw_framebuffer_from_hdc_locked(hdc); + pipe_mutex_unlock( stw_dev->fb_mutex ); + + return fb; +} + + +/** + * Given an hdc, return the corresponding stw_framebuffer. + */ +struct stw_framebuffer * +stw_framebuffer_from_hwnd( + HWND hwnd ) +{ + struct stw_framebuffer *fb; + + pipe_mutex_lock( stw_dev->fb_mutex ); + fb = stw_framebuffer_from_hwnd_locked(hwnd); + pipe_mutex_unlock( stw_dev->fb_mutex ); + + return fb; +} + + +BOOL +stw_pixelformat_set( + HDC hdc, + int iPixelFormat ) +{ + uint count; + uint index; + struct stw_framebuffer *fb; + + index = (uint) iPixelFormat - 1; + count = stw_pixelformat_get_extended_count(); + if (index >= count) + return FALSE; + + fb = stw_framebuffer_from_hdc_locked(hdc); + if(fb) { + /* SetPixelFormat must be called only once */ + stw_framebuffer_release( fb ); + return FALSE; + } + + fb = stw_framebuffer_create(hdc, iPixelFormat); + if(!fb) { + return FALSE; + } + + stw_framebuffer_release( fb ); + + /* Some applications mistakenly use the undocumented wglSetPixelFormat + * function instead of SetPixelFormat, so we call SetPixelFormat here to + * avoid opengl32.dll's wglCreateContext to fail */ + if (GetPixelFormat(hdc) == 0) { + SetPixelFormat(hdc, iPixelFormat, NULL); + } + + return TRUE; +} + + +int +stw_pixelformat_get( + HDC hdc ) +{ + int iPixelFormat = 0; + struct stw_framebuffer *fb; + + fb = stw_framebuffer_from_hdc(hdc); + if(fb) { + iPixelFormat = fb->iPixelFormat; + stw_framebuffer_release(fb); + } + + return iPixelFormat; +} + + +BOOL +stw_swap_buffers( + HDC hdc ) +{ + struct stw_framebuffer *fb; + struct pipe_screen *screen; + struct pipe_surface *surface; + + fb = stw_framebuffer_from_hdc( hdc ); + if (fb == NULL) + return FALSE; + + if (!(fb->pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) { + stw_framebuffer_release(fb); + return TRUE; + } + + /* If we're swapping the buffer associated with the current context + * we have to flush any pending rendering commands first. + */ + st_notify_swapbuffers( fb->stfb ); + + screen = stw_dev->screen; + + if(!st_get_framebuffer_surface( fb->stfb, ST_SURFACE_BACK_LEFT, &surface )) { + /* FIXME: this shouldn't happen, but does on glean */ + stw_framebuffer_release(fb); + return FALSE; + } + +#ifdef DEBUG + if(stw_dev->trace_running) { + screen = trace_screen(screen)->screen; + surface = trace_surface(surface)->surface; + } +#endif + + stw_dev->stw_winsys->flush_frontbuffer( screen, surface, hdc ); + + stw_framebuffer_update(fb); + stw_framebuffer_release(fb); + + return TRUE; +} + + +BOOL +stw_swap_layer_buffers( + HDC hdc, + UINT fuPlanes ) +{ + if(fuPlanes & WGL_SWAP_MAIN_PLANE) + return stw_swap_buffers(hdc); + + return FALSE; +} diff --git a/src/gallium/state_trackers/wgl/shared/stw_framebuffer.h b/src/gallium/state_trackers/wgl/shared/stw_framebuffer.h new file mode 100644 index 0000000000..13d29f37e4 --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_framebuffer.h @@ -0,0 +1,148 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STW_FRAMEBUFFER_H +#define STW_FRAMEBUFFER_H + +#include <windows.h> + +#include "main/mtypes.h" + +#include "pipe/p_thread.h" + +struct stw_pixelformat_info; + +/** + * Windows framebuffer, derived from gl_framebuffer. + */ +struct stw_framebuffer +{ + /** + * This mutex has two purposes: + * - protect the access to the mutable data members below + * - prevent the the framebuffer from being deleted while being accessed. + * + * It is OK to lock this mutex while holding the stw_device::fb_mutex lock, + * but the opposite must never happen. + */ + pipe_mutex mutex; + + /* + * Immutable members. + * + * Note that even access to immutable members implies acquiring the mutex + * above, to prevent the framebuffer from being destroyed. + */ + + HDC hDC; + HWND hWnd; + + int iPixelFormat; + const struct stw_pixelformat_info *pfi; + GLvisual visual; + + /* + * Mutable members. + */ + + struct st_framebuffer *stfb; + + /* FIXME: Make this work for multiple contexts bound to the same framebuffer */ + boolean must_resize; + unsigned width; + unsigned height; + + /** + * This is protected by stw_device::fb_mutex, not the mutex above. + * + * Deletions must be done by first acquiring stw_device::fb_mutex, and then + * acquiring the stw_framebuffer::mutex of the framebuffer to be deleted. + * This ensures that nobody else is reading/writing to the. + * + * It is not necessary to aquire the mutex above to navigate the linked list + * given that deletions are done with stw_device::fb_mutex held, so no other + * thread can delete. + */ + struct stw_framebuffer *next; +}; + + +/** + * Create a new framebuffer object which will correspond to the given HDC. + * + * This function will acquire stw_framebuffer::mutex. stw_framebuffer_release + * must be called when done + */ +struct stw_framebuffer * +stw_framebuffer_create( + HDC hdc, + int iPixelFormat ); + +/** + * Search a framebuffer with a matching HWND. + * + * This function will acquire stw_framebuffer::mutex. stw_framebuffer_release + * must be called when done + */ +struct stw_framebuffer * +stw_framebuffer_from_hwnd( + HWND hwnd ); + +/** + * Search a framebuffer with a matching HDC. + * + * This function will acquire stw_framebuffer::mutex. stw_framebuffer_release + * must be called when done + */ +struct stw_framebuffer * +stw_framebuffer_from_hdc( + HDC hdc ); + +BOOL +stw_framebuffer_allocate( + struct stw_framebuffer *fb ); + +void +stw_framebuffer_update( + struct stw_framebuffer *fb); + +/** + * Release stw_framebuffer::mutex lock. This framebuffer must not be accessed + * after calling this function, as it may have been deleted by another thread + * in the meanwhile. + */ +void +stw_framebuffer_release( + struct stw_framebuffer *fb); + +/** + * Cleanup any existing framebuffers when exiting application. + */ +void +stw_framebuffer_cleanup(void); + +#endif /* STW_FRAMEBUFFER_H */ diff --git a/src/gallium/state_trackers/wgl/shared/stw_getprocaddress.c b/src/gallium/state_trackers/wgl/shared/stw_getprocaddress.c new file mode 100644 index 0000000000..879ced925a --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_getprocaddress.c @@ -0,0 +1,86 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <windows.h> + +#define WGL_WGLEXT_PROTOTYPES + +#include <GL/gl.h> +#include <GL/wglext.h> + +#include "glapi/glapi.h" +#include "stw_public.h" +#include "stw_extgallium.h" + +struct stw_extension_entry +{ + const char *name; + PROC proc; +}; + +#define STW_EXTENSION_ENTRY(P) { #P, (PROC) P } + +static const struct stw_extension_entry stw_extension_entries[] = { + + /* WGL_ARB_extensions_string */ + STW_EXTENSION_ENTRY( wglGetExtensionsStringARB ), + + /* WGL_ARB_pixel_format */ + STW_EXTENSION_ENTRY( wglChoosePixelFormatARB ), + STW_EXTENSION_ENTRY( wglGetPixelFormatAttribfvARB ), + STW_EXTENSION_ENTRY( wglGetPixelFormatAttribivARB ), + + /* WGL_EXT_extensions_string */ + STW_EXTENSION_ENTRY( wglGetExtensionsStringEXT ), + + /* WGL_EXT_swap_interval */ + STW_EXTENSION_ENTRY( wglGetSwapIntervalEXT ), + STW_EXTENSION_ENTRY( wglSwapIntervalEXT ), + + /* WGL_EXT_gallium ? */ + STW_EXTENSION_ENTRY( wglGetGalliumScreenMESA ), + STW_EXTENSION_ENTRY( wglCreateGalliumContextMESA ), + + { NULL, NULL } +}; + +PROC +stw_get_proc_address( + LPCSTR lpszProc ) +{ + const struct stw_extension_entry *entry; + + if (lpszProc[0] == 'w' && lpszProc[1] == 'g' && lpszProc[2] == 'l') + for (entry = stw_extension_entries; entry->name; entry++) + if (strcmp( lpszProc, entry->name ) == 0) + return entry->proc; + + if (lpszProc[0] == 'g' && lpszProc[1] == 'l') + return (PROC) _glapi_get_proc_address( lpszProc ); + + return NULL; +} diff --git a/src/gallium/state_trackers/wgl/shared/stw_pixelformat.c b/src/gallium/state_trackers/wgl/shared/stw_pixelformat.c new file mode 100644 index 0000000000..c296744838 --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_pixelformat.c @@ -0,0 +1,370 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "main/mtypes.h" +#include "main/context.h" + +#include "pipe/p_format.h" +#include "pipe/p_defines.h" +#include "pipe/p_screen.h" + +#include "util/u_debug.h" + +#include "stw_device.h" +#include "stw_pixelformat.h" +#include "stw_public.h" +#include "stw_tls.h" + + +struct stw_pf_color_info +{ + enum pipe_format format; + struct { + unsigned char red; + unsigned char green; + unsigned char blue; + unsigned char alpha; + } bits; + struct { + unsigned char red; + unsigned char green; + unsigned char blue; + unsigned char alpha; + } shift; +}; + +struct stw_pf_depth_info +{ + enum pipe_format format; + struct { + unsigned char depth; + unsigned char stencil; + } bits; +}; + + +/* NOTE: order matters, since in otherwise equal circumstances the first + * format listed will get chosen */ + +static const struct stw_pf_color_info +stw_pf_color[] = { + /* no-alpha */ + { PIPE_FORMAT_X8R8G8B8_UNORM, { 8, 8, 8, 0}, {16, 8, 0, 0} }, + { PIPE_FORMAT_B8G8R8X8_UNORM, { 8, 8, 8, 0}, { 8, 16, 24, 0} }, + { PIPE_FORMAT_R5G6B5_UNORM, { 5, 6, 5, 0}, {11, 5, 0, 0} }, + /* alpha */ + { PIPE_FORMAT_A8R8G8B8_UNORM, { 8, 8, 8, 8}, {16, 8, 0, 24} }, + { PIPE_FORMAT_B8G8R8A8_UNORM, { 8, 8, 8, 8}, { 8, 16, 24, 0} }, +#if 0 + { PIPE_FORMAT_A2B10G10R10_UNORM, {10, 10, 10, 2}, { 0, 10, 20, 30} }, +#endif + { PIPE_FORMAT_A1R5G5B5_UNORM, { 5, 5, 5, 1}, {10, 5, 0, 15} }, + { PIPE_FORMAT_A4R4G4B4_UNORM, { 4, 4, 4, 4}, {16, 4, 0, 12} } +}; + + +static const struct stw_pf_depth_info +stw_pf_depth_stencil[] = { + /* pure depth */ + { PIPE_FORMAT_Z32_UNORM, {32, 0} }, + { PIPE_FORMAT_Z24X8_UNORM, {24, 0} }, + { PIPE_FORMAT_X8Z24_UNORM, {24, 0} }, + { PIPE_FORMAT_Z16_UNORM, {16, 0} }, + /* pure stencil */ + { PIPE_FORMAT_S8_UNORM, { 0, 8} }, + /* combined depth-stencil */ + { PIPE_FORMAT_S8Z24_UNORM, {24, 8} }, + { PIPE_FORMAT_Z24S8_UNORM, {24, 8} } +}; + + +static const boolean +stw_pf_doublebuffer[] = { + FALSE, + TRUE, +}; + + +const unsigned +stw_pf_multisample[] = { + 0, + 4 +}; + + +static void +stw_pixelformat_add( + struct stw_device *stw_dev, + const struct stw_pf_color_info *color, + const struct stw_pf_depth_info *depth, + unsigned accum, + boolean doublebuffer, + unsigned samples ) +{ + boolean extended = FALSE; + struct stw_pixelformat_info *pfi; + + assert(stw_dev->pixelformat_extended_count < STW_MAX_PIXELFORMATS); + if(stw_dev->pixelformat_extended_count >= STW_MAX_PIXELFORMATS) + return; + + assert(pf_layout( color->format ) == PIPE_FORMAT_LAYOUT_RGBAZS ); + assert(pf_get_component_bits( color->format, PIPE_FORMAT_COMP_R ) == color->bits.red ); + assert(pf_get_component_bits( color->format, PIPE_FORMAT_COMP_G ) == color->bits.green ); + assert(pf_get_component_bits( color->format, PIPE_FORMAT_COMP_B ) == color->bits.blue ); + assert(pf_get_component_bits( color->format, PIPE_FORMAT_COMP_A ) == color->bits.alpha ); + assert(pf_layout( depth->format ) == PIPE_FORMAT_LAYOUT_RGBAZS ); + assert(pf_get_component_bits( depth->format, PIPE_FORMAT_COMP_Z ) == depth->bits.depth ); + assert(pf_get_component_bits( depth->format, PIPE_FORMAT_COMP_S ) == depth->bits.stencil ); + + pfi = &stw_dev->pixelformats[stw_dev->pixelformat_extended_count]; + + memset(pfi, 0, sizeof *pfi); + + pfi->color_format = color->format; + pfi->depth_stencil_format = depth->format; + + pfi->pfd.nSize = sizeof pfi->pfd; + pfi->pfd.nVersion = 1; + + pfi->pfd.dwFlags = PFD_SUPPORT_OPENGL; + + /* TODO: also support non-native pixel formats */ + pfi->pfd.dwFlags |= PFD_DRAW_TO_WINDOW ; + + if (doublebuffer) + pfi->pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SWAP_COPY; + + pfi->pfd.iPixelType = PFD_TYPE_RGBA; + + pfi->pfd.cColorBits = color->bits.red + color->bits.green + color->bits.blue + color->bits.alpha; + pfi->pfd.cRedBits = color->bits.red; + pfi->pfd.cRedShift = color->shift.red; + pfi->pfd.cGreenBits = color->bits.green; + pfi->pfd.cGreenShift = color->shift.green; + pfi->pfd.cBlueBits = color->bits.blue; + pfi->pfd.cBlueShift = color->shift.blue; + pfi->pfd.cAlphaBits = color->bits.alpha; + pfi->pfd.cAlphaShift = color->shift.alpha; + pfi->pfd.cAccumBits = 4*accum; + pfi->pfd.cAccumRedBits = accum; + pfi->pfd.cAccumGreenBits = accum; + pfi->pfd.cAccumBlueBits = accum; + pfi->pfd.cAccumAlphaBits = accum; + pfi->pfd.cDepthBits = depth->bits.depth; + pfi->pfd.cStencilBits = depth->bits.stencil; + pfi->pfd.cAuxBuffers = 0; + pfi->pfd.iLayerType = 0; + pfi->pfd.bReserved = 0; + pfi->pfd.dwLayerMask = 0; + pfi->pfd.dwVisibleMask = 0; + pfi->pfd.dwDamageMask = 0; + + if(samples) { + pfi->numSampleBuffers = 1; + pfi->numSamples = samples; + extended = TRUE; + } + + ++stw_dev->pixelformat_extended_count; + + if(!extended) { + ++stw_dev->pixelformat_count; + assert(stw_dev->pixelformat_count == stw_dev->pixelformat_extended_count); + } +} + +void +stw_pixelformat_init( void ) +{ + struct pipe_screen *screen = stw_dev->screen; + unsigned i, j, k, l; + + assert( !stw_dev->pixelformat_count ); + assert( !stw_dev->pixelformat_extended_count ); + + for(i = 0; i < Elements(stw_pf_multisample); ++i) { + unsigned samples = stw_pf_multisample[i]; + + /* FIXME: re-enabled MSAA when we can query it */ + if(samples) + continue; + + for(j = 0; j < Elements(stw_pf_color); ++j) { + const struct stw_pf_color_info *color = &stw_pf_color[j]; + + if(!screen->is_format_supported(screen, color->format, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) + continue; + + for(k = 0; k < Elements(stw_pf_doublebuffer); ++k) { + unsigned doublebuffer = stw_pf_doublebuffer[k]; + + for(l = 0; l < Elements(stw_pf_depth_stencil); ++l) { + const struct stw_pf_depth_info *depth = &stw_pf_depth_stencil[l]; + + if(!screen->is_format_supported(screen, depth->format, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0)) + continue; + + stw_pixelformat_add( stw_dev, color, depth, 0, doublebuffer, samples ); + stw_pixelformat_add( stw_dev, color, depth, 16, doublebuffer, samples ); + } + } + } + } + + assert( stw_dev->pixelformat_count <= stw_dev->pixelformat_extended_count ); + assert( stw_dev->pixelformat_extended_count <= STW_MAX_PIXELFORMATS ); +} + +uint +stw_pixelformat_get_count( void ) +{ + return stw_dev->pixelformat_count; +} + +uint +stw_pixelformat_get_extended_count( void ) +{ + return stw_dev->pixelformat_extended_count; +} + +const struct stw_pixelformat_info * +stw_pixelformat_get_info( uint index ) +{ + assert( index < stw_dev->pixelformat_extended_count ); + + return &stw_dev->pixelformats[index]; +} + + +void +stw_pixelformat_visual(GLvisual *visual, + const struct stw_pixelformat_info *pfi ) +{ + memset(visual, 0, sizeof *visual); + _mesa_initialize_visual( + visual, + (pfi->pfd.iPixelType == PFD_TYPE_RGBA) ? GL_TRUE : GL_FALSE, + (pfi->pfd.dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE, + (pfi->pfd.dwFlags & PFD_STEREO) ? GL_TRUE : GL_FALSE, + pfi->pfd.cRedBits, + pfi->pfd.cGreenBits, + pfi->pfd.cBlueBits, + pfi->pfd.cAlphaBits, + (pfi->pfd.iPixelType == PFD_TYPE_COLORINDEX) ? pfi->pfd.cColorBits : 0, + pfi->pfd.cDepthBits, + pfi->pfd.cStencilBits, + pfi->pfd.cAccumRedBits, + pfi->pfd.cAccumGreenBits, + pfi->pfd.cAccumBlueBits, + pfi->pfd.cAccumAlphaBits, + pfi->numSamples ); +} + + +int +stw_pixelformat_describe( + HDC hdc, + int iPixelFormat, + UINT nBytes, + LPPIXELFORMATDESCRIPTOR ppfd ) +{ + uint count; + uint index; + const struct stw_pixelformat_info *pfi; + + (void) hdc; + + count = stw_pixelformat_get_extended_count(); + index = (uint) iPixelFormat - 1; + + if (ppfd == NULL) + return count; + if (index >= count || nBytes != sizeof( PIXELFORMATDESCRIPTOR )) + return 0; + + pfi = stw_pixelformat_get_info( index ); + + memcpy(ppfd, &pfi->pfd, sizeof( PIXELFORMATDESCRIPTOR )); + + return count; +} + +/* Only used by the wgl code, but have it here to avoid exporting the + * pixelformat.h functionality. + */ +int stw_pixelformat_choose( HDC hdc, + CONST PIXELFORMATDESCRIPTOR *ppfd ) +{ + uint count; + uint index; + uint bestindex; + uint bestdelta; + + (void) hdc; + + count = stw_pixelformat_get_count(); + bestindex = count; + bestdelta = ~0U; + + for (index = 0; index < count; index++) { + uint delta = 0; + const struct stw_pixelformat_info *pfi = stw_pixelformat_get_info( index ); + + if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE) && + !!(ppfd->dwFlags & PFD_DOUBLEBUFFER) != + !!(pfi->pfd.dwFlags & PFD_DOUBLEBUFFER)) + continue; + + /* FIXME: Take in account individual channel bits */ + if (ppfd->cColorBits != pfi->pfd.cColorBits) + delta += 8; + + if (ppfd->cDepthBits != pfi->pfd.cDepthBits) + delta += 4; + + if (ppfd->cStencilBits != pfi->pfd.cStencilBits) + delta += 2; + + if (ppfd->cAlphaBits != pfi->pfd.cAlphaBits) + delta++; + + if (delta < bestdelta) { + bestindex = index; + bestdelta = delta; + if (bestdelta == 0) + break; + } + } + + if (bestindex == count) + return 0; + + return bestindex + 1; +} diff --git a/src/gallium/state_trackers/wgl/shared/stw_pixelformat.h b/src/gallium/state_trackers/wgl/shared/stw_pixelformat.h new file mode 100644 index 0000000000..bec429231b --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_pixelformat.h @@ -0,0 +1,65 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STW_PIXELFORMAT_H +#define STW_PIXELFORMAT_H + +#include <windows.h> + +#include "main/mtypes.h" + +#include "pipe/p_compiler.h" +#include "pipe/p_format.h" + +struct stw_pixelformat_info +{ + enum pipe_format color_format; + enum pipe_format depth_stencil_format; + + PIXELFORMATDESCRIPTOR pfd; + + unsigned numSampleBuffers; + unsigned numSamples; +}; + +void +stw_pixelformat_init( void ); + +uint +stw_pixelformat_get_count( void ); + +uint +stw_pixelformat_get_extended_count( void ); + +const struct stw_pixelformat_info * +stw_pixelformat_get_info( uint index ); + +void +stw_pixelformat_visual(GLvisual *visual, + const struct stw_pixelformat_info *pfi ); + +#endif /* STW_PIXELFORMAT_H */ diff --git a/src/gallium/state_trackers/wgl/shared/stw_public.h b/src/gallium/state_trackers/wgl/shared/stw_public.h new file mode 100644 index 0000000000..7fe9cfb356 --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_public.h @@ -0,0 +1,73 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STW_PUBLIC_H +#define STW_PUBLIC_H + +#include <windows.h> + +BOOL stw_copy_context( UINT_PTR hglrcSrc, + UINT_PTR hglrcDst, + UINT mask ); + +UINT_PTR stw_create_layer_context( HDC hdc, + int iLayerPlane ); + +BOOL stw_share_lists( UINT_PTR hglrc1, UINT_PTR hglrc2 ); + +BOOL stw_delete_context( UINT_PTR hglrc ); + +BOOL +stw_release_context( UINT_PTR dhglrc ); + +UINT_PTR stw_get_current_context( void ); + +HDC stw_get_current_dc( void ); + +BOOL stw_make_current( HDC hdc, UINT_PTR hglrc ); + +BOOL stw_swap_buffers( HDC hdc ); + +BOOL +stw_swap_layer_buffers( HDC hdc, UINT fuPlanes ); + +PROC stw_get_proc_address( LPCSTR lpszProc ); + +int stw_pixelformat_describe( HDC hdc, + int iPixelFormat, + UINT nBytes, + LPPIXELFORMATDESCRIPTOR ppfd ); + +int stw_pixelformat_get( HDC hdc ); + +BOOL stw_pixelformat_set( HDC hdc, + int iPixelFormat ); + +int stw_pixelformat_choose( HDC hdc, + CONST PIXELFORMATDESCRIPTOR *ppfd ); + +#endif diff --git a/src/gallium/state_trackers/wgl/shared/stw_tls.c b/src/gallium/state_trackers/wgl/shared/stw_tls.c new file mode 100644 index 0000000000..4bd6a9289c --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_tls.c @@ -0,0 +1,139 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <windows.h> + +#include "pipe/p_compiler.h" +#include "util/u_memory.h" +#include "stw_tls.h" + +static DWORD tlsIndex = TLS_OUT_OF_INDEXES; + +boolean +stw_tls_init(void) +{ + tlsIndex = TlsAlloc(); + if (tlsIndex == TLS_OUT_OF_INDEXES) { + return FALSE; + } + + return TRUE; +} + +static INLINE struct stw_tls_data * +stw_tls_data_create() +{ + struct stw_tls_data *data; + + data = CALLOC_STRUCT(stw_tls_data); + if (!data) + goto no_data; + + data->hCallWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, + stw_call_window_proc, + NULL, + GetCurrentThreadId()); + if(data->hCallWndProcHook == NULL) + goto no_hook; + + TlsSetValue(tlsIndex, data); + + return data; + +no_hook: + FREE(data); +no_data: + return NULL; +} + +boolean +stw_tls_init_thread(void) +{ + struct stw_tls_data *data; + + if (tlsIndex == TLS_OUT_OF_INDEXES) { + return FALSE; + } + + data = stw_tls_data_create(); + if(!data) + return FALSE; + + return TRUE; +} + +void +stw_tls_cleanup_thread(void) +{ + struct stw_tls_data *data; + + if (tlsIndex == TLS_OUT_OF_INDEXES) { + return; + } + + data = (struct stw_tls_data *) TlsGetValue(tlsIndex); + if(data) { + TlsSetValue(tlsIndex, NULL); + + if(data->hCallWndProcHook) { + UnhookWindowsHookEx(data->hCallWndProcHook); + data->hCallWndProcHook = NULL; + } + + FREE(data); + } +} + +void +stw_tls_cleanup(void) +{ + if (tlsIndex != TLS_OUT_OF_INDEXES) { + TlsFree(tlsIndex); + tlsIndex = TLS_OUT_OF_INDEXES; + } +} + +struct stw_tls_data * +stw_tls_get_data(void) +{ + struct stw_tls_data *data; + + if (tlsIndex == TLS_OUT_OF_INDEXES) { + return NULL; + } + + data = (struct stw_tls_data *) TlsGetValue(tlsIndex); + if(!data) { + /* DllMain is called with DLL_THREAD_ATTACH only by threads created after + * the DLL is loaded by the process */ + data = stw_tls_data_create(); + if(!data) + return NULL; + } + + return data; +} diff --git a/src/gallium/state_trackers/wgl/shared/stw_tls.h b/src/gallium/state_trackers/wgl/shared/stw_tls.h new file mode 100644 index 0000000000..fbf8b1cbee --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_tls.h @@ -0,0 +1,59 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STW_TLS_H +#define STW_TLS_H + +#include <windows.h> + +struct stw_tls_data +{ + HHOOK hCallWndProcHook; +}; + +boolean +stw_tls_init(void); + +boolean +stw_tls_init_thread(void); + +void +stw_tls_cleanup_thread(void); + +void +stw_tls_cleanup(void); + +struct stw_tls_data * +stw_tls_get_data(void); + +LRESULT CALLBACK +stw_call_window_proc( + int nCode, + WPARAM wParam, + LPARAM lParam ); + +#endif /* STW_TLS_H */ diff --git a/src/gallium/state_trackers/wgl/shared/stw_winsys.h b/src/gallium/state_trackers/wgl/shared/stw_winsys.h new file mode 100644 index 0000000000..c0bf82c9ed --- /dev/null +++ b/src/gallium/state_trackers/wgl/shared/stw_winsys.h @@ -0,0 +1,65 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STW_WINSYS_H +#define STW_WINSYS_H + +#include <windows.h> /* for HDC */ + +#include "pipe/p_compiler.h" + +struct pipe_screen; +struct pipe_context; +struct pipe_surface; + +struct stw_winsys +{ + struct pipe_screen * + (*create_screen)( void ); + + struct pipe_context * + (*create_context)( struct pipe_screen *screen ); + + void + (*flush_frontbuffer)( struct pipe_screen *screen, + struct pipe_surface *surf, + HDC hDC ); +}; + +boolean +stw_init(const struct stw_winsys *stw_winsys); + +boolean +stw_init_thread(void); + +void +stw_cleanup_thread(void); + +void +stw_cleanup(void); + +#endif /* STW_WINSYS_H */ diff --git a/src/gallium/state_trackers/wgl/wgl/stw_wgl.c b/src/gallium/state_trackers/wgl/wgl/stw_wgl.c new file mode 100644 index 0000000000..a131292f7a --- /dev/null +++ b/src/gallium/state_trackers/wgl/wgl/stw_wgl.c @@ -0,0 +1,329 @@ +/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <windows.h> + +#include "util/u_debug.h" +#include "shared/stw_public.h" +#include "stw_wgl.h" + + +WINGDIAPI BOOL APIENTRY +wglCopyContext( + HGLRC hglrcSrc, + HGLRC hglrcDst, + UINT mask ) +{ + return stw_copy_context( (UINT_PTR)hglrcSrc, + (UINT_PTR)hglrcDst, + mask ); +} + +WINGDIAPI HGLRC APIENTRY +wglCreateContext( + HDC hdc ) +{ + return wglCreateLayerContext(hdc, 0); +} + +WINGDIAPI HGLRC APIENTRY +wglCreateLayerContext( + HDC hdc, + int iLayerPlane ) +{ + return (HGLRC) stw_create_layer_context( hdc, iLayerPlane ); +} + +WINGDIAPI BOOL APIENTRY +wglDeleteContext( + HGLRC hglrc ) +{ + return stw_delete_context( (UINT_PTR)hglrc ); +} + + +WINGDIAPI HGLRC APIENTRY +wglGetCurrentContext( VOID ) +{ + return (HGLRC)stw_get_current_context(); +} + +WINGDIAPI HDC APIENTRY +wglGetCurrentDC( VOID ) +{ + return stw_get_current_dc(); +} + +WINGDIAPI BOOL APIENTRY +wglMakeCurrent( + HDC hdc, + HGLRC hglrc ) +{ + return stw_make_current( hdc, (UINT_PTR)hglrc ); +} + + +WINGDIAPI BOOL APIENTRY +wglSwapBuffers( + HDC hdc ) +{ + return stw_swap_buffers( hdc ); +} + + +WINGDIAPI BOOL APIENTRY +wglSwapLayerBuffers( + HDC hdc, + UINT fuPlanes ) +{ + return stw_swap_layer_buffers( hdc, fuPlanes ); +} + +WINGDIAPI PROC APIENTRY +wglGetProcAddress( + LPCSTR lpszProc ) +{ + return stw_get_proc_address( lpszProc ); +} + + +WINGDIAPI int APIENTRY +wglChoosePixelFormat( + HDC hdc, + CONST PIXELFORMATDESCRIPTOR *ppfd ) +{ + if (ppfd->nSize != sizeof( PIXELFORMATDESCRIPTOR ) || ppfd->nVersion != 1) + return 0; + if (ppfd->iPixelType != PFD_TYPE_RGBA) + return 0; + if (!(ppfd->dwFlags & PFD_DRAW_TO_WINDOW)) + return 0; + if (!(ppfd->dwFlags & PFD_SUPPORT_OPENGL)) + return 0; + if (ppfd->dwFlags & PFD_DRAW_TO_BITMAP) + return 0; + if (ppfd->dwFlags & PFD_SUPPORT_GDI) + return 0; + if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE) && (ppfd->dwFlags & PFD_STEREO)) + return 0; + + return stw_pixelformat_choose( hdc, ppfd ); +} + +WINGDIAPI int APIENTRY +wglDescribePixelFormat( + HDC hdc, + int iPixelFormat, + UINT nBytes, + LPPIXELFORMATDESCRIPTOR ppfd ) +{ + return stw_pixelformat_describe( hdc, iPixelFormat, nBytes, ppfd ); +} + +WINGDIAPI int APIENTRY +wglGetPixelFormat( + HDC hdc ) +{ + return stw_pixelformat_get( hdc ); +} + +WINGDIAPI BOOL APIENTRY +wglSetPixelFormat( + HDC hdc, + int iPixelFormat, + const PIXELFORMATDESCRIPTOR *ppfd ) +{ + if (ppfd->nSize != sizeof( PIXELFORMATDESCRIPTOR )) + return FALSE; + + return stw_pixelformat_set( hdc, iPixelFormat ); +} + + +WINGDIAPI BOOL APIENTRY +wglUseFontBitmapsA( + HDC hdc, + DWORD first, + DWORD count, + DWORD listBase ) +{ + (void) hdc; + (void) first; + (void) count; + (void) listBase; + + assert( 0 ); + + return FALSE; +} + +WINGDIAPI BOOL APIENTRY +wglShareLists( + HGLRC hglrc1, + HGLRC hglrc2 ) +{ + return stw_share_lists( (UINT_PTR)hglrc1, (UINT_PTR)hglrc2);; +} + +WINGDIAPI BOOL APIENTRY +wglUseFontBitmapsW( + HDC hdc, + DWORD first, + DWORD count, + DWORD listBase ) +{ + (void) hdc; + (void) first; + (void) count; + (void) listBase; + + assert( 0 ); + + return FALSE; +} + +WINGDIAPI BOOL APIENTRY +wglUseFontOutlinesA( + HDC hdc, + DWORD first, + DWORD count, + DWORD listBase, + FLOAT deviation, + FLOAT extrusion, + int format, + LPGLYPHMETRICSFLOAT lpgmf ) +{ + (void) hdc; + (void) first; + (void) count; + (void) listBase; + (void) deviation; + (void) extrusion; + (void) format; + (void) lpgmf; + + assert( 0 ); + + return FALSE; +} + +WINGDIAPI BOOL APIENTRY +wglUseFontOutlinesW( + HDC hdc, + DWORD first, + DWORD count, + DWORD listBase, + FLOAT deviation, + FLOAT extrusion, + int format, + LPGLYPHMETRICSFLOAT lpgmf ) +{ + (void) hdc; + (void) first; + (void) count; + (void) listBase; + (void) deviation; + (void) extrusion; + (void) format; + (void) lpgmf; + + assert( 0 ); + + return FALSE; +} + +WINGDIAPI BOOL APIENTRY +wglDescribeLayerPlane( + HDC hdc, + int iPixelFormat, + int iLayerPlane, + UINT nBytes, + LPLAYERPLANEDESCRIPTOR plpd ) +{ + (void) hdc; + (void) iPixelFormat; + (void) iLayerPlane; + (void) nBytes; + (void) plpd; + + assert( 0 ); + + return FALSE; +} + +WINGDIAPI int APIENTRY +wglSetLayerPaletteEntries( + HDC hdc, + int iLayerPlane, + int iStart, + int cEntries, + CONST COLORREF *pcr ) +{ + (void) hdc; + (void) iLayerPlane; + (void) iStart; + (void) cEntries; + (void) pcr; + + assert( 0 ); + + return 0; +} + +WINGDIAPI int APIENTRY +wglGetLayerPaletteEntries( + HDC hdc, + int iLayerPlane, + int iStart, + int cEntries, + COLORREF *pcr ) +{ + (void) hdc; + (void) iLayerPlane; + (void) iStart; + (void) cEntries; + (void) pcr; + + assert( 0 ); + + return 0; +} + +WINGDIAPI BOOL APIENTRY +wglRealizeLayerPalette( + HDC hdc, + int iLayerPlane, + BOOL bRealize ) +{ + (void) hdc; + (void) iLayerPlane; + (void) bRealize; + + assert( 0 ); + + return FALSE; +} diff --git a/src/gallium/state_trackers/wgl/wgl/stw_wgl.h b/src/gallium/state_trackers/wgl/wgl/stw_wgl.h new file mode 100644 index 0000000000..a98179944a --- /dev/null +++ b/src/gallium/state_trackers/wgl/wgl/stw_wgl.h @@ -0,0 +1,63 @@ +/************************************************************************** + * + * Copyright 2009 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#ifndef STW_WGL_H_ +#define STW_WGL_H_ + + +#include <windows.h> + +#include <GL/gl.h> + + +/* + * Undeclared APIs exported by opengl32.dll + */ + +WINGDIAPI BOOL WINAPI +wglSwapBuffers(HDC hdc); + +WINGDIAPI int WINAPI +wglChoosePixelFormat(HDC hdc, + CONST PIXELFORMATDESCRIPTOR *ppfd); + +WINGDIAPI int WINAPI +wglDescribePixelFormat(HDC hdc, + int iPixelFormat, + UINT nBytes, + LPPIXELFORMATDESCRIPTOR ppfd); + +WINGDIAPI int WINAPI +wglGetPixelFormat(HDC hdc); + +WINGDIAPI BOOL WINAPI +wglSetPixelFormat(HDC hdc, + int iPixelFormat, + CONST PIXELFORMATDESCRIPTOR *ppfd); + + +#endif /* STW_WGL_H_ */ diff --git a/src/gallium/state_trackers/xorg/Makefile b/src/gallium/state_trackers/xorg/Makefile new file mode 100644 index 0000000000..27a1990724 --- /dev/null +++ b/src/gallium/state_trackers/xorg/Makefile @@ -0,0 +1,18 @@ +TOP = ../../../.. +include $(TOP)/configs/current + +LIBNAME = xorgtracker + +LIBRARY_INCLUDES = \ + -DHAVE_CONFIG_H \ + $(shell pkg-config --cflags-only-I pixman-1 xorg-server libdrm xproto) \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/include \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/mesa/drivers/dri/common \ + -I$(TOP)/src/mesa/main + +C_SOURCES = $(wildcard ./*.c) + +include ../../Makefile.template diff --git a/src/gallium/state_trackers/xorg/SConscript b/src/gallium/state_trackers/xorg/SConscript new file mode 100644 index 0000000000..65f55ea378 --- /dev/null +++ b/src/gallium/state_trackers/xorg/SConscript @@ -0,0 +1,27 @@ +####################################################################### +# SConscript for xorg state_tracker + +Import('*') + +if 'xorg' in env['statetrackers']: + + env = env.Clone() + + env.Append(CPPPATH = [ + '#/src/mesa', + ]) + + env.ParseConfig('pkg-config --cflags --libs xorg-server') + + st_xorg = env.ConvenienceLibrary( + target = 'st_xorg', + source = [ 'xorg_composite.c', + 'xorg_crtc.c', + 'xorg_dri2.c', + 'xorg_driver.c', + 'xorg_exa.c', + 'xorg_exa_tgsi.c', + 'xorg_output.c', + ] + ) + Export('st_xorg') diff --git a/src/gallium/state_trackers/xorg/xorg_composite.c b/src/gallium/state_trackers/xorg/xorg_composite.c new file mode 100644 index 0000000000..15c955450d --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_composite.c @@ -0,0 +1,1019 @@ +#include "xorg_composite.h" + +#include "xorg_exa_tgsi.h" + +#include "cso_cache/cso_context.h" +#include "util/u_draw_quad.h" +#include "util/u_math.h" + +#include "pipe/p_inlines.h" + +struct xorg_composite_blend { + int op:8; + + unsigned rgb_src_factor:5; /**< PIPE_BLENDFACTOR_x */ + unsigned rgb_dst_factor:5; /**< PIPE_BLENDFACTOR_x */ + + unsigned alpha_src_factor:5; /**< PIPE_BLENDFACTOR_x */ + unsigned alpha_dst_factor:5; /**< PIPE_BLENDFACTOR_x */ +}; + +#define BLEND_OP_OVER 3 +static const struct xorg_composite_blend xorg_blends[] = { + { PictOpClear, + PIPE_BLENDFACTOR_CONST_COLOR, PIPE_BLENDFACTOR_CONST_ALPHA, + PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO }, + + { PictOpSrc, + PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE, + PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO }, + + { PictOpDst, + PIPE_BLENDFACTOR_ZERO, PIPE_BLENDFACTOR_ZERO, + PIPE_BLENDFACTOR_ONE, PIPE_BLENDFACTOR_ONE }, + + { PictOpOver, + PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE, + PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA }, + + { PictOpOverReverse, + PIPE_BLENDFACTOR_SRC_ALPHA, PIPE_BLENDFACTOR_ONE, + PIPE_BLENDFACTOR_INV_SRC_ALPHA, PIPE_BLENDFACTOR_INV_SRC_ALPHA }, +}; + + +static INLINE void +pixel_to_float4(Pixel pixel, float *color) +{ + CARD32 r, g, b, a; + + a = (pixel >> 24) & 0xff; + r = (pixel >> 16) & 0xff; + g = (pixel >> 8) & 0xff; + b = (pixel >> 0) & 0xff; + color[0] = ((float)r) / 255.; + color[1] = ((float)g) / 255.; + color[2] = ((float)b) / 255.; + color[3] = ((float)a) / 255.; +} + +static INLINE void +render_pixel_to_float4(PictFormatPtr format, + CARD32 pixel, float *color) +{ + CARD32 r, g, b, a; + + debug_assert(format->type == PictTypeDirect); + + r = (pixel >> format->direct.red) & format->direct.redMask; + g = (pixel >> format->direct.green) & format->direct.greenMask; + b = (pixel >> format->direct.blue) & format->direct.blueMask; + a = (pixel >> format->direct.alpha) & format->direct.alphaMask; + color[0] = ((float)r) / ((float)format->direct.redMask); + color[1] = ((float)g) / ((float)format->direct.greenMask); + color[2] = ((float)b) / ((float)format->direct.blueMask); + color[3] = ((float)a) / ((float)format->direct.alphaMask); +} + +struct acceleration_info { + int op : 16; + int with_mask : 1; + int component_alpha : 1; +}; +static const struct acceleration_info accelerated_ops[] = { + {PictOpClear, 1, 0}, + {PictOpSrc, 1, 0}, + {PictOpDst, 1, 0}, + {PictOpOver, 1, 0}, + {PictOpOverReverse, 1, 0}, + {PictOpIn, 1, 0}, + {PictOpInReverse, 1, 0}, + {PictOpOut, 1, 0}, + {PictOpOutReverse, 1, 0}, + {PictOpAtop, 1, 0}, + {PictOpAtopReverse, 1, 0}, + {PictOpXor, 1, 0}, + {PictOpAdd, 1, 0}, + {PictOpSaturate, 1, 0}, +}; + +static struct xorg_composite_blend +blend_for_op(int op) +{ + const int num_blends = + sizeof(xorg_blends)/sizeof(struct xorg_composite_blend); + int i; + + for (i = 0; i < num_blends; ++i) { + if (xorg_blends[i].op == op) + return xorg_blends[i]; + } + return xorg_blends[BLEND_OP_OVER]; +} + +static INLINE int +render_repeat_to_gallium(int mode) +{ + switch(mode) { + case RepeatNone: + return PIPE_TEX_WRAP_CLAMP; + case RepeatNormal: + return PIPE_TEX_WRAP_REPEAT; + case RepeatReflect: + return PIPE_TEX_WRAP_MIRROR_REPEAT; + case RepeatPad: + return PIPE_TEX_WRAP_CLAMP_TO_EDGE; + default: + debug_printf("Unsupported repeat mode\n"); + } + return PIPE_TEX_WRAP_REPEAT; +} + + +static INLINE void +setup_vertex0(float vertex[2][4], float x, float y, + float color[4]) +{ + vertex[0][0] = x; + vertex[0][1] = y; + vertex[0][2] = 0.f; /*z*/ + vertex[0][3] = 1.f; /*w*/ + + vertex[1][0] = color[0]; /*r*/ + vertex[1][1] = color[1]; /*g*/ + vertex[1][2] = color[2]; /*b*/ + vertex[1][3] = color[3]; /*a*/ +} + +static struct pipe_buffer * +setup_vertex_data0(struct exa_context *ctx, + int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height) +{ + float vertices[4][2][4]; + + /* 1st vertex */ + setup_vertex0(vertices[0], dstX, dstY, + ctx->solid_color); + /* 2nd vertex */ + setup_vertex0(vertices[1], dstX + width, dstY, + ctx->solid_color); + /* 3rd vertex */ + setup_vertex0(vertices[2], dstX + width, dstY + height, + ctx->solid_color); + /* 4th vertex */ + setup_vertex0(vertices[3], dstX, dstY + height, + ctx->solid_color); + + return pipe_user_buffer_create(ctx->pipe->screen, + vertices, + sizeof(vertices)); +} + +static INLINE void +setup_vertex1(float vertex[2][4], float x, float y, float s, float t) +{ + vertex[0][0] = x; + vertex[0][1] = y; + vertex[0][2] = 0.f; /*z*/ + vertex[0][3] = 1.f; /*w*/ + + vertex[1][0] = s; /*s*/ + vertex[1][1] = t; /*t*/ + vertex[1][2] = 0.f; /*r*/ + vertex[1][3] = 1.f; /*q*/ +} + +static struct pipe_buffer * +setup_vertex_data1(struct exa_context *ctx, + int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height) +{ + float vertices[4][2][4]; + float s0, t0, s1, t1; + struct pipe_texture *src = ctx->bound_textures[0]; + + s0 = srcX / src->width[0]; + s1 = srcX + width / src->width[0]; + t0 = srcY / src->height[0]; + t1 = srcY + height / src->height[0]; + + /* 1st vertex */ + setup_vertex1(vertices[0], dstX, dstY, + s0, t0); + /* 2nd vertex */ + setup_vertex1(vertices[1], dstX + width, dstY, + s1, t0); + /* 3rd vertex */ + setup_vertex1(vertices[2], dstX + width, dstY + height, + s1, t1); + /* 4th vertex */ + setup_vertex1(vertices[3], dstX, dstY + height, + s0, t1); + + return pipe_user_buffer_create(ctx->pipe->screen, + vertices, + sizeof(vertices)); +} + +static struct pipe_buffer * +setup_vertex_data_tex(struct exa_context *ctx, + float x0, float y0, float x1, float y1, + float s0, float t0, float s1, float t1, + float z) +{ + float vertices[4][2][4]; + + /* 1st vertex */ + setup_vertex1(vertices[0], x0, y0, + s0, t0); + /* 2nd vertex */ + setup_vertex1(vertices[1], x1, y0, + s1, t0); + /* 3rd vertex */ + setup_vertex1(vertices[2], x1, y1, + s1, t1); + /* 4th vertex */ + setup_vertex1(vertices[3], x0, y1, + s0, t1); + + return pipe_user_buffer_create(ctx->pipe->screen, + vertices, + sizeof(vertices)); +} + + + +static INLINE void +setup_vertex2(float vertex[3][4], float x, float y, + float s0, float t0, float s1, float t1) +{ + vertex[0][0] = x; + vertex[0][1] = y; + vertex[0][2] = 0.f; /*z*/ + vertex[0][3] = 1.f; /*w*/ + + vertex[1][0] = s0; /*s*/ + vertex[1][1] = t0; /*t*/ + vertex[1][2] = 0.f; /*r*/ + vertex[1][3] = 1.f; /*q*/ + + vertex[2][0] = s1; /*s*/ + vertex[2][1] = t1; /*t*/ + vertex[2][2] = 0.f; /*r*/ + vertex[2][3] = 1.f; /*q*/ +} + +static struct pipe_buffer * +setup_vertex_data2(struct exa_context *ctx, + int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height) +{ + float vertices[4][3][4]; + float st0[4], st1[4]; + struct pipe_texture *src = ctx->bound_textures[0]; + struct pipe_texture *mask = ctx->bound_textures[0]; + + st0[0] = srcX / src->width[0]; + st0[1] = srcY / src->height[0]; + st0[2] = srcX + width / src->width[0]; + st0[3] = srcY + height / src->height[0]; + + st1[0] = maskX / mask->width[0]; + st1[1] = maskY / mask->height[0]; + st1[2] = maskX + width / mask->width[0]; + st1[3] = maskY + height / mask->height[0]; + + /* 1st vertex */ + setup_vertex2(vertices[0], dstX, dstY, + st0[0], st0[1], st1[0], st1[1]); + /* 2nd vertex */ + setup_vertex2(vertices[1], dstX + width, dstY, + st0[2], st0[1], st1[2], st1[1]); + /* 3rd vertex */ + setup_vertex2(vertices[2], dstX + width, dstY + height, + st0[2], st0[3], st1[2], st1[3]); + /* 4th vertex */ + setup_vertex2(vertices[3], dstX, dstY + height, + st0[0], st0[3], st1[0], st1[3]); + + return pipe_user_buffer_create(ctx->pipe->screen, + vertices, + sizeof(vertices)); +} + +boolean xorg_composite_accelerated(int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + unsigned i; + unsigned accel_ops_count = + sizeof(accelerated_ops)/sizeof(struct acceleration_info); + + + /*FIXME: currently accel is disabled */ + return FALSE; + + if (pSrcPicture) { + /* component alpha not supported */ + if (pSrcPicture->componentAlpha) + return FALSE; + /* fills not supported */ + if (pSrcPicture->pSourcePict) + return FALSE; + } + + for (i = 0; i < accel_ops_count; ++i) { + if (op == accelerated_ops[i].op) { + if (pMaskPicture && !accelerated_ops[i].with_mask) + return FALSE; + return TRUE; + } + } + return FALSE; +} + +static void +bind_clip_state(struct exa_context *exa) +{ +} + +static void +bind_framebuffer_state(struct exa_context *exa, struct exa_pixmap_priv *pDst) +{ + unsigned i; + struct pipe_framebuffer_state state; + struct pipe_surface *surface = exa_gpu_surface(exa, pDst); + memset(&state, 0, sizeof(struct pipe_framebuffer_state)); + + state.width = pDst->tex->width[0]; + state.height = pDst->tex->height[0]; + + state.nr_cbufs = 1; + state.cbufs[0] = surface; + for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) + state.cbufs[i] = 0; + + /* currently we don't use depth/stencil */ + state.zsbuf = 0; + + cso_set_framebuffer(exa->cso, &state); +} + +enum AxisOrientation { + Y0_BOTTOM, + Y0_TOP +}; + +static void +set_viewport(struct exa_context *exa, int width, int height, + enum AxisOrientation orientation) +{ + struct pipe_viewport_state viewport; + float y_scale = (orientation == Y0_BOTTOM) ? -2.f : 2.f; + + viewport.scale[0] = width / 2.f; + viewport.scale[1] = height / y_scale; + viewport.scale[2] = 1.0; + viewport.scale[3] = 1.0; + viewport.translate[0] = width / 2.f; + viewport.translate[1] = height / 2.f; + viewport.translate[2] = 0.0; + viewport.translate[3] = 0.0; + + cso_set_viewport(exa->cso, &viewport); +} + +static void +bind_viewport_state(struct exa_context *exa, struct exa_pixmap_priv *pDst) +{ + int width = pDst->tex->width[0]; + int height = pDst->tex->height[0]; + + debug_printf("Bind viewport (%d, %d)\n", width, height); + + set_viewport(exa, width, height, Y0_TOP); +} + +static void +bind_blend_state(struct exa_context *exa, int op, + PicturePtr pSrcPicture, PicturePtr pMaskPicture) +{ + boolean component_alpha = (pSrcPicture) ? + pSrcPicture->componentAlpha : FALSE; + struct xorg_composite_blend blend_opt; + struct pipe_blend_state blend; + + if (component_alpha) { + op = PictOpOver; + } + blend_opt = blend_for_op(op); + + memset(&blend, 0, sizeof(struct pipe_blend_state)); + blend.blend_enable = 1; + blend.colormask |= PIPE_MASK_R; + blend.colormask |= PIPE_MASK_G; + blend.colormask |= PIPE_MASK_B; + blend.colormask |= PIPE_MASK_A; + + blend.rgb_src_factor = blend_opt.rgb_src_factor; + blend.alpha_src_factor = blend_opt.alpha_src_factor; + blend.rgb_dst_factor = blend_opt.rgb_dst_factor; + blend.alpha_dst_factor = blend_opt.alpha_dst_factor; + + cso_set_blend(exa->cso, &blend); +} + +static void +bind_rasterizer_state(struct exa_context *exa) +{ + struct pipe_rasterizer_state raster; + memset(&raster, 0, sizeof(struct pipe_rasterizer_state)); + raster.gl_rasterization_rules = 1; + cso_set_rasterizer(exa->cso, &raster); +} + +static void +bind_shaders(struct exa_context *exa, int op, + PicturePtr pSrcPicture, PicturePtr pMaskPicture) +{ + unsigned vs_traits = 0, fs_traits = 0; + struct xorg_shader shader; + + exa->has_solid_color = FALSE; + + if (pSrcPicture) { + if (pSrcPicture->pSourcePict) { + if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) { + fs_traits |= FS_SOLID_FILL; + vs_traits |= VS_SOLID_FILL; + render_pixel_to_float4(pSrcPicture->pFormat, + pSrcPicture->pSourcePict->solidFill.color, + exa->solid_color); + exa->has_solid_color = TRUE; + } else { + debug_assert("!gradients not supported"); + } + } else { + fs_traits |= FS_COMPOSITE; + vs_traits |= VS_COMPOSITE; + } + } + + if (pMaskPicture) { + vs_traits |= VS_MASK; + fs_traits |= FS_MASK; + } + + shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits); + cso_set_vertex_shader_handle(exa->cso, shader.vs); + cso_set_fragment_shader_handle(exa->cso, shader.fs); +} + + +static void +bind_samplers(struct exa_context *exa, int op, + PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, + struct exa_pixmap_priv *pSrc, + struct exa_pixmap_priv *pMask, + struct exa_pixmap_priv *pDst) +{ + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_state src_sampler, mask_sampler; + + exa->num_bound_samplers = 0; + + memset(&src_sampler, 0, sizeof(struct pipe_sampler_state)); + memset(&mask_sampler, 0, sizeof(struct pipe_sampler_state)); + + if (pSrcPicture && pSrc) { + unsigned src_wrap = render_repeat_to_gallium( + pSrcPicture->repeatType); + src_sampler.wrap_s = src_wrap; + src_sampler.wrap_t = src_wrap; + src_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + src_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + src_sampler.normalized_coords = 1; + samplers[0] = &src_sampler; + exa->bound_textures[0] = pSrc->tex; + ++exa->num_bound_samplers; + } + + if (pMaskPicture && pMask) { + unsigned mask_wrap = render_repeat_to_gallium( + pMaskPicture->repeatType); + mask_sampler.wrap_s = mask_wrap; + mask_sampler.wrap_t = mask_wrap; + mask_sampler.min_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + mask_sampler.mag_img_filter = PIPE_TEX_MIPFILTER_NEAREST; + mask_sampler.normalized_coords = 1; + samplers[1] = &mask_sampler; + exa->bound_textures[1] = pMask->tex; + ++exa->num_bound_samplers; + } + + cso_set_samplers(exa->cso, exa->num_bound_samplers, + (const struct pipe_sampler_state **)samplers); + cso_set_sampler_textures(exa->cso, exa->num_bound_samplers, + exa->bound_textures); +} + +static void +setup_vs_constant_buffer(struct exa_context *exa, + int width, int height) +{ + const int param_bytes = 8 * sizeof(float); + float vs_consts[8] = { + 2.f/width, 2.f/height, 1, 1, + -1, -1, 0, 0 + }; + struct pipe_constant_buffer *cbuf = &exa->vs_const_buffer; + + pipe_buffer_reference(&cbuf->buffer, NULL); + cbuf->buffer = pipe_buffer_create(exa->pipe->screen, 16, + PIPE_BUFFER_USAGE_CONSTANT, + param_bytes); + + if (cbuf->buffer) { + pipe_buffer_write(exa->pipe->screen, cbuf->buffer, + 0, param_bytes, vs_consts); + } + exa->pipe->set_constant_buffer(exa->pipe, PIPE_SHADER_VERTEX, 0, cbuf); +} + + +static void +setup_fs_constant_buffer(struct exa_context *exa) +{ + const int param_bytes = 4 * sizeof(float); + float fs_consts[8] = { + 0, 0, 0, 1, + }; + struct pipe_constant_buffer *cbuf = &exa->fs_const_buffer; + + pipe_buffer_reference(&cbuf->buffer, NULL); + cbuf->buffer = pipe_buffer_create(exa->pipe->screen, 16, + PIPE_BUFFER_USAGE_CONSTANT, + param_bytes); + + if (cbuf->buffer) { + pipe_buffer_write(exa->pipe->screen, cbuf->buffer, + 0, param_bytes, fs_consts); + } + exa->pipe->set_constant_buffer(exa->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf); +} + +static void +setup_constant_buffers(struct exa_context *exa, struct exa_pixmap_priv *pDst) +{ + int width = pDst->tex->width[0]; + int height = pDst->tex->height[0]; + + setup_vs_constant_buffer(exa, width, height); + setup_fs_constant_buffer(exa); +} + +boolean xorg_composite_bind_state(struct exa_context *exa, + int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture, + struct exa_pixmap_priv *pSrc, + struct exa_pixmap_priv *pMask, + struct exa_pixmap_priv *pDst) +{ + bind_framebuffer_state(exa, pDst); + bind_viewport_state(exa, pDst); + bind_blend_state(exa, op, pSrcPicture, pMaskPicture); + bind_rasterizer_state(exa); + bind_shaders(exa, op, pSrcPicture, pMaskPicture); + bind_samplers(exa, op, pSrcPicture, pMaskPicture, + pDstPicture, pSrc, pMask, pDst); + bind_clip_state(exa); + setup_constant_buffers(exa, pDst); + + return FALSE; +} + +void xorg_composite(struct exa_context *exa, + struct exa_pixmap_priv *dst, + int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height) +{ + struct pipe_context *pipe = exa->pipe; + struct pipe_buffer *buf = 0; + + if (exa->num_bound_samplers == 0 ) { /* solid fill */ + buf = setup_vertex_data0(exa, + srcX, srcY, maskX, maskY, + dstX, dstY, width, height); + } else if (exa->num_bound_samplers == 1 ) /* src */ + buf = setup_vertex_data1(exa, + srcX, srcY, maskX, maskY, + dstX, dstY, width, height); + else if (exa->num_bound_samplers == 2) /* src + mask */ + buf = setup_vertex_data2(exa, + srcX, srcY, maskX, maskY, + dstX, dstY, width, height); + else if (exa->num_bound_samplers == 3) { /* src + mask + dst */ + debug_assert(!"src/mask/dst not handled right now"); +#if 0 + buf = setup_vertex_data2(exa, + srcX, srcY, maskX, maskY, + dstX, dstY, width, height); +#endif + } + + if (buf) { + int num_attribs = 1; /*pos*/ + num_attribs += exa->num_bound_samplers; + if (exa->has_solid_color) + ++num_attribs; + + util_draw_vertex_buffer(pipe, buf, 0, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + num_attribs); /* attribs/vert */ + + pipe_buffer_reference(&buf, NULL); + } +} + +boolean xorg_solid_bind_state(struct exa_context *exa, + struct exa_pixmap_priv *pixmap, + Pixel fg) +{ + unsigned vs_traits, fs_traits; + struct xorg_shader shader; + + pixel_to_float4(fg, exa->solid_color); + exa->has_solid_color = TRUE; + + exa->solid_color[3] = 1.f; + + debug_printf("Color Pixel=(%d, %d, %d, %d), RGBA=(%f, %f, %f, %f)\n", + (fg >> 24) & 0xff, (fg >> 16) & 0xff, + (fg >> 8) & 0xff, (fg >> 0) & 0xff, + exa->solid_color[0], exa->solid_color[1], + exa->solid_color[2], exa->solid_color[3]); + +#if 0 + exa->solid_color[0] = 1.f; + exa->solid_color[1] = 0.f; + exa->solid_color[2] = 0.f; + exa->solid_color[3] = 1.f; +#endif + + vs_traits = VS_SOLID_FILL; + fs_traits = FS_SOLID_FILL; + + bind_framebuffer_state(exa, pixmap); + bind_viewport_state(exa, pixmap); + bind_rasterizer_state(exa); + bind_blend_state(exa, PictOpSrc, NULL, NULL); + setup_constant_buffers(exa, pixmap); + bind_clip_state(exa); + + shader = xorg_shaders_get(exa->shaders, vs_traits, fs_traits); + cso_set_vertex_shader_handle(exa->cso, shader.vs); + cso_set_fragment_shader_handle(exa->cso, shader.fs); + + return FALSE; +} + +void xorg_solid(struct exa_context *exa, + struct exa_pixmap_priv *pixmap, + int x0, int y0, int x1, int y1) +{ + struct pipe_context *pipe = exa->pipe; + struct pipe_buffer *buf = 0; + float vertices[4][2][4]; + + x0 = 10; y0 = 10; + x1 = 300; y1 = 300; + + /* 1st vertex */ + setup_vertex0(vertices[0], x0, y0, + exa->solid_color); + /* 2nd vertex */ + setup_vertex0(vertices[1], x1, y0, + exa->solid_color); + /* 3rd vertex */ + setup_vertex0(vertices[2], x1, y1, + exa->solid_color); + /* 4th vertex */ + setup_vertex0(vertices[3], x0, y1, + exa->solid_color); + + buf = pipe_user_buffer_create(exa->pipe->screen, + vertices, + sizeof(vertices)); + + + if (buf) { + debug_printf("Drawing buf is %p\n", buf); + util_draw_vertex_buffer(pipe, buf, 0, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ + + pipe_buffer_reference(&buf, NULL); + } +} + + +static INLINE void shift_rectx(float coords[4], + const float *bounds, + const float shift) +{ + coords[0] += shift; + coords[2] -= shift; + if (bounds) { + coords[2] = MIN2(coords[2], bounds[2]); + /* bound x/y + width/height */ + if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) { + coords[2] = (bounds[0] + bounds[2]) - coords[0]; + } + } +} + +static INLINE void shift_recty(float coords[4], + const float *bounds, + const float shift) +{ + coords[1] += shift; + coords[3] -= shift; + if (bounds) { + coords[3] = MIN2(coords[3], bounds[3]); + if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) { + coords[3] = (bounds[1] + bounds[3]) - coords[1]; + } + } +} + +static INLINE void bound_rect(float coords[4], + const float bounds[4], + float shift[4]) +{ + /* if outside the bounds */ + if (coords[0] > (bounds[0] + bounds[2]) || + coords[1] > (bounds[1] + bounds[3]) || + (coords[0] + coords[2]) < bounds[0] || + (coords[1] + coords[3]) < bounds[1]) { + coords[0] = 0.f; + coords[1] = 0.f; + coords[2] = 0.f; + coords[3] = 0.f; + shift[0] = 0.f; + shift[1] = 0.f; + return; + } + + /* bound x */ + if (coords[0] < bounds[0]) { + shift[0] = bounds[0] - coords[0]; + coords[2] -= shift[0]; + coords[0] = bounds[0]; + } else + shift[0] = 0.f; + + /* bound y */ + if (coords[1] < bounds[1]) { + shift[1] = bounds[1] - coords[1]; + coords[3] -= shift[1]; + coords[1] = bounds[1]; + } else + shift[1] = 0.f; + + shift[2] = bounds[2] - coords[2]; + shift[3] = bounds[3] - coords[3]; + /* bound width/height */ + coords[2] = MIN2(coords[2], bounds[2]); + coords[3] = MIN2(coords[3], bounds[3]); + + /* bound x/y + width/height */ + if ((coords[0] + coords[2]) > (bounds[0] + bounds[2])) { + coords[2] = (bounds[0] + bounds[2]) - coords[0]; + } + if ((coords[1] + coords[3]) > (bounds[1] + bounds[3])) { + coords[3] = (bounds[1] + bounds[3]) - coords[1]; + } + + /* if outside the bounds */ + if ((coords[0] + coords[2]) < bounds[0] || + (coords[1] + coords[3]) < bounds[1]) { + coords[0] = 0.f; + coords[1] = 0.f; + coords[2] = 0.f; + coords[3] = 0.f; + return; + } +} + +static INLINE void sync_size(float *src_loc, float *dst_loc) +{ + src_loc[2] = MIN2(src_loc[2], dst_loc[2]); + src_loc[3] = MIN2(src_loc[3], dst_loc[3]); + dst_loc[2] = src_loc[2]; + dst_loc[3] = src_loc[3]; +} + + +static void renderer_copy_texture(struct exa_context *exa, + struct pipe_texture *src, + float sx1, float sy1, + float sx2, float sy2, + struct pipe_texture *dst, + float dx1, float dy1, + float dx2, float dy2) +{ + struct pipe_context *pipe = exa->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_buffer *buf; + struct pipe_surface *dst_surf = screen->get_tex_surface( + screen, dst, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + struct pipe_framebuffer_state fb; + float s0, t0, s1, t1; + struct xorg_shader shader; + + assert(src->width[0] != 0); + assert(src->height[0] != 0); + assert(dst->width[0] != 0); + assert(dst->height[0] != 0); + +#if 0 + debug_printf("copy texture [%f, %f, %f, %f], [%f, %f, %f, %f]\n", + sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); +#endif + +#if 1 + s0 = sx1 / src->width[0]; + s1 = sx2 / src->width[0]; + t0 = sy1 / src->height[0]; + t1 = sy2 / src->height[0]; +#else + s0 = 0; + s1 = 1; + t0 = 0; + t1 = 1; +#endif + + assert(screen->is_format_supported(screen, dst_surf->format, PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)); + + /* save state (restored below) */ + cso_save_blend(exa->cso); + cso_save_samplers(exa->cso); + cso_save_sampler_textures(exa->cso); + cso_save_framebuffer(exa->cso); + cso_save_fragment_shader(exa->cso); + cso_save_vertex_shader(exa->cso); + + cso_save_viewport(exa->cso); + + + /* set misc state we care about */ + { + struct pipe_blend_state blend; + memset(&blend, 0, sizeof(blend)); + blend.rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.colormask = PIPE_MASK_RGBA; + cso_set_blend(exa->cso, &blend); + } + + /* sampler */ + { + struct pipe_sampler_state sampler; + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.normalized_coords = 1; + cso_single_sampler(exa->cso, 0, &sampler); + cso_single_sampler_done(exa->cso); + } + + set_viewport(exa, dst_surf->width, dst_surf->height, Y0_TOP); + + /* texture */ + cso_set_sampler_textures(exa->cso, 1, &src); + + /* shaders */ + shader = xorg_shaders_get(exa->shaders, + VS_COMPOSITE, + FS_COMPOSITE); + cso_set_vertex_shader_handle(exa->cso, shader.vs); + cso_set_fragment_shader_handle(exa->cso, shader.fs); + + /* drawing dest */ + memset(&fb, 0, sizeof(fb)); + fb.width = dst_surf->width; + fb.height = dst_surf->height; + fb.nr_cbufs = 1; + fb.cbufs[0] = dst_surf; + { + int i; + for (i = 1; i < PIPE_MAX_COLOR_BUFS; ++i) + fb.cbufs[i] = 0; + } + cso_set_framebuffer(exa->cso, &fb); + + /* draw quad */ + buf = setup_vertex_data_tex(exa, + dx1, dy1, + dx2, dy2, + s0, t0, s1, t1, + 0.0f); + + if (buf) { + util_draw_vertex_buffer(exa->pipe, buf, 0, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ + + pipe_buffer_reference(&buf, NULL); + } + + /* restore state we changed */ + cso_restore_blend(exa->cso); + cso_restore_samplers(exa->cso); + cso_restore_sampler_textures(exa->cso); + cso_restore_framebuffer(exa->cso); + cso_restore_vertex_shader(exa->cso); + cso_restore_fragment_shader(exa->cso); + cso_restore_viewport(exa->cso); + + pipe_surface_reference(&dst_surf, NULL); +} + +void xorg_copy_pixmap(struct exa_context *ctx, + struct exa_pixmap_priv *dst_priv, int dx, int dy, + struct exa_pixmap_priv *src_priv, int sx, int sy, + int width, int height) +{ + float dst_loc[4], src_loc[4]; + float dst_bounds[4], src_bounds[4]; + float src_shift[4], dst_shift[4], shift[4]; + struct pipe_texture *dst = dst_priv->tex; + struct pipe_texture *src = src_priv->tex; + + dst_loc[0] = dx; + dst_loc[1] = dy; + dst_loc[2] = width; + dst_loc[3] = height; + dst_bounds[0] = 0.f; + dst_bounds[1] = 0.f; + dst_bounds[2] = dst->width[0]; + dst_bounds[3] = dst->height[0]; + + src_loc[0] = sx; + src_loc[1] = sy; + src_loc[2] = width; + src_loc[3] = height; + src_bounds[0] = 0.f; + src_bounds[1] = 0.f; + src_bounds[2] = src->width[0]; + src_bounds[3] = src->height[0]; + + bound_rect(src_loc, src_bounds, src_shift); + bound_rect(dst_loc, dst_bounds, dst_shift); + shift[0] = src_shift[0] - dst_shift[0]; + shift[1] = src_shift[1] - dst_shift[1]; + + if (shift[0] < 0) + shift_rectx(src_loc, src_bounds, -shift[0]); + else + shift_rectx(dst_loc, dst_bounds, shift[0]); + + if (shift[1] < 0) + shift_recty(src_loc, src_bounds, -shift[1]); + else + shift_recty(dst_loc, dst_bounds, shift[1]); + + sync_size(src_loc, dst_loc); + + if (src_loc[2] >= 0 && src_loc[3] >= 0 && + dst_loc[2] >= 0 && dst_loc[3] >= 0) { + renderer_copy_texture(ctx, + src, + src_loc[0], + src_loc[1] + src_loc[3], + src_loc[0] + src_loc[2], + src_loc[1], + dst, + dst_loc[0], + dst_loc[1] + dst_loc[3], + dst_loc[0] + dst_loc[2], + dst_loc[1]); + } +} + diff --git a/src/gallium/state_trackers/xorg/xorg_composite.h b/src/gallium/state_trackers/xorg/xorg_composite.h new file mode 100644 index 0000000000..e73f1c704a --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_composite.h @@ -0,0 +1,37 @@ +#ifndef XORG_COMPOSITE_H +#define XORG_COMPOSITE_H + +#include "xorg_exa.h" + +boolean xorg_composite_accelerated(int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture); + +boolean xorg_composite_bind_state(struct exa_context *exa, + int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture, + struct exa_pixmap_priv *pSrc, + struct exa_pixmap_priv *pMask, + struct exa_pixmap_priv *pDst); + +void xorg_composite(struct exa_context *exa, + struct exa_pixmap_priv *dst, + int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height); + +boolean xorg_solid_bind_state(struct exa_context *exa, + struct exa_pixmap_priv *pixmap, + Pixel fg); +void xorg_solid(struct exa_context *exa, + struct exa_pixmap_priv *pixmap, + int x0, int y0, int x1, int y1); + +void xorg_copy_pixmap(struct exa_context *ctx, + struct exa_pixmap_priv *dst, int dx, int dy, + struct exa_pixmap_priv *src, int sx, int sy, + int width, int height); + +#endif diff --git a/src/gallium/state_trackers/xorg/xorg_crtc.c b/src/gallium/state_trackers/xorg/xorg_crtc.c new file mode 100644 index 0000000000..fe08bde9ef --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_crtc.c @@ -0,0 +1,331 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <math.h> +#include <stdint.h> + +#include "xorg-server.h" +#include <xf86.h> +#include <xf86i2c.h> +#include <xf86Crtc.h> +#include "xorg_tracker.h" +#include "xf86Modes.h" + +#define DPMS_SERVER +#include <X11/extensions/dpms.h> + +#include "pipe/p_inlines.h" +#include "util/u_rect.h" + +struct crtc_private +{ + drmModeCrtcPtr drm_crtc; + + /* hwcursor */ + struct pipe_texture *cursor_tex; + unsigned cursor_handle; +}; + +static void +crtc_dpms(xf86CrtcPtr crtc, int mode) +{ + //ScrnInfoPtr pScrn = crtc->scrn; + + switch (mode) { + case DPMSModeOn: + case DPMSModeStandby: + case DPMSModeSuspend: + break; + case DPMSModeOff: + break; + } +} + +static Bool +crtc_lock(xf86CrtcPtr crtc) +{ + return FALSE; +} + +static void +crtc_unlock(xf86CrtcPtr crtc) +{ +} + +static void +crtc_prepare(xf86CrtcPtr crtc) +{ +} + +static void +crtc_commit(xf86CrtcPtr crtc) +{ +} + +static Bool +crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +static void +crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, + DisplayModePtr adjusted_mode, int x, int y) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + modesettingPtr ms = modesettingPTR(crtc->scrn); + xf86OutputPtr output = config->output[config->compat_output]; + drmModeConnectorPtr drm_connector = output->driver_private; + struct crtc_private *crtcp = crtc->driver_private; + drmModeCrtcPtr drm_crtc = crtcp->drm_crtc; + drmModeModeInfo drm_mode; + + drm_mode.clock = mode->Clock; + drm_mode.hdisplay = mode->HDisplay; + drm_mode.hsync_start = mode->HSyncStart; + drm_mode.hsync_end = mode->HSyncEnd; + drm_mode.htotal = mode->HTotal; + drm_mode.vdisplay = mode->VDisplay; + drm_mode.vsync_start = mode->VSyncStart; + drm_mode.vsync_end = mode->VSyncEnd; + drm_mode.vtotal = mode->VTotal; + drm_mode.flags = mode->Flags; + drm_mode.hskew = mode->HSkew; + drm_mode.vscan = mode->VScan; + drm_mode.vrefresh = mode->VRefresh; + if (!mode->name) + xf86SetModeDefaultName(mode); + strncpy(drm_mode.name, mode->name, DRM_DISPLAY_MODE_LEN); + + drmModeSetCrtc(ms->fd, drm_crtc->crtc_id, ms->fb_id, x, y, + &drm_connector->connector_id, 1, &drm_mode); +} + +#if 0 +static void +crtc_load_lut(xf86CrtcPtr crtc) +{ + //ScrnInfoPtr pScrn = crtc->scrn; +} +#endif + +static void +crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green, CARD16 * blue, + int size) +{ +} + +static void * +crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) +{ + //ScrnInfoPtr pScrn = crtc->scrn; + + return NULL; +} + +static PixmapPtr +crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) +{ + //ScrnInfoPtr pScrn = crtc->scrn; + + return NULL; +} + +static void +crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) +{ + //ScrnInfoPtr pScrn = crtc->scrn; +} + +static void +crtc_destroy(xf86CrtcPtr crtc) +{ + struct crtc_private *crtcp = crtc->driver_private; + + if (crtcp->cursor_tex) + pipe_texture_reference(&crtcp->cursor_tex, NULL); + + drmModeFreeCrtc(crtcp->drm_crtc); + xfree(crtcp); +} + +static void +crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) +{ + unsigned char *ptr; + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + struct pipe_transfer *transfer; + + if (!crtcp->cursor_tex) { + struct pipe_texture templat; + unsigned pitch; + + memset(&templat, 0, sizeof(templat)); + templat.tex_usage |= PIPE_TEXTURE_USAGE_RENDER_TARGET; + templat.tex_usage |= PIPE_TEXTURE_USAGE_PRIMARY; + templat.target = PIPE_TEXTURE_2D; + templat.last_level = 0; + templat.depth[0] = 1; + templat.format = PIPE_FORMAT_A8R8G8B8_UNORM; + templat.width[0] = 64; + templat.height[0] = 64; + pf_get_block(templat.format, &templat.block); + + crtcp->cursor_tex = ms->screen->texture_create(ms->screen, + &templat); + ms->api->local_handle_from_texture(ms->api, + ms->screen, + crtcp->cursor_tex, + &pitch, + &crtcp->cursor_handle); + } + + transfer = ms->screen->get_tex_transfer(ms->screen, crtcp->cursor_tex, + 0, 0, 0, + PIPE_TRANSFER_WRITE, + 0, 0, 64, 64); + ptr = ms->screen->transfer_map(ms->screen, transfer); + util_copy_rect(ptr, &crtcp->cursor_tex->block, + transfer->stride, 0, 0, + 64, 64, (void*)image, 64 * 4, 0, 0); + ms->screen->transfer_unmap(ms->screen, transfer); + ms->screen->tex_transfer_destroy(transfer); +} + +static void +crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + + drmModeMoveCursor(ms->fd, crtcp->drm_crtc->crtc_id, x, y); +} + +static void +crtc_show_cursor(xf86CrtcPtr crtc) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + + if (crtcp->cursor_tex) + drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, + crtcp->cursor_handle, 64, 64); +} + +static void +crtc_hide_cursor(xf86CrtcPtr crtc) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + struct crtc_private *crtcp = crtc->driver_private; + + drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 0, 0, 0); +} + +static const xf86CrtcFuncsRec crtc_funcs = { + .dpms = crtc_dpms, + .save = NULL, + .restore = NULL, + .lock = crtc_lock, + .unlock = crtc_unlock, + .mode_fixup = crtc_mode_fixup, + .prepare = crtc_prepare, + .mode_set = crtc_mode_set, + .commit = crtc_commit, + .gamma_set = crtc_gamma_set, + .shadow_create = crtc_shadow_create, + .shadow_allocate = crtc_shadow_allocate, + .shadow_destroy = crtc_shadow_destroy, + .set_cursor_position = crtc_set_cursor_position, + .show_cursor = crtc_show_cursor, + .hide_cursor = crtc_hide_cursor, + .load_cursor_image = NULL, /* lets convert to argb only */ + .set_cursor_colors = NULL, /* using argb only */ + .load_cursor_argb = crtc_load_cursor_argb, + .destroy = crtc_destroy, +}; + +void +crtc_cursor_destroy(xf86CrtcPtr crtc) +{ + struct crtc_private *crtcp = crtc->driver_private; + + if (crtcp->cursor_tex) { + pipe_texture_reference(&crtcp->cursor_tex, NULL); + } +} + +void +crtc_init(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + xf86CrtcPtr crtc; + drmModeResPtr res; + drmModeCrtcPtr drm_crtc = NULL; + struct crtc_private *crtcp; + int c; + + res = drmModeGetResources(ms->fd); + if (res == 0) { + ErrorF("Failed drmModeGetResources %d\n", errno); + return; + } + + for (c = 0; c < res->count_crtcs; c++) { + drm_crtc = drmModeGetCrtc(ms->fd, res->crtcs[c]); + if (!drm_crtc) + continue; + + crtc = xf86CrtcCreate(pScrn, &crtc_funcs); + if (crtc == NULL) + goto out; + + crtcp = xcalloc(1, sizeof(struct crtc_private)); + if (!crtcp) { + xf86CrtcDestroy(crtc); + goto out; + } + + crtcp->drm_crtc = drm_crtc; + + crtc->driver_private = crtcp; + + } + + out: + drmModeFreeResources(res); +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/src/gallium/state_trackers/xorg/xorg_dri2.c b/src/gallium/state_trackers/xorg/xorg_dri2.c new file mode 100644 index 0000000000..8a362596c7 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_dri2.c @@ -0,0 +1,380 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#include "xorg-server.h" +#include "xf86.h" +#include "xf86_OSproc.h" + +#include "xorg_tracker.h" +#include "xorg_exa.h" + +#include "dri2.h" + +#include "pipe/p_state.h" +#include "pipe/p_inlines.h" + +#include "util/u_rect.h" + +typedef struct { + PixmapPtr pPixmap; + struct pipe_texture *tex; + struct pipe_fence_handle *fence; +} *BufferPrivatePtr; + +static Bool +driDoCreateBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer, unsigned int format) +{ + struct pipe_texture *tex = NULL; + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_pixmap_priv *exa_priv; + BufferPrivatePtr private = buffer->driverPrivate; + PixmapPtr pPixmap; + unsigned stride, handle; + + if (pDraw->type == DRAWABLE_PIXMAP) + pPixmap = (PixmapPtr) pDraw; + else + pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw); + exa_priv = exaGetPixmapDriverPrivate(pPixmap); + + switch (buffer->attachment) { + default: + if (buffer->attachment != DRI2BufferFakeFrontLeft || + pDraw->type != DRAWABLE_PIXMAP) { + private->pPixmap = (*pScreen->CreatePixmap)(pScreen, pDraw->width, + pDraw->height, + pDraw->depth, + 0); + } + break; + case DRI2BufferFrontLeft: + break; + case DRI2BufferStencil: +#if defined(DRI2INFOREC_VERSION) && DRI2INFOREC_VERSION > 2 + case DRI2BufferDepthStencil: + if (exa_priv->depth_stencil_tex && + !pf_is_depth_stencil(exa_priv->depth_stencil_tex->format)) + exa_priv->depth_stencil_tex = NULL; + /* Fall through */ +#endif + case DRI2BufferDepth: + if (exa_priv->depth_stencil_tex) + pipe_texture_reference(&tex, exa_priv->depth_stencil_tex); + else { + struct pipe_texture template; + memset(&template, 0, sizeof(template)); + template.target = PIPE_TEXTURE_2D; + if (buffer->attachment == DRI2BufferDepth) + template.format = ms->ds_depth_bits_last ? + PIPE_FORMAT_X8Z24_UNORM : PIPE_FORMAT_Z24X8_UNORM; + else + template.format = ms->ds_depth_bits_last ? + PIPE_FORMAT_S8Z24_UNORM : PIPE_FORMAT_Z24S8_UNORM; + pf_get_block(template.format, &template.block); + template.width[0] = pDraw->width; + template.height[0] = pDraw->height; + template.depth[0] = 1; + template.last_level = 0; + template.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL | + PIPE_TEXTURE_USAGE_DISPLAY_TARGET; + tex = ms->screen->texture_create(ms->screen, &template); + pipe_texture_reference(&exa_priv->depth_stencil_tex, tex); + } + break; + } + + if (!private->pPixmap) { + private->pPixmap = pPixmap; + pPixmap->refcnt++; + } + + if (!tex) { + exaMoveInPixmap(private->pPixmap); + xorg_exa_set_shared_usage(private->pPixmap); + pScreen->ModifyPixmapHeader(private->pPixmap, 0, 0, 0, 0, 0, NULL); + tex = xorg_exa_get_texture(private->pPixmap); + } + + if (!tex) + FatalError("NO TEXTURE IN DRI2\n"); + + ms->api->shared_handle_from_texture(ms->api, ms->screen, tex, &stride, &handle); + + buffer->name = handle; + buffer->pitch = stride; + buffer->cpp = 4; + buffer->driverPrivate = private; + buffer->flags = 0; /* not tiled */ + private->tex = tex; + + return TRUE; +} + +static void +driDoDestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + BufferPrivatePtr private = buffer->driverPrivate; + struct exa_pixmap_priv *exa_priv = exaGetPixmapDriverPrivate(private->pPixmap); + + pipe_texture_reference(&private->tex, NULL); + ms->screen->fence_reference(ms->screen, &private->fence, NULL); + pipe_texture_reference(&exa_priv->depth_stencil_tex, NULL); + (*pScreen->DestroyPixmap)(private->pPixmap); +} + +#if defined(DRI2INFOREC_VERSION) && DRI2INFOREC_VERSION > 2 + +static DRI2BufferPtr +driCreateBuffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format) +{ + DRI2BufferPtr buffer; + BufferPrivatePtr private; + + buffer = xcalloc(1, sizeof *buffer); + if (!buffer) + return NULL; + + private = xcalloc(1, sizeof *private); + if (!private) { + goto fail; + } + + buffer->attachment = attachment; + buffer->driverPrivate = private; + + if (driDoCreateBuffer(pDraw, buffer, format)) + return buffer; + + xfree(private); +fail: + xfree(buffer); + return NULL; +} + +static void +driDestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer) +{ + driDoDestroyBuffer(pDraw, buffer); + + xfree(buffer->driverPrivate); + xfree(buffer); +} + +#else /* DRI2INFOREC_VERSION <= 2 */ + +static DRI2BufferPtr +driCreateBuffers(DrawablePtr pDraw, unsigned int *attachments, int count) +{ + BufferPrivatePtr privates; + DRI2BufferPtr buffers; + int i; + + buffers = xcalloc(count, sizeof *buffers); + if (!buffers) + goto fail_buffers; + + privates = xcalloc(count, sizeof *privates); + if (!privates) + goto fail_privates; + + for (i = 0; i < count; i++) { + buffers[i].attachment = attachments[i]; + buffers[i].driverPrivate = &privates[i]; + + if (!driDoCreateBuffer(pDraw, &buffers[i], 0)) + goto fail; + } + + return buffers; + +fail: + xfree(privates); +fail_privates: + xfree(buffers); +fail_buffers: + return NULL; +} + +static void +driDestroyBuffers(DrawablePtr pDraw, DRI2BufferPtr buffers, int count) +{ + int i; + + for (i = 0; i < count; i++) { + driDoDestroyBuffer(pDraw, &buffers[i]); + } + + if (buffers) { + xfree(buffers[0].driverPrivate); + xfree(buffers); + } +} + +#endif /* DRI2INFOREC_VERSION */ + +static void +driCopyRegion(DrawablePtr pDraw, RegionPtr pRegion, + DRI2BufferPtr pDestBuffer, DRI2BufferPtr pSrcBuffer) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate; + BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate; + PixmapPtr src_pixmap; + PixmapPtr dst_pixmap; + GCPtr gc; + RegionPtr copy_clip; + + /* + * In driCreateBuffers we dewrap windows into the + * backing pixmaps in order to get to the texture. + * We need to use the real drawable in CopyArea + * so that cliprects and offsets are correct. + */ + src_pixmap = src_priv->pPixmap; + dst_pixmap = dst_priv->pPixmap; + if (pSrcBuffer->attachment == DRI2BufferFrontLeft) + src_pixmap = (PixmapPtr)pDraw; + if (pDestBuffer->attachment == DRI2BufferFrontLeft) + dst_pixmap = (PixmapPtr)pDraw; + + /* + * The clients implements glXWaitX with a copy front to fake and then + * waiting on the server to signal its completion of it. While + * glXWaitGL is a client side flush and a copy from fake to front. + * This is how it is done in the DRI2 protocol, how ever depending + * which type of drawables the server does things a bit differently + * then what the protocol says as the fake and front are the same. + * + * for pixmaps glXWaitX is a server flush. + * for pixmaps glXWaitGL is a client flush. + * for windows glXWaitX is a copy from front to fake then a server flush. + * for windows glXWaitGL is a client flush then a copy from fake to front. + * + * XXX in the windows case this code always flushes but that isn't a + * must in the glXWaitGL case but we don't know if this is a glXWaitGL + * or a glFlush/glFinish call. + */ + if (dst_pixmap == src_pixmap) { + /* pixmap glXWaitX */ + if (pSrcBuffer->attachment == DRI2BufferFrontLeft && + pDestBuffer->attachment == DRI2BufferFakeFrontLeft) { + ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS, NULL); + return; + } + /* pixmap glXWaitGL */ + if (pDestBuffer->attachment == DRI2BufferFrontLeft && + pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) { + return; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "copying between the same pixmap\n"); + } + } + + gc = GetScratchGC(pDraw->depth, pScreen); + copy_clip = REGION_CREATE(pScreen, NULL, 0); + REGION_COPY(pScreen, copy_clip, pRegion); + (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); + ValidateGC(&dst_pixmap->drawable, gc); + + /* If this is a full buffer swap, throttle on the previous one */ + if (dst_priv->fence && REGION_NUM_RECTS(pRegion) == 1) { + BoxPtr extents = REGION_EXTENTS(pScreen, pRegion); + + if (extents->x1 == 0 && extents->y1 == 0 && + extents->x2 == pDraw->width && extents->y2 == pDraw->height) { + ms->screen->fence_finish(ms->screen, dst_priv->fence, 0); + ms->screen->fence_reference(ms->screen, &dst_priv->fence, NULL); + } + } + + (*gc->ops->CopyArea)(&src_pixmap->drawable, &dst_pixmap->drawable, gc, + 0, 0, pDraw->width, pDraw->height, 0, 0); + + FreeScratchGC(gc); + + ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS, + pDestBuffer->attachment == DRI2BufferFrontLeft ? + &dst_priv->fence : NULL); +} + +Bool +driScreenInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + DRI2InfoRec dri2info; + +#if defined(DRI2INFOREC_VERSION) + dri2info.version = DRI2INFOREC_VERSION; +#else + dri2info.version = 1; +#endif + dri2info.fd = ms->fd; + + dri2info.driverName = pScrn->driverName; + dri2info.deviceName = "/dev/dri/card0"; /* FIXME */ + +#if defined(DRI2INFOREC_VERSION) && DRI2INFOREC_VERSION > 2 + dri2info.CreateBuffer = driCreateBuffer; + dri2info.DestroyBuffer = driDestroyBuffer; +#else + dri2info.CreateBuffers = driCreateBuffers; + dri2info.DestroyBuffers = driDestroyBuffers; +#endif + dri2info.CopyRegion = driCopyRegion; + dri2info.Wait = NULL; + + ms->d_depth_bits_last = + ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_X8Z24_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); + ms->ds_depth_bits_last = + ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_S8Z24_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); + + return DRI2ScreenInit(pScreen, &dri2info); +} + +void +driCloseScreen(ScreenPtr pScreen) +{ + DRI2CloseScreen(pScreen); +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/src/gallium/state_trackers/xorg/xorg_driver.c b/src/gallium/state_trackers/xorg/xorg_driver.c new file mode 100644 index 0000000000..643b6b3b9e --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_driver.c @@ -0,0 +1,744 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + + +#include "xorg-server.h" +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "mipointer.h" +#include "micmap.h" +#include <X11/extensions/randr.h> +#include "fb.h" +#include "edid.h" +#include "xf86i2c.h" +#include "xf86Crtc.h" +#include "miscstruct.h" +#include "dixstruct.h" +#include "xf86xv.h" +#include <X11/extensions/Xv.h> +#ifndef XSERVER_LIBPCIACCESS +#error "libpciaccess needed" +#endif + +#include <pciaccess.h> + +#include "pipe/p_context.h" +#include "xorg_tracker.h" +#include "xorg_winsys.h" + +static void AdjustFrame(int scrnIndex, int x, int y, int flags); +static Bool CloseScreen(int scrnIndex, ScreenPtr pScreen); +static Bool EnterVT(int scrnIndex, int flags); +static Bool SaveHWState(ScrnInfoPtr pScrn); +static Bool RestoreHWState(ScrnInfoPtr pScrn); + + +static ModeStatus ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, + int flags); +static void FreeScreen(int scrnIndex, int flags); +static void LeaveVT(int scrnIndex, int flags); +static Bool SwitchMode(int scrnIndex, DisplayModePtr mode, int flags); +static Bool ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, + char **argv); +static Bool PreInit(ScrnInfoPtr pScrn, int flags); + +typedef enum +{ + OPTION_SW_CURSOR, +} modesettingOpts; + +static const OptionInfoRec Options[] = { + {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE}, + {-1, NULL, OPTV_NONE, {0}, FALSE} +}; + +/* + * Exported Xorg driver functions to winsys + */ + +const OptionInfoRec * +xorg_tracker_available_options(int chipid, int busid) +{ + return Options; +} + +void +xorg_tracker_set_functions(ScrnInfoPtr scrn) +{ + scrn->PreInit = PreInit; + scrn->ScreenInit = ScreenInit; + scrn->SwitchMode = SwitchMode; + scrn->AdjustFrame = AdjustFrame; + scrn->EnterVT = EnterVT; + scrn->LeaveVT = LeaveVT; + scrn->FreeScreen = FreeScreen; + scrn->ValidMode = ValidMode; +} + +/* + * Static Xorg funtctions + */ + +static Bool +GetRec(ScrnInfoPtr pScrn) +{ + if (pScrn->driverPrivate) + return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(modesettingRec), 1); + + return TRUE; +} + +static void +FreeRec(ScrnInfoPtr pScrn) +{ + if (!pScrn) + return; + + if (!pScrn->driverPrivate) + return; + + xfree(pScrn->driverPrivate); + + pScrn->driverPrivate = NULL; +} + +static void +ProbeDDC(ScrnInfoPtr pScrn, int index) +{ + ConfiguredMonitor = NULL; +} + +static Bool +CreateFrontBuffer(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + ScreenPtr pScreen = pScrn->pScreen; + PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); + unsigned handle, stride; + + ms->noEvict = TRUE; + xorg_exa_set_displayed_usage(rootPixmap); + pScreen->ModifyPixmapHeader(rootPixmap, + pScrn->virtualX, pScrn->virtualY, + pScrn->depth, pScrn->bitsPerPixel, + pScrn->displayWidth * pScrn->bitsPerPixel / 8, + NULL); + ms->noEvict = FALSE; + + handle = xorg_exa_get_pixmap_handle(rootPixmap, &stride); + + drmModeAddFB(ms->fd, + pScrn->virtualX, + pScrn->virtualY, + pScrn->depth, + pScrn->bitsPerPixel, + stride, + handle, + &ms->fb_id); + + pScrn->frameX0 = 0; + pScrn->frameY0 = 0; + AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + + return TRUE; +} + +static Bool +crtc_resize(ScrnInfoPtr pScrn, int width, int height) +{ + modesettingPtr ms = modesettingPTR(pScrn); + //ScreenPtr pScreen = pScrn->pScreen; + //PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen); + //Bool fbAccessDisabled; + //CARD8 *fbstart; + + if (width == pScrn->virtualX && height == pScrn->virtualY) + return TRUE; + + ErrorF("RESIZING TO %dx%d\n", width, height); + + pScrn->virtualX = width; + pScrn->virtualY = height; + + /* HW dependent - FIXME */ + pScrn->displayWidth = pScrn->virtualX; + + drmModeRmFB(ms->fd, ms->fb_id); + + /* now create new frontbuffer */ + return CreateFrontBuffer(pScrn); +} + +static const xf86CrtcConfigFuncsRec crtc_config_funcs = { + crtc_resize +}; + +static Bool +PreInit(ScrnInfoPtr pScrn, int flags) +{ + xf86CrtcConfigPtr xf86_config; + modesettingPtr ms; + rgb defaultWeight = { 0, 0, 0 }; + EntityInfoPtr pEnt; + EntPtr msEnt = NULL; + char *BusID; + int max_width, max_height; + + if (pScrn->numEntities != 1) + return FALSE; + + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + if (flags & PROBE_DETECT) { + ProbeDDC(pScrn, pEnt->index); + return TRUE; + } + + /* Allocate driverPrivate */ + if (!GetRec(pScrn)) + return FALSE; + + ms = modesettingPTR(pScrn); + ms->SaveGeneration = -1; + ms->pEnt = pEnt; + + pScrn->displayWidth = 640; /* default it */ + + if (ms->pEnt->location.type != BUS_PCI) + return FALSE; + + ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index); + + /* Allocate an entity private if necessary */ + if (xf86IsEntityShared(pScrn->entityList[0])) { + FatalError("Entity"); +#if 0 + msEnt = xf86GetEntityPrivate(pScrn->entityList[0], + modesettingEntityIndex)->ptr; + ms->entityPrivate = msEnt; +#else + (void)msEnt; +#endif + } else + ms->entityPrivate = NULL; + + if (xf86IsEntityShared(pScrn->entityList[0])) { + if (xf86IsPrimInitDone(pScrn->entityList[0])) { + /* do something */ + } else { + xf86SetPrimInitDone(pScrn->entityList[0]); + } + } + + BusID = xalloc(64); + sprintf(BusID, "PCI:%d:%d:%d", + ((ms->PciInfo->domain << 8) | ms->PciInfo->bus), + ms->PciInfo->dev, ms->PciInfo->func + ); + + ms->api = drm_api_create(); + ms->fd = drmOpen(NULL, BusID); + + if (ms->fd < 0) + return FALSE; + + pScrn->monitor = pScrn->confScreen->monitor; + pScrn->progClock = TRUE; + pScrn->rgbBits = 8; + + if (!xf86SetDepthBpp + (pScrn, 0, 0, 0, + PreferConvert24to32 | SupportConvert24to32 | Support32bppFb)) + return FALSE; + + switch (pScrn->depth) { + case 15: + case 16: + case 24: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by the driver\n", + pScrn->depth); + return FALSE; + } + xf86PrintDepthBpp(pScrn); + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) + return FALSE; + if (!xf86SetDefaultVisual(pScrn, -1)) + return FALSE; + + /* Process the options */ + xf86CollectOptions(pScrn, NULL); + if (!(ms->Options = xalloc(sizeof(Options)))) + return FALSE; + memcpy(ms->Options, Options, sizeof(Options)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options); + + /* Allocate an xf86CrtcConfig */ + xf86CrtcConfigInit(pScrn, &crtc_config_funcs); + xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + + max_width = 8192; + max_height = 8192; + xf86CrtcSetSizeRange(pScrn, 320, 200, max_width, max_height); + + if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) { + ms->SWCursor = TRUE; + } + + SaveHWState(pScrn); + + crtc_init(pScrn); + output_init(pScrn); + + if (!xf86InitialConfiguration(pScrn, TRUE)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + RestoreHWState(pScrn); + return FALSE; + } + + RestoreHWState(pScrn); + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() here. + */ + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) { + return FALSE; + } + } + + if (pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); + return FALSE; + } + + pScrn->currentMode = pScrn->modes; + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load the required sub modules */ + if (!xf86LoadSubModule(pScrn, "fb")) { + return FALSE; + } + + xf86LoadSubModule(pScrn, "exa"); + +#ifdef DRI2 + xf86LoadSubModule(pScrn, "dri2"); +#endif + + return TRUE; +} + +static Bool +SaveHWState(ScrnInfoPtr pScrn) +{ + /*xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);*/ + + return TRUE; +} + +static Bool +RestoreHWState(ScrnInfoPtr pScrn) +{ + /*xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);*/ + + return TRUE; +} + +static void xorgBlockHandler(int i, pointer blockData, pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]); + + pScreen->BlockHandler = ms->blockHandler; + pScreen->BlockHandler(i, blockData, pTimeout, pReadmask); + pScreen->BlockHandler = xorgBlockHandler; + + ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, NULL); + +#ifdef DRM_MODE_FEATURE_DIRTYFB + { + RegionPtr dirty = DamageRegion(ms->damage); + unsigned num_cliprects = REGION_NUM_RECTS(dirty); + + if (num_cliprects) { + drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip)); + BoxPtr rect = REGION_RECTS(dirty); + int i; + + for (i = 0; i < num_cliprects; i++, rect++) { + clip[i].x = rect->x1; + clip[i].y = rect->y1; + clip[i].width = rect->x2 - rect->x1; + clip[i].height = rect->y2 - rect->y1; + } + + /* TODO query connector property to see if this is needed */ + drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects); + + DamageEmpty(ms->damage); + } + } +#endif +} + +static Bool +CreateScreenResources(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + PixmapPtr rootPixmap; + Bool ret; + unsigned handle, stride; + + ms->noEvict = TRUE; + + pScreen->CreateScreenResources = ms->createScreenResources; + ret = pScreen->CreateScreenResources(pScreen); + pScreen->CreateScreenResources = CreateScreenResources; + + rootPixmap = pScreen->GetScreenPixmap(pScreen); + + xorg_exa_set_displayed_usage(rootPixmap); + xorg_exa_set_shared_usage(rootPixmap); + if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL)) + FatalError("Couldn't adjust screen pixmap\n"); + + ms->noEvict = FALSE; + + handle = xorg_exa_get_pixmap_handle(rootPixmap, &stride); + + drmModeAddFB(ms->fd, + pScrn->virtualX, + pScrn->virtualY, + pScrn->depth, + pScrn->bitsPerPixel, + stride, + handle, + &ms->fb_id); + + AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + +#ifdef DRM_MODE_FEATURE_DIRTYFB + ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE, + pScreen, rootPixmap); + + if (ms->damage) { + DamageRegister(&rootPixmap->drawable, ms->damage); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to create screen damage record\n"); + return FALSE; + } +#endif + + return ret; +} + +static Bool +ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + VisualPtr visual; + + /* deal with server regeneration */ + if (ms->fd < 0) { + char *BusID; + + BusID = xalloc(64); + sprintf(BusID, "PCI:%d:%d:%d", + ((ms->PciInfo->domain << 8) | ms->PciInfo->bus), + ms->PciInfo->dev, ms->PciInfo->func + ); + + ms->fd = drmOpen(NULL, BusID); + + if (ms->fd < 0) + return FALSE; + } + + if (!ms->screen) { + ms->screen = ms->api->create_screen(ms->api, ms->fd, NULL); + + if (!ms->screen) { + FatalError("Could not init pipe_screen\n"); + return FALSE; + } + } + + pScrn->pScreen = pScreen; + + /* HW dependent - FIXME */ + pScrn->displayWidth = pScrn->virtualX; + + miClearVisualTypes(); + + if (!miSetVisualTypes(pScrn->depth, + miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + + if (!miSetPixmapDepths()) + return FALSE; + + pScrn->memPhysBase = 0; + pScrn->fbOffset = 0; + + if (!fbScreenInit(pScreen, NULL, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth, pScrn->bitsPerPixel)) + return FALSE; + + if (pScrn->bitsPerPixel > 8) { + /* Fixup RGB ordering */ + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) { + if ((visual->class | DynamicClass) == DirectColor) { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + } + + fbPictureInit(pScreen, NULL, 0); + + ms->blockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = xorgBlockHandler; + ms->createScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = CreateScreenResources; + + xf86SetBlackWhitePixels(pScreen); + + ms->exa = xorg_exa_init(pScrn); + + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + xf86SetSilkenMouse(pScreen); + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + /* Need to extend HWcursor support to handle mask interleave */ + if (!ms->SWCursor) + xf86_cursors_init(pScreen, 64, 64, + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | + HARDWARE_CURSOR_ARGB); + + /* Must force it before EnterVT, so we are in control of VT and + * later memory should be bound when allocating, e.g rotate_mem */ + pScrn->vtSema = TRUE; + + pScreen->SaveScreen = xf86SaveScreen; + ms->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = CloseScreen; + + if (!xf86CrtcScreenInit(pScreen)) + return FALSE; + + if (!miCreateDefColormap(pScreen)) + return FALSE; + + xf86DPMSInit(pScreen, xf86DPMSSet, 0); + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + +#if 1 +#ifdef DRI2 + driScreenInit(pScreen); +#endif +#endif + + return EnterVT(scrnIndex, 1); +} + +static void +AdjustFrame(int scrnIndex, int x, int y, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output = config->output[config->compat_output]; + xf86CrtcPtr crtc = output->crtc; + + if (crtc && crtc->enabled) { + crtc->funcs->mode_set(crtc, pScrn->currentMode, pScrn->currentMode, x, + y); + crtc->x = output->initial_x + x; + crtc->y = output->initial_y + y; + } +} + +static void +FreeScreen(int scrnIndex, int flags) +{ + FreeRec(xf86Screens[scrnIndex]); +} + +static void +LeaveVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + modesettingPtr ms = modesettingPTR(pScrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int o; + + for (o = 0; o < config->num_crtc; o++) { + xf86CrtcPtr crtc = config->crtc[o]; + + crtc_cursor_destroy(crtc); + + if (crtc->rotatedPixmap || crtc->rotatedData) { + crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap, + crtc->rotatedData); + crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; + } + } + + drmModeRmFB(ms->fd, ms->fb_id); + + RestoreHWState(pScrn); + + if (drmDropMaster(ms->fd)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmDropMaster failed: %s\n", strerror(errno)); + + pScrn->vtSema = FALSE; +} + +/* + * This gets called when gaining control of the VT, and from ScreenInit(). + */ +static Bool +EnterVT(int scrnIndex, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + modesettingPtr ms = modesettingPTR(pScrn); + + if (drmSetMaster(ms->fd)) { + if (errno == EINVAL) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmSetMaster failed: 2.6.29 or newer kernel required for " + "multi-server DRI\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmSetMaster failed: %s\n", strerror(errno)); + } + } + + /* + * Only save state once per server generation since that's what most + * drivers do. Could change this to save state at each VT enter. + */ + if (ms->SaveGeneration != serverGeneration) { + ms->SaveGeneration = serverGeneration; + SaveHWState(pScrn); + } + + if (!flags) /* signals startup as we'll do this in CreateScreenResources */ + CreateFrontBuffer(pScrn); + + if (!xf86SetDesiredModes(pScrn)) + return FALSE; + + return TRUE; +} + +static Bool +SwitchMode(int scrnIndex, DisplayModePtr mode, int flags) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + + return xf86SetSingleMode(pScrn, mode, RR_Rotate_0); +} + +static Bool +CloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + modesettingPtr ms = modesettingPTR(pScrn); + + if (pScrn->vtSema) { + LeaveVT(scrnIndex, 0); + } +#ifdef DRI2 + driCloseScreen(pScreen); +#endif + + pScreen->BlockHandler = ms->blockHandler; + pScreen->CreateScreenResources = ms->createScreenResources; + +#ifdef DRM_MODE_FEATURE_DIRTYFB + if (ms->damage) { + DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage); + DamageDestroy(ms->damage); + ms->damage = NULL; + } +#endif + + if (ms->exa) + xorg_exa_close(pScrn); + + ms->api->destroy(ms->api); + ms->api = NULL; + drmClose(ms->fd); + ms->fd = -1; + + pScrn->vtSema = FALSE; + pScreen->CloseScreen = ms->CloseScreen; + return (*pScreen->CloseScreen) (scrnIndex, pScreen); +} + +static ModeStatus +ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) +{ + return MODE_OK; +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/src/gallium/state_trackers/xorg/xorg_exa.c b/src/gallium/state_trackers/xorg/xorg_exa.c new file mode 100644 index 0000000000..312dab1544 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_exa.c @@ -0,0 +1,771 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#include "xorg_exa.h" +#include "xorg_tracker.h" +#include "xorg_composite.h" +#include "xorg_exa_tgsi.h" + +#include <xorg-server.h> +#include <xf86.h> +#include <picturestr.h> +#include <picture.h> + +#include "pipe/p_format.h" +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "pipe/p_inlines.h" + +#include "cso_cache/cso_context.h" + +#include "util/u_rect.h" + +/* + * Helper functions + */ + +static void +exa_get_pipe_format(int depth, enum pipe_format *format, int *bbp) +{ + switch (depth) { + case 32: + *format = PIPE_FORMAT_A8R8G8B8_UNORM; + assert(*bbp == 32); + break; + case 24: + *format = PIPE_FORMAT_X8R8G8B8_UNORM; + assert(*bbp == 32); + break; + case 16: + *format = PIPE_FORMAT_R5G6B5_UNORM; + assert(*bbp == 16); + break; + case 15: + *format = PIPE_FORMAT_A1R5G5B5_UNORM; + assert(*bbp == 16); + break; + case 8: + case 4: + case 1: + *format = PIPE_FORMAT_A8R8G8B8_UNORM; /* bad bad bad */ + break; + default: + assert(0); + break; + } +} + +static void +xorg_exa_init_state(struct exa_context *exa) +{ + struct pipe_depth_stencil_alpha_state dsa; + + /* set common initial clip state */ + memset(&dsa, 0, sizeof(struct pipe_depth_stencil_alpha_state)); + cso_set_depth_stencil_alpha(exa->cso, &dsa); +} + +static void +xorg_exa_common_done(struct exa_context *exa) +{ + exa->copy.src = NULL; + exa->copy.dst = NULL; + exa->has_solid_color = FALSE; + exa->num_bound_samplers = 0; +} + +/* + * Static exported EXA functions + */ + +static void +ExaWaitMarker(ScreenPtr pScreen, int marker) +{ +} + +static int +ExaMarkSync(ScreenPtr pScreen) +{ + return 1; +} + +static Bool +ExaDownloadFromScreen(PixmapPtr pPix, int x, int y, int w, int h, char *dst, + int dst_pitch) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPix); + struct pipe_transfer *transfer; + + if (!priv || !priv->tex) + return FALSE; + + if (exa->pipe->is_texture_referenced(exa->pipe, priv->tex, 0, 0) & + PIPE_REFERENCED_FOR_WRITE) + exa->pipe->flush(exa->pipe, 0, NULL); + + transfer = exa->scrn->get_tex_transfer(exa->scrn, priv->tex, 0, 0, 0, + PIPE_TRANSFER_READ, x, y, w, h); + if (!transfer) + return FALSE; + + util_copy_rect((unsigned char*)dst, &priv->tex->block, dst_pitch, 0, 0, + w, h, exa->scrn->transfer_map(exa->scrn, transfer), + transfer->stride, 0, 0); + + exa->scrn->transfer_unmap(exa->scrn, transfer); + exa->scrn->tex_transfer_destroy(transfer); + + return TRUE; +} + +static Bool +ExaUploadToScreen(PixmapPtr pPix, int x, int y, int w, int h, char *src, + int src_pitch) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPix); + struct pipe_transfer *transfer; + + if (!priv || !priv->tex) + return FALSE; + + transfer = exa->scrn->get_tex_transfer(exa->scrn, priv->tex, 0, 0, 0, + PIPE_TRANSFER_WRITE, x, y, w, h); + if (!transfer) + return FALSE; + + util_copy_rect(exa->scrn->transfer_map(exa->scrn, transfer), + &priv->tex->block, transfer->stride, 0, 0, w, h, + (unsigned char*)src, src_pitch, 0, 0); + + exa->scrn->transfer_unmap(exa->scrn, transfer); + exa->scrn->tex_transfer_destroy(transfer); + + return TRUE; +} + +static Bool +ExaPrepareAccess(PixmapPtr pPix, int index) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv; + + priv = exaGetPixmapDriverPrivate(pPix); + + if (!priv) + return FALSE; + + if (!priv->tex) + return FALSE; + + if (priv->map_count++ == 0) + { + if (exa->pipe->is_texture_referenced(exa->pipe, priv->tex, 0, 0) & + PIPE_REFERENCED_FOR_WRITE) + exa->pipe->flush(exa->pipe, 0, NULL); + + priv->map_transfer = + exa->scrn->get_tex_transfer(exa->scrn, priv->tex, 0, 0, 0, + PIPE_TRANSFER_READ_WRITE, + 0, 0, priv->tex->width[0], priv->tex->height[0]); + + pPix->devPrivate.ptr = + exa->scrn->transfer_map(exa->scrn, priv->map_transfer); + pPix->devKind = priv->map_transfer->stride; + } + + return TRUE; +} + +static void +ExaFinishAccess(PixmapPtr pPix, int index) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv; + priv = exaGetPixmapDriverPrivate(pPix); + + if (!priv) + return; + + if (!priv->map_transfer) + return; + + if (--priv->map_count == 0) { + assert(priv->map_transfer); + exa->scrn->transfer_unmap(exa->scrn, priv->map_transfer); + exa->scrn->tex_transfer_destroy(priv->map_transfer); + priv->map_transfer = NULL; + pPix->devPrivate.ptr = NULL; + } +} + +static void +ExaDone(PixmapPtr pPixmap) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + struct exa_context *exa = ms->exa; + + if (!priv) + return; + +#if 1 + xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, NULL); +#else + xorg_finish(exa); +#endif + xorg_exa_common_done(exa); +} + +static void +ExaDoneComposite(PixmapPtr pPixmap) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + + xorg_exa_common_done(exa); +} + +static Bool +ExaPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + struct exa_context *exa = ms->exa; + + debug_printf("ExaPrepareSolid - test\n"); + if (pPixmap->drawable.depth < 15) + return FALSE; + + if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planeMask)) + return FALSE; + + if (!priv || !priv->tex) + return FALSE; + + if (alu != GXcopy) + return FALSE; + + if (!exa->pipe) + return FALSE; + + debug_printf(" ExaPrepareSolid(0x%x)\n", fg); + return xorg_solid_bind_state(exa, priv, fg); +} + +static void +ExaSolid(PixmapPtr pPixmap, int x0, int y0, int x1, int y1) +{ + ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + + debug_printf("\tExaSolid(%d, %d, %d, %d)\n", x0, y0, x1, y1); + +#if 0 + if (x0 == 0 && y0 == 0 && + x1 == priv->tex->width[0] && + y1 == priv->tex->height[0]) { + exa->ctx->clear(exa->ctx, PIPE_CLEAR_COLOR | PIPE_CLEAR_DEPTHSTENCIL, + exa->solid_color, 1., 0); + } else +#endif + xorg_solid(exa, priv, x0, y0, x1, y1) ; +} + +static Bool +ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, + int ydir, int alu, Pixel planeMask) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap); + struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap); + + debug_printf("ExaPrepareCopy\n"); + + if (alu != GXcopy) + return FALSE; + + if (pSrcPixmap->drawable.depth < 15 || pDstPixmap->drawable.depth < 15) + return FALSE; + + if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask)) + return FALSE; + + if (!priv || !src_priv) + return FALSE; + + if (!priv->tex || !src_priv->tex) + return FALSE; + + if (!exa->pipe) + return FALSE; + + exa->copy.src = src_priv; + exa->copy.dst = priv; + + /*XXX disabled until some issues with syncing are fixed */ + return FALSE; +} + +static void +ExaCopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, + int width, int height) +{ + ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap); + + debug_printf("\tExaCopy(srcx=%d, srcy=%d, dstX=%d, dstY=%d, w=%d, h=%d)\n", + srcX, srcY, dstX, dstY, width, height); + + debug_assert(priv == exa->copy.dst); + + xorg_copy_pixmap(exa, exa->copy.dst, dstX, dstY, + exa->copy.src, srcX, srcY, + width, height); +} + +static Bool +ExaPrepareComposite(int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture, + PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +{ + ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + + debug_printf("ExaPrepareComposite\n"); + + return xorg_composite_bind_state(exa, op, pSrcPicture, pMaskPicture, + pDstPicture, + exaGetPixmapDriverPrivate(pSrc), + exaGetPixmapDriverPrivate(pMask), + exaGetPixmapDriverPrivate(pDst)); +} + +static void +ExaComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int width, int height) +{ + ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDst); + + debug_printf("\tExaComposite\n"); + + xorg_composite(exa, priv, srcX, srcY, maskX, maskY, + dstX, dstY, width, height); +} + +static Bool +ExaCheckComposite(int op, + PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + return xorg_composite_accelerated(op, + pSrcPicture, + pMaskPicture, + pDstPicture); +} + +static void * +ExaCreatePixmap(ScreenPtr pScreen, int size, int align) +{ + struct exa_pixmap_priv *priv; + + priv = xcalloc(1, sizeof(struct exa_pixmap_priv)); + if (!priv) + return NULL; + + return priv; +} + +static void +ExaDestroyPixmap(ScreenPtr pScreen, void *dPriv) +{ + struct exa_pixmap_priv *priv = (struct exa_pixmap_priv *)dPriv; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + + if (!priv) + return; + + if (priv->tex) + ms->screen->texture_destroy(priv->tex); + + xfree(priv); +} + +static Bool +ExaPixmapIsOffscreen(PixmapPtr pPixmap) +{ + struct exa_pixmap_priv *priv; + + priv = exaGetPixmapDriverPrivate(pPixmap); + + if (!priv) + return FALSE; + + if (priv->tex) + return TRUE; + + return FALSE; +} + +int +xorg_exa_set_displayed_usage(PixmapPtr pPixmap) +{ + struct exa_pixmap_priv *priv; + priv = exaGetPixmapDriverPrivate(pPixmap); + + if (!priv) { + FatalError("NO PIXMAP PRIVATE\n"); + return 0; + } + + priv->flags |= PIPE_TEXTURE_USAGE_PRIMARY; + + return 0; +} + +int +xorg_exa_set_shared_usage(PixmapPtr pPixmap) +{ + struct exa_pixmap_priv *priv; + priv = exaGetPixmapDriverPrivate(pPixmap); + + if (!priv) { + FatalError("NO PIXMAP PRIVATE\n"); + return 0; + } + + priv->flags |= PIPE_TEXTURE_USAGE_DISPLAY_TARGET; + + return 0; +} + +unsigned +xorg_exa_get_pixmap_handle(PixmapPtr pPixmap, unsigned *stride_out) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_pixmap_priv *priv; + unsigned handle; + unsigned stride; + + if (!ms->exa) { + FatalError("NO MS->EXA\n"); + return 0; + } + + priv = exaGetPixmapDriverPrivate(pPixmap); + + if (!priv) { + FatalError("NO PIXMAP PRIVATE\n"); + return 0; + } + + ms->api->local_handle_from_texture(ms->api, ms->screen, priv->tex, &stride, &handle); + if (stride_out) + *stride_out = stride; + + return handle; +} + +static Bool +ExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, + int depth, int bitsPerPixel, int devKind, + pointer pPixData) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + + if (!priv || pPixData) + return FALSE; + + if (depth <= 0) + depth = pPixmap->drawable.depth; + + if (bitsPerPixel <= 0) + bitsPerPixel = pPixmap->drawable.bitsPerPixel; + + if (width <= 0) + width = pPixmap->drawable.width; + + if (height <= 0) + height = pPixmap->drawable.height; + + if (width <= 0 || height <= 0 || depth <= 0) + return FALSE; + + miModifyPixmapHeader(pPixmap, width, height, depth, + bitsPerPixel, devKind, NULL); + + /* Deal with screen resize */ + if (!priv->tex || + (priv->tex->width[0] != width || + priv->tex->height[0] != height || + priv->tex_flags != priv->flags)) { + struct pipe_texture *texture = NULL; + +#ifdef DRM_MODE_FEATURE_DIRTYFB + if (priv->flags) +#endif + { + struct pipe_texture template; + + memset(&template, 0, sizeof(template)); + template.target = PIPE_TEXTURE_2D; + exa_get_pipe_format(depth, &template.format, &bitsPerPixel); + pf_get_block(template.format, &template.block); + template.width[0] = width; + template.height[0] = height; + template.depth[0] = 1; + template.last_level = 0; + template.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET | priv->flags; + priv->tex_flags = priv->flags; + texture = exa->scrn->texture_create(exa->scrn, &template); + + if (priv->tex) { + struct pipe_surface *dst_surf; + struct pipe_surface *src_surf; + + dst_surf = exa->scrn->get_tex_surface(exa->scrn, texture, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_WRITE); + src_surf = exa_gpu_surface(exa, priv); + exa->pipe->surface_copy(exa->pipe, dst_surf, 0, 0, src_surf, + 0, 0, min(width, texture->width[0]), + min(height, texture->height[0])); + exa->scrn->tex_surface_destroy(dst_surf); + exa->scrn->tex_surface_destroy(src_surf); + } else if (pPixmap->devPrivate.ptr) { + struct pipe_transfer *transfer; + + if (priv->map_count != 0) + FatalError("doing ExaModifyPixmapHeader on mapped buffer\n"); + + transfer = + exa->scrn->get_tex_transfer(exa->scrn, texture, 0, 0, 0, + PIPE_TRANSFER_WRITE, + 0, 0, width, height); + util_copy_rect(exa->scrn->transfer_map(exa->scrn, transfer), + &texture->block, transfer->stride, 0, 0, + width, height, pPixmap->devPrivate.ptr, + pPixmap->devKind, 0, 0); + exa->scrn->transfer_unmap(exa->scrn, transfer); + exa->scrn->tex_transfer_destroy(transfer); + + xfree(pPixmap->devPrivate.ptr); + pPixmap->devPrivate.ptr = NULL; + } + } +#ifdef DRM_MODE_FEATURE_DIRTYFB + else { + xfree(pPixmap->devPrivate.ptr); + pPixmap->devPrivate.ptr = xalloc(pPixmap->drawable.height * + pPixmap->devKind); + } +#endif + + pipe_texture_reference(&priv->tex, texture); + } + + return TRUE; +} + +struct pipe_texture * +xorg_exa_get_texture(PixmapPtr pPixmap) +{ + struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); + struct pipe_texture *tex = NULL; + pipe_texture_reference(&tex, priv->tex); + return tex; +} + +void +xorg_exa_close(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa = ms->exa; + struct pipe_constant_buffer *vsbuf = &exa->vs_const_buffer; + struct pipe_constant_buffer *fsbuf = &exa->fs_const_buffer; + + if (exa->shaders) { + xorg_shaders_destroy(exa->shaders); + } + + if (vsbuf && vsbuf->buffer) + pipe_buffer_reference(&vsbuf->buffer, NULL); + + if (fsbuf && fsbuf->buffer) + pipe_buffer_reference(&fsbuf->buffer, NULL); + + if (exa->cso) { + cso_release_all(exa->cso); + cso_destroy_context(exa->cso); + } + + if (exa->pipe) + exa->pipe->destroy(exa->pipe); + + exaDriverFini(pScrn->pScreen); + xfree(exa); + ms->exa = NULL; +} + +void * +xorg_exa_init(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + struct exa_context *exa; + ExaDriverPtr pExa; + + exa = xcalloc(1, sizeof(struct exa_context)); + if (!exa) + return NULL; + + pExa = exaDriverAlloc(); + if (!pExa) { + goto out_err; + } + + memset(pExa, 0, sizeof(*pExa)); + + pExa->exa_major = 2; + pExa->exa_minor = 2; + pExa->memoryBase = 0; + pExa->memorySize = 0; + pExa->offScreenBase = 0; + pExa->pixmapOffsetAlign = 0; + pExa->pixmapPitchAlign = 1; + pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_HANDLES_PIXMAPS; +#ifdef EXA_SUPPORTS_PREPARE_AUX + pExa->flags |= EXA_SUPPORTS_PREPARE_AUX; +#endif +#ifdef EXA_MIXED_PIXMAPS + pExa->flags |= EXA_MIXED_PIXMAPS; +#endif + pExa->maxX = 8191; /* FIXME */ + pExa->maxY = 8191; /* FIXME */ + + pExa->WaitMarker = ExaWaitMarker; + pExa->MarkSync = ExaMarkSync; + pExa->PrepareSolid = ExaPrepareSolid; + pExa->Solid = ExaSolid; + pExa->DoneSolid = ExaDone; + pExa->PrepareCopy = ExaPrepareCopy; + pExa->Copy = ExaCopy; + pExa->DoneCopy = ExaDone; + pExa->CheckComposite = ExaCheckComposite; + pExa->PrepareComposite = ExaPrepareComposite; + pExa->Composite = ExaComposite; + pExa->DoneComposite = ExaDoneComposite; + pExa->PixmapIsOffscreen = ExaPixmapIsOffscreen; + pExa->DownloadFromScreen = ExaDownloadFromScreen; + pExa->UploadToScreen = ExaUploadToScreen; + pExa->PrepareAccess = ExaPrepareAccess; + pExa->FinishAccess = ExaFinishAccess; + pExa->CreatePixmap = ExaCreatePixmap; + pExa->DestroyPixmap = ExaDestroyPixmap; + pExa->ModifyPixmapHeader = ExaModifyPixmapHeader; + + if (!exaDriverInit(pScrn->pScreen, pExa)) { + goto out_err; + } + + exa->scrn = ms->screen; + exa->pipe = ms->api->create_context(ms->api, exa->scrn); + /* Share context with DRI */ + ms->ctx = exa->pipe; + + exa->cso = cso_create_context(exa->pipe); + exa->shaders = xorg_shaders_create(exa); + + xorg_exa_init_state(exa); + + return (void *)exa; + +out_err: + xorg_exa_close(pScrn); + + return NULL; +} + +struct pipe_surface * +exa_gpu_surface(struct exa_context *exa, struct exa_pixmap_priv *priv) +{ + return exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0, + PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE); + +} + +void xorg_exa_flush(struct exa_context *exa, uint pipeFlushFlags, + struct pipe_fence_handle **fence) +{ + exa->pipe->flush(exa->pipe, pipeFlushFlags, fence); +} + +void xorg_exa_finish(struct exa_context *exa) +{ + struct pipe_fence_handle *fence = NULL; + + xorg_exa_flush(exa, PIPE_FLUSH_RENDER_CACHE, &fence); + + exa->pipe->screen->fence_finish(exa->pipe->screen, fence, 0); + exa->pipe->screen->fence_reference(exa->pipe->screen, &fence, NULL); +} + diff --git a/src/gallium/state_trackers/xorg/xorg_exa.h b/src/gallium/state_trackers/xorg/xorg_exa.h new file mode 100644 index 0000000000..43949b04a4 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_exa.h @@ -0,0 +1,57 @@ +#ifndef XORG_EXA_H +#define XORG_EXA_H + +#include "xorg_tracker.h" + +#include <pipe/p_state.h> + +struct cso_context; +struct xorg_shaders; + +/* src + mask + dst */ +#define MAX_EXA_SAMPLERS 3 + +struct exa_context +{ + ExaDriverPtr pExa; + struct pipe_context *pipe; + struct pipe_screen *scrn; + struct cso_context *cso; + struct xorg_shaders *shaders; + + struct pipe_constant_buffer vs_const_buffer; + struct pipe_constant_buffer fs_const_buffer; + + struct pipe_texture *bound_textures[MAX_EXA_SAMPLERS]; + int num_bound_samplers; + + float solid_color[4]; + boolean has_solid_color; + + struct { + struct exa_pixmap_priv *src; + struct exa_pixmap_priv *dst; + } copy; +}; + + +struct exa_pixmap_priv +{ + int flags; + int tex_flags; + + struct pipe_texture *tex; + struct pipe_texture *depth_stencil_tex; + + struct pipe_transfer *map_transfer; + unsigned map_count; +}; + +struct pipe_surface * +exa_gpu_surface(struct exa_context *exa, struct exa_pixmap_priv *priv); + +void xorg_exa_flush(struct exa_context *exa, uint pipeFlushFlags, + struct pipe_fence_handle **fence); +void xorg_exa_finish(struct exa_context *exa); + +#endif diff --git a/src/gallium/state_trackers/xorg/xorg_exa_tgsi.c b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.c new file mode 100644 index 0000000000..694eded09a --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.c @@ -0,0 +1,489 @@ +#include "xorg_exa_tgsi.h" + +/*### stupidity defined in X11/extensions/XI.h */ +#undef Absolute + +#include "pipe/p_format.h" +#include "pipe/p_context.h" +#include "pipe/p_state.h" +#include "pipe/p_inlines.h" +#include "pipe/p_shader_tokens.h" + +#include "util/u_memory.h" +#include "util/u_simple_shaders.h" + +#include "tgsi/tgsi_ureg.h" + +#include "cso_cache/cso_context.h" +#include "cso_cache/cso_hash.h" + +/* Vertex shader: + * IN[0] = vertex pos + * IN[1] = src tex coord | solid fill color + * IN[2] = mask tex coord + * IN[3] = dst tex coord + * CONST[0] = (2/dst_width, 2/dst_height, 1, 1) + * CONST[1] = (-1, -1, 0, 0) + * + * OUT[0] = vertex pos + * OUT[1] = src tex coord | solid fill color + * OUT[2] = mask tex coord + * OUT[3] = dst tex coord + */ + +/* Fragment shader: + * SAMP[0] = src + * SAMP[1] = mask + * SAMP[2] = dst + * IN[0] = pos src | solid fill color + * IN[1] = pos mask + * IN[2] = pos dst + * CONST[0] = (0, 0, 0, 1) + * + * OUT[0] = color + */ + +struct xorg_shaders { + struct exa_context *exa; + + struct cso_hash *vs_hash; + struct cso_hash *fs_hash; +}; + +static const char over_op[] = + "SUB TEMP[3], CONST[0].wwww, TEMP[1].wwww\n" + "MUL TEMP[3], TEMP[0], TEMP[3]\n" + "ADD TEMP[0], TEMP[3], TEMP[0]\n"; + + +static INLINE void +create_preamble(struct ureg_program *ureg) +{ +} + + +static INLINE void +src_in_mask(struct ureg_program *ureg, + struct ureg_dst dst, + struct ureg_src src, + struct ureg_src mask) +{ + /* MUL dst, src, mask.wwww */ + ureg_MUL(ureg, dst, src, + ureg_scalar(mask, TGSI_SWIZZLE_W)); +} + +static struct ureg_src +vs_normalize_coords(struct ureg_program *ureg, struct ureg_src coords, + struct ureg_src const0, struct ureg_src const1) +{ + struct ureg_dst tmp = ureg_DECL_temporary(ureg); + struct ureg_src ret; + ureg_MUL(ureg, tmp, coords, const0); + ureg_ADD(ureg, tmp, ureg_src(tmp), const1); + ret = ureg_src(tmp); + ureg_release_temporary(ureg, tmp); + return ret; +} + +static void +linear_gradient(struct ureg_program *ureg, + struct ureg_dst out, + struct ureg_src pos, + struct ureg_src sampler, + struct ureg_src coords, + struct ureg_src const0124, + struct ureg_src matrow0, + struct ureg_src matrow1, + struct ureg_src matrow2) +{ + struct ureg_dst temp0 = ureg_DECL_temporary(ureg); + struct ureg_dst temp1 = ureg_DECL_temporary(ureg); + struct ureg_dst temp2 = ureg_DECL_temporary(ureg); + struct ureg_dst temp3 = ureg_DECL_temporary(ureg); + struct ureg_dst temp4 = ureg_DECL_temporary(ureg); + struct ureg_dst temp5 = ureg_DECL_temporary(ureg); + + ureg_MOV(ureg, + ureg_writemask(temp0, TGSI_WRITEMASK_XY), pos); + ureg_MOV(ureg, + ureg_writemask(temp0, TGSI_WRITEMASK_Z), + ureg_scalar(const0124, TGSI_SWIZZLE_Y)); + + ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0)); + ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0)); + ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0)); + ureg_RCP(ureg, temp3, ureg_src(temp3)); + ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3)); + ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3)); + + ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_X), + ureg_src(temp1)); + ureg_MOV(ureg, ureg_writemask(temp4, TGSI_WRITEMASK_Y), + ureg_src(temp2)); + + ureg_MUL(ureg, temp0, + ureg_scalar(coords, TGSI_SWIZZLE_Y), + ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_Y)); + ureg_MAD(ureg, temp1, + ureg_scalar(coords, TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(temp4), TGSI_SWIZZLE_X), + ureg_src(temp0)); + + ureg_MUL(ureg, temp2, + ureg_src(temp1), + ureg_scalar(coords, TGSI_SWIZZLE_Z)); + + ureg_TEX(ureg, out, + TGSI_TEXTURE_1D, ureg_src(temp2), sampler); + + ureg_release_temporary(ureg, temp0); + ureg_release_temporary(ureg, temp1); + ureg_release_temporary(ureg, temp2); + ureg_release_temporary(ureg, temp3); + ureg_release_temporary(ureg, temp4); + ureg_release_temporary(ureg, temp5); +} + + +static void +radial_gradient(struct ureg_program *ureg, + struct ureg_dst out, + struct ureg_src pos, + struct ureg_src sampler, + struct ureg_src coords, + struct ureg_src const0124, + struct ureg_src matrow0, + struct ureg_src matrow1, + struct ureg_src matrow2) +{ + struct ureg_dst temp0 = ureg_DECL_temporary(ureg); + struct ureg_dst temp1 = ureg_DECL_temporary(ureg); + struct ureg_dst temp2 = ureg_DECL_temporary(ureg); + struct ureg_dst temp3 = ureg_DECL_temporary(ureg); + struct ureg_dst temp4 = ureg_DECL_temporary(ureg); + struct ureg_dst temp5 = ureg_DECL_temporary(ureg); + + ureg_MOV(ureg, + ureg_writemask(temp0, TGSI_WRITEMASK_XY), + pos); + ureg_MOV(ureg, + ureg_writemask(temp0, TGSI_WRITEMASK_Z), + ureg_scalar(const0124, TGSI_SWIZZLE_Y)); + + ureg_DP3(ureg, temp1, matrow0, ureg_src(temp0)); + ureg_DP3(ureg, temp2, matrow1, ureg_src(temp0)); + ureg_DP3(ureg, temp3, matrow2, ureg_src(temp0)); + ureg_RCP(ureg, temp3, ureg_src(temp3)); + ureg_MUL(ureg, temp1, ureg_src(temp1), ureg_src(temp3)); + ureg_MUL(ureg, temp2, ureg_src(temp2), ureg_src(temp3)); + + ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_X), + ureg_src(temp1)); + ureg_MOV(ureg, ureg_writemask(temp5, TGSI_WRITEMASK_Y), + ureg_src(temp2)); + + ureg_MUL(ureg, temp0, ureg_scalar(coords, TGSI_SWIZZLE_Y), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y)); + ureg_MAD(ureg, temp1, + ureg_scalar(coords, TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), + ureg_src(temp0)); + ureg_ADD(ureg, temp1, + ureg_src(temp1), ureg_src(temp1)); + ureg_MUL(ureg, temp3, + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_Y)); + ureg_MAD(ureg, temp4, + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), + ureg_scalar(ureg_src(temp5), TGSI_SWIZZLE_X), + ureg_src(temp3)); + ureg_MOV(ureg, temp4, ureg_negate(ureg_src(temp4))); + ureg_MUL(ureg, temp2, + ureg_scalar(coords, TGSI_SWIZZLE_Z), + ureg_src(temp4)); + ureg_MUL(ureg, temp0, + ureg_scalar(const0124, TGSI_SWIZZLE_W), + ureg_src(temp2)); + ureg_MUL(ureg, temp3, + ureg_src(temp1), ureg_src(temp1)); + ureg_SUB(ureg, temp2, + ureg_src(temp3), ureg_src(temp0)); + ureg_RSQ(ureg, temp2, ureg_abs(ureg_src(temp2))); + ureg_RCP(ureg, temp2, ureg_src(temp2)); + ureg_SUB(ureg, temp1, + ureg_src(temp2), ureg_src(temp1)); + ureg_ADD(ureg, temp0, + ureg_scalar(coords, TGSI_SWIZZLE_Z), + ureg_scalar(coords, TGSI_SWIZZLE_Z)); + ureg_RCP(ureg, temp0, ureg_src(temp0)); + ureg_MUL(ureg, temp2, + ureg_src(temp1), ureg_src(temp0)); + ureg_TEX(ureg, out, TGSI_TEXTURE_1D, + ureg_src(temp2), sampler); + + ureg_release_temporary(ureg, temp0); + ureg_release_temporary(ureg, temp1); + ureg_release_temporary(ureg, temp2); + ureg_release_temporary(ureg, temp3); + ureg_release_temporary(ureg, temp4); + ureg_release_temporary(ureg, temp5); +} + +static void * +create_vs(struct pipe_context *pipe, + unsigned vs_traits) +{ + struct ureg_program *ureg; + struct ureg_src src; + struct ureg_dst dst; + struct ureg_src const0, const1; + boolean is_fill = vs_traits & VS_FILL; + boolean is_composite = vs_traits & VS_COMPOSITE; + boolean has_mask = vs_traits & VS_MASK; + + ureg = ureg_create(TGSI_PROCESSOR_VERTEX); + if (ureg == NULL) + return 0; + + const0 = ureg_DECL_constant(ureg); + const1 = ureg_DECL_constant(ureg); + + /* it has to be either a fill or a composite op */ + debug_assert(is_fill ^ is_composite); + + src = ureg_DECL_vs_input(ureg, + TGSI_SEMANTIC_POSITION, 0); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); + src = vs_normalize_coords(ureg, src, + const0, const1); + ureg_MOV(ureg, dst, src); + + + if (is_composite) { + src = ureg_DECL_vs_input(ureg, + TGSI_SEMANTIC_GENERIC, 1); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 1); + ureg_MOV(ureg, dst, src); + } + if (is_fill) { + src = ureg_DECL_vs_input(ureg, + TGSI_SEMANTIC_COLOR, 0); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); + ureg_MOV(ureg, dst, src); + } + + if (has_mask) { + src = ureg_DECL_vs_input(ureg, + TGSI_SEMANTIC_GENERIC, 2); + dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 2); + ureg_MOV(ureg, dst, src); + } + + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} + +static void * +create_fs(struct pipe_context *pipe, + unsigned fs_traits) +{ + struct ureg_program *ureg; + struct ureg_src /*dst_sampler,*/ src_sampler, mask_sampler; + struct ureg_src /*dst_pos,*/ src_input, mask_pos; + struct ureg_dst src, mask; + struct ureg_dst out; + boolean has_mask = fs_traits & FS_MASK; + boolean is_fill = fs_traits & FS_FILL; + boolean is_composite = fs_traits & FS_COMPOSITE; + boolean is_solid = fs_traits & FS_SOLID_FILL; + boolean is_lingrad = fs_traits & FS_LINGRAD_FILL; + boolean is_radgrad = fs_traits & FS_RADGRAD_FILL; + + ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); + if (ureg == NULL) + return 0; + + /* it has to be either a fill or a composite op */ + debug_assert(is_fill ^ is_composite); + + out = ureg_DECL_output(ureg, + TGSI_SEMANTIC_COLOR, + 0); + + if (is_composite) { + src_sampler = ureg_DECL_sampler(ureg, 0); + src_input = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_POSITION, + 0, + TGSI_INTERPOLATE_PERSPECTIVE); + } else { + debug_assert(is_fill); + if (is_solid) + src_input = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_COLOR, + 0, + TGSI_INTERPOLATE_PERSPECTIVE); + else + src_input = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_POSITION, + 0, + TGSI_INTERPOLATE_PERSPECTIVE); + } + + if (has_mask) { + mask_sampler = ureg_DECL_sampler(ureg, 1); + mask_pos = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_POSITION, + 1, + TGSI_INTERPOLATE_PERSPECTIVE); + } + +#if 0 /* unused right now */ + dst_sampler = ureg_DECL_sampler(ureg, 2); + dst_pos = ureg_DECL_fs_input(ureg, + TGSI_SEMANTIC_POSITION, + 2, + TGSI_INTERPOLATE_PERSPECTIVE); +#endif + + if (is_composite) { + if (has_mask) + src = ureg_DECL_temporary(ureg); + else + src = out; + ureg_TEX(ureg, src, + TGSI_TEXTURE_2D, src_input, src_sampler); + } else if (is_fill) { + if (is_solid) { + if (has_mask) + src = ureg_dst(src_input); + else + ureg_MOV(ureg, out, src_input); + } else if (is_lingrad || is_radgrad) { + struct ureg_src coords, const0124, + matrow0, matrow1, matrow2; + + if (has_mask) + src = ureg_DECL_temporary(ureg); + else + src = out; + + coords = ureg_DECL_constant(ureg); + const0124 = ureg_DECL_constant(ureg); + matrow0 = ureg_DECL_constant(ureg); + matrow1 = ureg_DECL_constant(ureg); + matrow2 = ureg_DECL_constant(ureg); + + if (is_lingrad) { + linear_gradient(ureg, src, + src_input, src_sampler, + coords, const0124, + matrow0, matrow1, matrow2); + } else if (is_radgrad) { + radial_gradient(ureg, src, + src_input, src_sampler, + coords, const0124, + matrow0, matrow1, matrow2); + } + } else + debug_assert(!"Unknown fill type!"); + } + + if (has_mask) { + mask = ureg_DECL_temporary(ureg); + ureg_TEX(ureg, mask, + TGSI_TEXTURE_2D, mask_pos, mask_sampler); + /* src IN mask */ + src_in_mask(ureg, out, ureg_src(src), ureg_src(mask)); + ureg_release_temporary(ureg, mask); + } + + ureg_END(ureg); + + return ureg_create_shader_and_destroy(ureg, pipe); +} + +struct xorg_shaders * xorg_shaders_create(struct exa_context *exa) +{ + struct xorg_shaders *sc = CALLOC_STRUCT(xorg_shaders); + + sc->exa = exa; + sc->vs_hash = cso_hash_create(); + sc->fs_hash = cso_hash_create(); + + return sc; +} + +static void +cache_destroy(struct cso_context *cso, + struct cso_hash *hash, + unsigned processor) +{ + struct cso_hash_iter iter = cso_hash_first_node(hash); + while (!cso_hash_iter_is_null(iter)) { + void *shader = (void *)cso_hash_iter_data(iter); + if (processor == PIPE_SHADER_FRAGMENT) { + cso_delete_fragment_shader(cso, shader); + } else if (processor == PIPE_SHADER_VERTEX) { + cso_delete_vertex_shader(cso, shader); + } + iter = cso_hash_erase(hash, iter); + } + cso_hash_delete(hash); +} + +void xorg_shaders_destroy(struct xorg_shaders *sc) +{ + cache_destroy(sc->exa->cso, sc->vs_hash, + PIPE_SHADER_VERTEX); + cache_destroy(sc->exa->cso, sc->fs_hash, + PIPE_SHADER_FRAGMENT); + + free(sc); +} + +static INLINE void * +shader_from_cache(struct pipe_context *pipe, + unsigned type, + struct cso_hash *hash, + unsigned key) +{ + void *shader = 0; + + struct cso_hash_iter iter = cso_hash_find(hash, key); + + if (cso_hash_iter_is_null(iter)) { + if (type == PIPE_SHADER_VERTEX) + shader = create_vs(pipe, key); + else + shader = create_fs(pipe, key); + cso_hash_insert(hash, key, shader); + } else + shader = (void *)cso_hash_iter_data(iter); + + return shader; +} + +struct xorg_shader xorg_shaders_get(struct xorg_shaders *sc, + unsigned vs_traits, + unsigned fs_traits) +{ + struct xorg_shader shader = {0}; + void *vs, *fs; + + vs = shader_from_cache(sc->exa->pipe, PIPE_SHADER_VERTEX, + sc->vs_hash, vs_traits); + fs = shader_from_cache(sc->exa->pipe, PIPE_SHADER_FRAGMENT, + sc->fs_hash, fs_traits); + + debug_assert(vs && fs); + if (!vs || !fs) + return shader; + + shader.vs = vs; + shader.fs = fs; + + return shader; +} diff --git a/src/gallium/state_trackers/xorg/xorg_exa_tgsi.h b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.h new file mode 100644 index 0000000000..1535a0c8c3 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_exa_tgsi.h @@ -0,0 +1,43 @@ +#ifndef XORG_EXA_TGSI_H +#define XORG_EXA_TGSI_H + +#include "xorg_exa.h" + +enum xorg_vs_traits { + VS_COMPOSITE = 1 << 0, + VS_MASK = 1 << 1, + VS_SOLID_FILL = 1 << 2, + VS_LINGRAD_FILL = 1 << 3, + VS_RADGRAD_FILL = 1 << 4, + VS_FILL = (VS_SOLID_FILL | + VS_LINGRAD_FILL | + VS_RADGRAD_FILL) + /*VS_TRANSFORM = 1 << 5*/ +}; + +enum xorg_fs_traits { + FS_COMPOSITE = 1 << 0, + FS_MASK = 1 << 1, + FS_SOLID_FILL = 1 << 2, + FS_LINGRAD_FILL = 1 << 3, + FS_RADGRAD_FILL = 1 << 4, + FS_FILL = (FS_SOLID_FILL | + FS_LINGRAD_FILL | + FS_RADGRAD_FILL) +}; + +struct xorg_shader { + void *fs; + void *vs; +}; + +struct xorg_shaders; + +struct xorg_shaders *xorg_shaders_create(struct exa_context *exa); +void xorg_shaders_destroy(struct xorg_shaders *shaders); + +struct xorg_shader xorg_shaders_get(struct xorg_shaders *shaders, + unsigned vs_traits, + unsigned fs_traits); + +#endif diff --git a/src/gallium/state_trackers/xorg/xorg_output.c b/src/gallium/state_trackers/xorg/xorg_output.c new file mode 100644 index 0000000000..950af942f5 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_output.c @@ -0,0 +1,296 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#include "xorg-server.h" +#include <xf86.h> +#include <xf86i2c.h> +#include <xf86Crtc.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> + +#define DPMS_SERVER +#include <X11/extensions/dpms.h> + +#include "X11/Xatom.h" + +#include "xorg_tracker.h" + +static char *connector_enum_list[] = { + "Unknown", + "VGA", + "DVI-I", + "DVI-D", + "DVI-A", + "Composite", + "SVIDEO", + "LVDS", + "Component", + "9-pin DIN", + "DisplayPort", + "HDMI Type A", + "HDMI Type B", +}; + +static void +dpms(xf86OutputPtr output, int mode) +{ +} + +static void +save(xf86OutputPtr output) +{ +} + +static void +restore(xf86OutputPtr output) +{ +} + +static int +mode_valid(xf86OutputPtr output, DisplayModePtr pMode) +{ + return MODE_OK; +} + +static Bool +mode_fixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +static void +prepare(xf86OutputPtr output) +{ + dpms(output, DPMSModeOff); +} + +static void +mode_set(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ +} + +static void +commit(xf86OutputPtr output) +{ + dpms(output, DPMSModeOn); + + if (output->scrn->pScreen != NULL) + xf86_reload_cursors(output->scrn->pScreen); +} + +static xf86OutputStatus +detect(xf86OutputPtr output) +{ + drmModeConnectorPtr drm_connector = output->driver_private; + + switch (drm_connector->connection) { + case DRM_MODE_CONNECTED: + return XF86OutputStatusConnected; + case DRM_MODE_DISCONNECTED: + return XF86OutputStatusDisconnected; + default: + return XF86OutputStatusUnknown; + } +} + +static DisplayModePtr +get_modes(xf86OutputPtr output) +{ + drmModeConnectorPtr drm_connector = output->driver_private; + drmModeModeInfoPtr drm_mode = NULL; + DisplayModePtr modes = NULL, mode = NULL; + int i; + + for (i = 0; i < drm_connector->count_modes; i++) { + drm_mode = &drm_connector->modes[i]; + if (drm_mode) { + mode = xcalloc(1, sizeof(DisplayModeRec)); + if (!mode) + continue; + mode->type = 0; + mode->Clock = drm_mode->clock; + mode->HDisplay = drm_mode->hdisplay; + mode->HSyncStart = drm_mode->hsync_start; + mode->HSyncEnd = drm_mode->hsync_end; + mode->HTotal = drm_mode->htotal; + mode->VDisplay = drm_mode->vdisplay; + mode->VSyncStart = drm_mode->vsync_start; + mode->VSyncEnd = drm_mode->vsync_end; + mode->VTotal = drm_mode->vtotal; + mode->Flags = drm_mode->flags; + mode->HSkew = drm_mode->hskew; + mode->VScan = drm_mode->vscan; + mode->VRefresh = xf86ModeVRefresh(mode); + mode->Private = (void *)drm_mode; + xf86SetModeDefaultName(mode); + modes = xf86ModesAdd(modes, mode); + xf86PrintModeline(0, mode); + } + } + + return modes; +} + +static void +destroy(xf86OutputPtr output) +{ + drmModeFreeConnector(output->driver_private); +} + +static void +create_resources(xf86OutputPtr output) +{ +#ifdef RANDR_12_INTERFACE +#endif /* RANDR_12_INTERFACE */ +} + +#ifdef RANDR_12_INTERFACE +static Bool +set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value) +{ + return TRUE; +} +#endif /* RANDR_12_INTERFACE */ + +#ifdef RANDR_13_INTERFACE +static Bool +get_property(xf86OutputPtr output, Atom property) +{ + return TRUE; +} +#endif /* RANDR_13_INTERFACE */ + +#ifdef RANDR_GET_CRTC_INTERFACE +static xf86CrtcPtr +get_crtc(xf86OutputPtr output) +{ + return NULL; +} +#endif + +static const xf86OutputFuncsRec output_funcs = { + .create_resources = create_resources, + .dpms = dpms, + .save = save, + .restore = restore, + .mode_valid = mode_valid, + .mode_fixup = mode_fixup, + .prepare = prepare, + .mode_set = mode_set, + .commit = commit, + .detect = detect, + .get_modes = get_modes, +#ifdef RANDR_12_INTERFACE + .set_property = set_property, +#endif +#ifdef RANDR_13_INTERFACE + .get_property = get_property, +#endif + .destroy = destroy, +#ifdef RANDR_GET_CRTC_INTERFACE + .get_crtc = get_crtc, +#endif +}; + +void +output_init(ScrnInfoPtr pScrn) +{ + modesettingPtr ms = modesettingPTR(pScrn); + xf86OutputPtr output; + drmModeResPtr res; + drmModeConnectorPtr drm_connector = NULL; + drmModeEncoderPtr drm_encoder = NULL; + char *name; + int c, v, p; + + res = drmModeGetResources(ms->fd); + if (res == 0) { + DRV_ERROR("Failed drmModeGetResources\n"); + return; + } + + for (c = 0; c < res->count_connectors; c++) { + drm_connector = drmModeGetConnector(ms->fd, res->connectors[c]); + if (!drm_connector) + goto out; + +#if 0 + for (p = 0; p < drm_connector->count_props; p++) { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(ms->fd, drm_connector->props[p]); + + name = NULL; + if (prop) { + ErrorF("VALUES %d\n", prop->count_values); + + for (v = 0; v < prop->count_values; v++) + ErrorF("%s %lld\n", prop->name, prop->values[v]); + } + } +#else + (void)p; + (void)v; +#endif + + name = connector_enum_list[drm_connector->connector_type]; + + output = xf86OutputCreate(pScrn, &output_funcs, name); + if (!output) + continue; + + drm_encoder = drmModeGetEncoder(ms->fd, drm_connector->encoders[0]); + if (drm_encoder) { + output->possible_crtcs = drm_encoder->possible_crtcs; + output->possible_clones = drm_encoder->possible_clones; + } else { + output->possible_crtcs = 0; + output->possible_clones = 0; + } + output->driver_private = drm_connector; + output->subpixel_order = SubPixelHorizontalRGB; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + } + + out: + drmModeFreeResources(res); +} + +/* vim: set sw=4 ts=8 sts=4: */ diff --git a/src/gallium/state_trackers/xorg/xorg_tracker.h b/src/gallium/state_trackers/xorg/xorg_tracker.h new file mode 100644 index 0000000000..b1ab783a15 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_tracker.h @@ -0,0 +1,155 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +#ifndef _XORG_TRACKER_H_ +#define _XORG_TRACKER_H_ + +#include <stddef.h> +#include <stdint.h> +#include <errno.h> +#include <drm.h> +#include <xf86drm.h> +#include <xf86drmMode.h> +#include <xorg-server.h> +#include <xf86.h> +#include "xf86Crtc.h" +#include <exa.h> + +#ifdef DRM_MODE_FEATURE_DIRTYFB +#include <damage.h> +#endif + +#include "pipe/p_screen.h" +#include "state_tracker/drm_api.h" + +#define DRV_ERROR(msg) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, msg); + +typedef struct +{ + int lastInstance; + int refCount; + ScrnInfoPtr pScrn_1; + ScrnInfoPtr pScrn_2; +} EntRec, *EntPtr; + +typedef struct _modesettingRec +{ + /* drm */ + int fd; + unsigned fb_id; + + /* X */ + EntPtr entityPrivate; + + int Chipset; + EntityInfoPtr pEnt; + struct pci_device *PciInfo; + + Bool noAccel; + Bool SWCursor; + CloseScreenProcPtr CloseScreen; + + /* Broken-out options. */ + OptionInfoPtr Options; + + unsigned int SaveGeneration; + + void (*blockHandler)(int, pointer, pointer, pointer); + CreateScreenResourcesProcPtr createScreenResources; + + /* gallium */ + struct drm_api *api; + struct pipe_screen *screen; + struct pipe_context *ctx; + boolean d_depth_bits_last; + boolean ds_depth_bits_last; + + /* exa */ + void *exa; + Bool noEvict; + +#ifdef DRM_MODE_FEATURE_DIRTYFB + DamagePtr damage; +#endif +} modesettingRec, *modesettingPtr; + +#define modesettingPTR(p) ((modesettingPtr)((p)->driverPrivate)) + + +/*********************************************************************** + * xorg_exa.c + */ +struct pipe_texture * +xorg_exa_get_texture(PixmapPtr pPixmap); + +unsigned +xorg_exa_get_pixmap_handle(PixmapPtr pPixmap, unsigned *stride); + +int +xorg_exa_set_displayed_usage(PixmapPtr pPixmap); + +int +xorg_exa_set_shared_usage(PixmapPtr pPixmap); + +void * +xorg_exa_init(ScrnInfoPtr pScrn); + +void +xorg_exa_close(ScrnInfoPtr pScrn); + + +/*********************************************************************** + * xorg_dri2.c + */ +Bool +driScreenInit(ScreenPtr pScreen); + +void +driCloseScreen(ScreenPtr pScreen); + + +/*********************************************************************** + * xorg_crtc.c + */ +void +crtc_init(ScrnInfoPtr pScrn); + +void +crtc_cursor_destroy(xf86CrtcPtr crtc); + + +/*********************************************************************** + * xorg_output.c + */ +void +output_init(ScrnInfoPtr pScrn); + + +#endif /* _XORG_TRACKER_H_ */ diff --git a/src/gallium/state_trackers/xorg/xorg_winsys.h b/src/gallium/state_trackers/xorg/xorg_winsys.h new file mode 100644 index 0000000000..47ee4b9ffd --- /dev/null +++ b/src/gallium/state_trackers/xorg/xorg_winsys.h @@ -0,0 +1,49 @@ +/* + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Author: Alan Hourihane <alanh@tungstengraphics.com> + * Author: Jakob Bornecrantz <wallbraker@gmail.com> + * + */ + +/* + * File with all the junk needed to personalize the a xorg driver. + */ + +#ifndef _XORG_WINSYS_H_ +#define _XORG_WINSYS_H_ + +#include "xorg-server.h" +#include "xf86.h" +#include "pciaccess.h" + +#ifndef XSERVER_LIBPCIACCESS +#error "libpciaccess needed" +#endif + +void xorg_tracker_set_functions(ScrnInfoPtr scrn); +const OptionInfoRec * xorg_tracker_available_options(int chipid, int busid); + +#endif |