diff options
Diffstat (limited to 'src/mesa/state_tracker')
30 files changed, 1352 insertions, 225 deletions
diff --git a/src/mesa/state_tracker/acc2.c b/src/mesa/state_tracker/acc2.c new file mode 100644 index 00000000000..fa5de2b764c --- /dev/null +++ b/src/mesa/state_tracker/acc2.c @@ -0,0 +1,319 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + /* + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/macros.h" + +#include "st_context.h" +#include "st_cb_accum.h" +#include "st_cb_fbo.h" +#include "st_draw.h" +#include "st_format.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_inlines.h" +#include "util/p_tile.h" + + +#define UNCLAMPED_FLOAT_TO_SHORT(us, f) \ + us = ( (short) ( CLAMP((f), -1.0, 1.0) * 32767.0F) ) + + +/** + * For hardware that supports deep color buffers, we could accelerate + * most/all the accum operations with blending/texturing. + * For now, just use the get/put_tile() functions and do things in software. + */ + + +static void +acc_get_tile_rgba(struct pipe_context *pipe, struct pipe_surface *acc_ps, + uint x, uint y, uint w, uint h, float *p) +{ + const enum pipe_format f = acc_ps->format; + const int cpp = acc_ps->cpp; + + acc_ps->format = PIPE_FORMAT_R16G16B16A16_SNORM; + acc_ps->cpp = 8; + + pipe_get_tile_rgba(pipe, acc_ps, x, y, w, h, p); + + acc_ps->format = f; + acc_ps->cpp = cpp; +} + + +static void +acc_put_tile_rgba(struct pipe_context *pipe, struct pipe_surface *acc_ps, + uint x, uint y, uint w, uint h, const float *p) +{ + enum pipe_format f = acc_ps->format; + const int cpp = acc_ps->cpp; + + acc_ps->format = PIPE_FORMAT_R16G16B16A16_SNORM; + acc_ps->cpp = 8; + + pipe_put_tile_rgba(pipe, acc_ps, x, y, w, h, p); + + acc_ps->format = f; + acc_ps->cpp = cpp; +} + + + +void +st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb) +{ + struct pipe_context *pipe = ctx->st->pipe; + struct st_renderbuffer *acc_strb = st_renderbuffer(rb); + struct pipe_surface *acc_ps = acc_strb->surface; + const GLint xpos = ctx->DrawBuffer->_Xmin; + const GLint ypos = ctx->DrawBuffer->_Ymin; + const GLint width = ctx->DrawBuffer->_Xmax - xpos; + const GLint height = ctx->DrawBuffer->_Ymax - ypos; + const GLfloat r = ctx->Accum.ClearColor[0]; + const GLfloat g = ctx->Accum.ClearColor[1]; + const GLfloat b = ctx->Accum.ClearColor[2]; + const GLfloat a = ctx->Accum.ClearColor[3]; + GLfloat *accBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + int i; + +#if 1 + GLvoid *map; + + map = pipe_surface_map(acc_ps); + switch (acc_strb->format) { + case PIPE_FORMAT_R16G16B16A16_SNORM: + { + GLshort r = FLOAT_TO_SHORT(ctx->Accum.ClearColor[0]); + GLshort g = FLOAT_TO_SHORT(ctx->Accum.ClearColor[1]); + GLshort b = FLOAT_TO_SHORT(ctx->Accum.ClearColor[2]); + GLshort a = FLOAT_TO_SHORT(ctx->Accum.ClearColor[3]); + int i, j; + for (i = 0; i < height; i++) { + GLshort *dst = ((GLshort *) map + + ((ypos + i) * acc_ps->pitch + xpos) * 4); + for (j = 0; j < width; j++) { + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = a; + dst += 4; + } + } + } + break; + default: + _mesa_problem(ctx, "unexpected format in st_clear_accum_buffer()"); + } + + pipe_surface_unmap(acc_ps); + +#else + for (i = 0; i < width * height; i++) { + accBuf[i*4+0] = r; + accBuf[i*4+1] = g; + accBuf[i*4+2] = b; + accBuf[i*4+3] = a; + } + + acc_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf); +#endif +} + + +/** For ADD/MULT */ +static void +accum_mad(struct pipe_context *pipe, GLfloat scale, GLfloat bias, + GLint xpos, GLint ypos, GLint width, GLint height, + struct pipe_surface *acc_ps) +{ + GLfloat *accBuf; + GLint i; + + accBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + + pipe_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf); + + for (i = 0; i < 4 * width * height; i++) { + accBuf[i] = accBuf[i] * scale + bias; + } + + pipe_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf); + + free(accBuf); +} + + +static void +accum_accum(struct pipe_context *pipe, GLfloat value, + GLint xpos, GLint ypos, GLint width, GLint height, + struct pipe_surface *acc_ps, + struct pipe_surface *color_ps) +{ + GLfloat *colorBuf, *accBuf; + GLint i; + + colorBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + accBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + + pipe_get_tile_rgba(pipe, color_ps, xpos, ypos, width, height, colorBuf); + acc_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf); + + for (i = 0; i < 4 * width * height; i++) { + accBuf[i] = accBuf[i] + colorBuf[i] * value; + } + + acc_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf); + + free(colorBuf); + free(accBuf); +} + + +static void +accum_load(struct pipe_context *pipe, GLfloat value, + GLint xpos, GLint ypos, GLint width, GLint height, + struct pipe_surface *acc_ps, + struct pipe_surface *color_ps) +{ + GLfloat *buf; + GLint i; + + buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + + pipe_get_tile_rgba(pipe, color_ps, xpos, ypos, width, height, buf); + + for (i = 0; i < 4 * width * height; i++) { + buf[i] = buf[i] * value; + } + + acc_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, buf); + + free(buf); +} + + +static void +accum_return(GLcontext *ctx, GLfloat value, + GLint xpos, GLint ypos, GLint width, GLint height, + struct pipe_surface *acc_ps, + struct pipe_surface *color_ps) +{ + struct pipe_context *pipe = ctx->st->pipe; + const GLubyte *colormask = ctx->Color.ColorMask; + GLfloat *abuf, *cbuf = NULL; + GLint i, ch; + + abuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + + acc_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, abuf); + + if (!colormask[0] || !colormask[1] || !colormask[2] || !colormask[3]) { + cbuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + pipe_get_tile_rgba(pipe, color_ps, xpos, ypos, width, height, cbuf); + } + + for (i = 0; i < width * height; i++) { + for (ch = 0; ch < 4; ch++) { + if (colormask[ch]) { + GLfloat val = abuf[i * 4 + ch] * value; + abuf[i * 4 + ch] = CLAMP(val, 0.0, 1.0); + } + else { + abuf[i * 4 + ch] = cbuf[i * 4 + ch]; + } + } + } + + pipe_put_tile_rgba(pipe, color_ps, xpos, ypos, width, height, abuf); + + free(abuf); + if (cbuf) + free(cbuf); +} + + +static void +st_Accum(GLcontext *ctx, GLenum op, GLfloat value) +{ + struct st_context *st = ctx->st; + struct pipe_context *pipe = st->pipe; + struct st_renderbuffer *acc_strb + = st_renderbuffer(ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer); + struct st_renderbuffer *color_strb + = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); + struct pipe_surface *acc_ps = acc_strb->surface; + struct pipe_surface *color_ps = color_strb->surface; + + const GLint xpos = ctx->DrawBuffer->_Xmin; + const GLint ypos = ctx->DrawBuffer->_Ymin; + const GLint width = ctx->DrawBuffer->_Xmax - xpos; + const GLint height = ctx->DrawBuffer->_Ymax - ypos; + + /* make sure color bufs aren't cached */ + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + + switch (op) { + case GL_ADD: + if (value != 0.0F) { + accum_mad(pipe, 1.0, value, xpos, ypos, width, height, acc_ps); + } + break; + case GL_MULT: + if (value != 1.0F) { + accum_mad(pipe, value, 0.0, xpos, ypos, width, height, acc_ps); + } + break; + case GL_ACCUM: + if (value != 0.0F) { + accum_accum(pipe, value, xpos, ypos, width, height, acc_ps, color_ps); + } + break; + case GL_LOAD: + accum_load(pipe, value, xpos, ypos, width, height, acc_ps, color_ps); + break; + case GL_RETURN: + accum_return(ctx, value, xpos, ypos, width, height, acc_ps, color_ps); + break; + default: + assert(0); + } +} + + + +void st_init_accum_functions(struct dd_function_table *functions) +{ + functions->Accum = st_Accum; +} diff --git a/src/mesa/state_tracker/st_atom_constbuf.c b/src/mesa/state_tracker/st_atom_constbuf.c index 2856e0f0e0f..d02e51cb9a5 100644 --- a/src/mesa/state_tracker/st_atom_constbuf.c +++ b/src/mesa/state_tracker/st_atom_constbuf.c @@ -73,8 +73,8 @@ void st_upload_constants( struct st_context *st, /* We always need to get a new buffer, to keep the drivers simple and * avoid gratuitous rendering synchronization. */ - pipe_reference_buffer(pipe, &cbuf->buffer, NULL ); - cbuf->buffer = pipe_buffer_create(pipe, 1, PIPE_BUFFER_USAGE_CONSTANT, + pipe_buffer_reference(pipe->screen, &cbuf->buffer, NULL ); + cbuf->buffer = pipe_buffer_create(pipe->screen, 16, PIPE_BUFFER_USAGE_CONSTANT, paramBytes ); if (0) @@ -86,10 +86,10 @@ void st_upload_constants( struct st_context *st, /* load Mesa constants into the constant buffer */ if (cbuf->buffer) { - void *map = pipe_buffer_map(pipe, cbuf->buffer, + void *map = pipe_buffer_map(pipe->screen, cbuf->buffer, PIPE_BUFFER_USAGE_CPU_WRITE); memcpy(map, params->ParameterValues, paramBytes); - pipe_buffer_unmap(pipe, cbuf->buffer); + pipe_buffer_unmap(pipe->screen, cbuf->buffer); } cbuf->size = paramBytes; diff --git a/src/mesa/state_tracker/st_atom_sampler.c b/src/mesa/state_tracker/st_atom_sampler.c index 3ba6a971f6f..cef61fb55c5 100644 --- a/src/mesa/state_tracker/st_atom_sampler.c +++ b/src/mesa/state_tracker/st_atom_sampler.c @@ -35,6 +35,7 @@ #include "main/macros.h" #include "st_context.h" +#include "st_cb_texture.h" #include "st_atom.h" #include "st_program.h" #include "pipe/p_context.h" @@ -125,6 +126,8 @@ update_samplers(struct st_context *st) st->state.num_samplers = 0; + /*printf("%s samplers used = 0x%x\n", __FUNCTION__, fs->Base.Base.SamplersUsed);*/ + /* loop over sampler units (aka tex image units) */ for (su = 0; su < st->ctx->Const.MaxTextureImageUnits; su++) { struct pipe_sampler_state *sampler = st->state.samplers + su; @@ -136,8 +139,9 @@ update_samplers(struct st_context *st) const struct gl_texture_object *texobj = st->ctx->Texture.Unit[texUnit]._Current; - if (!texobj) - continue; + if (!texobj) { + texobj = st_get_default_texture(st); + } sampler->wrap_s = gl_wrap_to_sp(texobj->WrapS); sampler->wrap_t = gl_wrap_to_sp(texobj->WrapT); @@ -184,11 +188,11 @@ update_samplers(struct st_context *st) st->state.num_samplers = su + 1; - /* XXX more sampler state here */ - + /*printf("%s su=%u non-null\n", __FUNCTION__, su);*/ cso_single_sampler(st->cso_context, su, sampler); } else { + /*printf("%s su=%u null\n", __FUNCTION__, su);*/ cso_single_sampler(st->cso_context, su, NULL); } } diff --git a/src/mesa/state_tracker/st_atom_shader.c b/src/mesa/state_tracker/st_atom_shader.c index 4fa304ede0f..cbd414e2d3b 100644 --- a/src/mesa/state_tracker/st_atom_shader.c +++ b/src/mesa/state_tracker/st_atom_shader.c @@ -39,6 +39,7 @@ #include "main/imports.h" #include "main/mtypes.h" +#include "main/macros.h" #include "shader/program.h" #include "pipe/p_context.h" @@ -71,6 +72,8 @@ struct translated_vertex_program /** Maps VERT_RESULT_x to slot */ GLuint output_to_slot[VERT_RESULT_MAX]; + ubyte output_to_semantic_name[VERT_RESULT_MAX]; + ubyte output_to_semantic_index[VERT_RESULT_MAX]; /** Pointer to the translated vertex program */ struct st_vertex_program *vp; @@ -176,17 +179,22 @@ find_translated_vp(struct st_context *st, const GLbitfield outputsWritten = stvp->Base.Base.OutputsWritten; GLuint numVpOuts = 0; GLboolean emitPntSize = GL_FALSE, emitBFC0 = GL_FALSE, emitBFC1 = GL_FALSE; + GLint maxGeneric; /* Compute mapping of vertex program outputs to slots, which depends * on the fragment program's input->slot mapping. */ for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { - /* set default: */ + /* set defaults: */ xvp->output_to_slot[outAttr] = UNUSED; + xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_COUNT; + xvp->output_to_semantic_index[outAttr] = 99; if (outAttr == VERT_RESULT_HPOS) { /* always put xformed position into slot zero */ xvp->output_to_slot[VERT_RESULT_HPOS] = 0; + xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_POSITION; + xvp->output_to_semantic_index[outAttr] = 0; numVpOuts++; } else if (outputsWritten & (1 << outAttr)) { @@ -195,8 +203,11 @@ find_translated_vp(struct st_context *st, if (fpInAttrib >= 0) { GLuint fpInSlot = stfp->input_to_slot[fpInAttrib]; if (fpInSlot != ~0) { + /* match this vp output to the fp input */ GLuint vpOutSlot = stfp->input_map[fpInSlot]; xvp->output_to_slot[outAttr] = vpOutSlot; + xvp->output_to_semantic_name[outAttr] = stfp->input_semantic_name[fpInSlot]; + xvp->output_to_semantic_index[outAttr] = stfp->input_semantic_index[fpInSlot]; numVpOuts++; } } @@ -208,19 +219,27 @@ find_translated_vp(struct st_context *st, emitBFC1 = GL_TRUE; } #if 0 /*debug*/ - printf("assign output_to_slot[%d] = %d\n", outAttr, + printf("assign vp output_to_slot[%d] = %d\n", outAttr, xvp->output_to_slot[outAttr]); #endif } /* must do these last */ - if (emitPntSize) + if (emitPntSize) { xvp->output_to_slot[VERT_RESULT_PSIZ] = numVpOuts++; - if (emitBFC0) + xvp->output_to_semantic_name[VERT_RESULT_PSIZ] = TGSI_SEMANTIC_PSIZE; + xvp->output_to_semantic_index[VERT_RESULT_PSIZ] = 0; + } + if (emitBFC0) { xvp->output_to_slot[VERT_RESULT_BFC0] = numVpOuts++; - if (emitBFC1) + xvp->output_to_semantic_name[VERT_RESULT_BFC0] = TGSI_SEMANTIC_COLOR; + xvp->output_to_semantic_index[VERT_RESULT_BFC0] = 0; + } + if (emitBFC1) { xvp->output_to_slot[VERT_RESULT_BFC1] = numVpOuts++; - + xvp->output_to_semantic_name[VERT_RESULT_BFC0] = TGSI_SEMANTIC_COLOR; + xvp->output_to_semantic_index[VERT_RESULT_BFC0] = 1; + } /* Unneeded vertex program outputs will go to this slot. * We could use this info to do dead code elimination in the @@ -228,22 +247,38 @@ find_translated_vp(struct st_context *st, */ dummySlot = numVpOuts; - /* Map vert program outputs that aren't used to the dummy slot */ + /* find max GENERIC slot index */ + maxGeneric = -1; + for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { + if (xvp->output_to_semantic_name[outAttr] == TGSI_SEMANTIC_GENERIC) { + maxGeneric = MAX2(maxGeneric, + xvp->output_to_semantic_index[outAttr]); + } + } + + /* Map vert program outputs that aren't used to the dummy slot + * (and an unused generic attribute slot). + */ for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { if (outputsWritten & (1 << outAttr)) { - if (xvp->output_to_slot[outAttr] == UNUSED) + if (xvp->output_to_slot[outAttr] == UNUSED) { xvp->output_to_slot[outAttr] = dummySlot; + xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_GENERIC; + xvp->output_to_semantic_index[outAttr] = maxGeneric + 1; + } } + #if 0 /*debug*/ - printf("output_to_slot[%d] = %d\n", outAttr, + printf("vp output_to_slot[%d] = %d\n", outAttr, xvp->output_to_slot[outAttr]); #endif - } assert(stvp->Base.Base.NumInstructions > 1); - st_translate_vertex_program(st, stvp, xvp->output_to_slot); + st_translate_vertex_program(st, stvp, xvp->output_to_slot, + xvp->output_to_semantic_name, + xvp->output_to_semantic_index); xvp->vp = stvp; diff --git a/src/mesa/state_tracker/st_atom_texture.c b/src/mesa/state_tracker/st_atom_texture.c index 1ec671ed48f..fb03766ff59 100644 --- a/src/mesa/state_tracker/st_atom_texture.c +++ b/src/mesa/state_tracker/st_atom_texture.c @@ -49,6 +49,8 @@ update_textures(struct st_context *st) st->state.num_textures = 0; + /*printf("%s samplers used = 0x%x\n", __FUNCTION__, fprog->Base.SamplersUsed);*/ + for (su = 0; su < st->ctx->Const.MaxTextureCoordUnits; su++) { struct pipe_texture *pt = NULL; @@ -56,24 +58,34 @@ update_textures(struct st_context *st) const GLuint texUnit = fprog->Base.SamplerUnits[su]; struct gl_texture_object *texObj = st->ctx->Texture.Unit[texUnit]._Current; - struct st_texture_object *stObj = st_texture_object(texObj); - - if (texObj) { - GLboolean flush, retval; + struct st_texture_object *stObj; + GLboolean flush, retval; - retval = st_finalize_texture(st->ctx, st->pipe, texObj, &flush); - if (!retval) { - /* out of mem */ - /* missing texture */ - continue; - } + if (!texObj) { + texObj = st_get_default_texture(st); + } + stObj = st_texture_object(texObj); - st->state.num_textures = su + 1; + retval = st_finalize_texture(st->ctx, st->pipe, texObj, &flush); + if (!retval) { + /* out of mem */ + continue; } + st->state.num_textures = su + 1; + pt = st_get_stobj_texture(stObj); } + /* + if (pt) { + printf("%s su=%u non-null\n", __FUNCTION__, su); + } + else { + printf("%s su=%u null\n", __FUNCTION__, su); + } + */ + pipe_texture_reference(&st->state.sampler_texture[su], pt); } diff --git a/src/mesa/state_tracker/st_cb_accum.c b/src/mesa/state_tracker/st_cb_accum.c index a992e08ff68..cf3a99e7e9d 100644 --- a/src/mesa/state_tracker/st_cb_accum.c +++ b/src/mesa/state_tracker/st_cb_accum.c @@ -42,7 +42,7 @@ #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "pipe/p_inlines.h" -#include "util/p_tile.h" +#include "util/u_tile.h" #define UNCLAMPED_FLOAT_TO_SHORT(us, f) \ diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c index d5696a909f7..694104f9cfb 100644 --- a/src/mesa/state_tracker/st_cb_bitmap.c +++ b/src/mesa/state_tracker/st_cb_bitmap.c @@ -50,7 +50,7 @@ #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "pipe/p_inlines.h" -#include "util/p_tile.h" +#include "util/u_tile.h" #include "util/u_draw_quad.h" #include "util/u_simple_shaders.h" #include "shader/prog_instruction.h" @@ -378,7 +378,7 @@ setup_bitmap_vertex_data(struct st_context *st, void *buf; if (!st->bitmap.vbuf) { - st->bitmap.vbuf = pipe_buffer_create(pipe, 32, PIPE_BUFFER_USAGE_VERTEX, + st->bitmap.vbuf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX, sizeof(st->bitmap.vertices)); } @@ -418,9 +418,9 @@ setup_bitmap_vertex_data(struct st_context *st, } /* put vertex data into vbuf */ - buf = pipe_buffer_map(pipe, st->bitmap.vbuf, PIPE_BUFFER_USAGE_CPU_WRITE); + buf = pipe_buffer_map(pipe->screen, st->bitmap.vbuf, PIPE_BUFFER_USAGE_CPU_WRITE); memcpy(buf, st->bitmap.vertices, sizeof(st->bitmap.vertices)); - pipe_buffer_unmap(pipe, st->bitmap.vbuf); + pipe_buffer_unmap(pipe->screen, st->bitmap.vbuf); } @@ -779,7 +779,7 @@ st_destroy_bitmap(struct st_context *st) } if (st->bitmap.vbuf) { - pipe_buffer_destroy(pipe, st->bitmap.vbuf); + pipe_buffer_destroy(pipe->screen, st->bitmap.vbuf); st->bitmap.vbuf = NULL; } diff --git a/src/mesa/state_tracker/st_cb_bufferobjects.c b/src/mesa/state_tracker/st_cb_bufferobjects.c index af79aefa968..07fa2afce05 100644 --- a/src/mesa/state_tracker/st_cb_bufferobjects.c +++ b/src/mesa/state_tracker/st_cb_bufferobjects.c @@ -78,7 +78,7 @@ st_bufferobj_free(GLcontext *ctx, struct gl_buffer_object *obj) struct st_buffer_object *st_obj = st_buffer_object(obj); if (st_obj->buffer) - pipe_reference_buffer(pipe, &st_obj->buffer, NULL); + pipe_buffer_reference(pipe->screen, &st_obj->buffer, NULL); free(st_obj); } @@ -105,9 +105,9 @@ st_bufferobj_subdata(GLcontext *ctx, if (offset >= st_obj->size || size > (st_obj->size - offset)) return; - map = pipe_buffer_map(pipe, st_obj->buffer, PIPE_BUFFER_USAGE_CPU_WRITE); + map = pipe_buffer_map(pipe->screen, st_obj->buffer, PIPE_BUFFER_USAGE_CPU_WRITE); memcpy(map + offset, data, size); - pipe_buffer_unmap(pipe, st_obj->buffer); + pipe_buffer_unmap(pipe->screen, st_obj->buffer); } @@ -128,9 +128,9 @@ st_bufferobj_get_subdata(GLcontext *ctx, if (offset >= st_obj->size || size > (st_obj->size - offset)) return; - map = pipe_buffer_map(pipe, st_obj->buffer, PIPE_BUFFER_USAGE_CPU_READ); + map = pipe_buffer_map(pipe->screen, st_obj->buffer, PIPE_BUFFER_USAGE_CPU_READ); memcpy(data, map + offset, size); - pipe_buffer_unmap(pipe, st_obj->buffer); + pipe_buffer_unmap(pipe->screen, st_obj->buffer); } @@ -171,9 +171,9 @@ st_bufferobj_data(GLcontext *ctx, buffer_usage = 0; } - pipe_reference_buffer( pipe, &st_obj->buffer, NULL ); + pipe_buffer_reference( pipe->screen, &st_obj->buffer, NULL ); - st_obj->buffer = pipe_buffer_create( pipe, 32, buffer_usage, size ); + st_obj->buffer = pipe_buffer_create( pipe->screen, 32, buffer_usage, size ); st_obj->size = size; @@ -207,7 +207,7 @@ st_bufferobj_map(GLcontext *ctx, GLenum target, GLenum access, break; } - obj->Pointer = pipe_buffer_map(pipe, st_obj->buffer, flags); + obj->Pointer = pipe_buffer_map(pipe->screen, st_obj->buffer, flags); return obj->Pointer; } @@ -221,7 +221,7 @@ st_bufferobj_unmap(GLcontext *ctx, GLenum target, struct gl_buffer_object *obj) struct pipe_context *pipe = st_context(ctx)->pipe; struct st_buffer_object *st_obj = st_buffer_object(obj); - pipe_buffer_unmap(pipe, st_obj->buffer); + pipe_buffer_unmap(pipe->screen, st_obj->buffer); obj->Pointer = NULL; return GL_TRUE; } diff --git a/src/mesa/state_tracker/st_cb_clear.c b/src/mesa/state_tracker/st_cb_clear.c index e475f022d34..47ad3c2bc12 100644 --- a/src/mesa/state_tracker/st_cb_clear.c +++ b/src/mesa/state_tracker/st_cb_clear.c @@ -116,7 +116,7 @@ st_destroy_clear(struct st_context *st) st->clear.vs = NULL; } if (st->clear.vbuf) { - pipe_buffer_destroy(pipe, st->clear.vbuf); + pipe_buffer_destroy(pipe->screen, st->clear.vbuf); st->clear.vbuf = NULL; } } @@ -152,7 +152,7 @@ draw_quad(GLcontext *ctx, void *buf; if (!st->clear.vbuf) { - st->clear.vbuf = pipe_buffer_create(pipe, 32, PIPE_BUFFER_USAGE_VERTEX, + st->clear.vbuf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX, sizeof(st->clear.vertices)); } @@ -180,9 +180,9 @@ draw_quad(GLcontext *ctx, } /* put vertex data into vbuf */ - buf = pipe_buffer_map(pipe, st->clear.vbuf, PIPE_BUFFER_USAGE_CPU_WRITE); + buf = pipe_buffer_map(pipe->screen, st->clear.vbuf, PIPE_BUFFER_USAGE_CPU_WRITE); memcpy(buf, st->clear.vertices, sizeof(st->clear.vertices)); - pipe_buffer_unmap(pipe, st->clear.vbuf); + pipe_buffer_unmap(pipe->screen, st->clear.vbuf); /* draw */ util_draw_vertex_buffer(pipe, st->clear.vbuf, @@ -414,6 +414,9 @@ clear_color_buffer(GLcontext *ctx, struct gl_renderbuffer *rb) /* clear whole buffer w/out masking */ struct st_renderbuffer *strb = st_renderbuffer(rb); uint clearValue; + /* NOTE: we always pass the clear color as PIPE_FORMAT_A8R8G8B8_UNORM + * at this time! + */ util_pack_color(ctx->Color.ClearColor, PIPE_FORMAT_A8R8G8B8_UNORM, &clearValue); ctx->st->pipe->clear(ctx->st->pipe, strb->surface, clearValue); } diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c index db0c9fbd09c..00bbcae32ae 100644 --- a/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/src/mesa/state_tracker/st_cb_drawpixels.c @@ -55,7 +55,7 @@ #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "pipe/p_inlines.h" -#include "util/p_tile.h" +#include "util/u_tile.h" #include "util/u_draw_quad.h" #include "shader/prog_instruction.h" #include "cso_cache/cso_context.h" @@ -294,7 +294,7 @@ st_make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor) } stvp = (struct st_vertex_program *) p; - st_translate_vertex_program(st, stvp, NULL); + st_translate_vertex_program(st, stvp, NULL, NULL, NULL); st->drawpix.vert_shaders[passColor] = stvp; @@ -487,17 +487,17 @@ draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z, ubyte *map; /* allocate/load buffer object with vertex data */ - buf = pipe_buffer_create(pipe, 32, PIPE_BUFFER_USAGE_VERTEX, + buf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX, sizeof(verts)); - map = pipe_buffer_map(pipe, buf, PIPE_BUFFER_USAGE_CPU_WRITE); + map = pipe_buffer_map(pipe->screen, buf, PIPE_BUFFER_USAGE_CPU_WRITE); memcpy(map, verts, sizeof(verts)); - pipe_buffer_unmap(pipe, buf); + pipe_buffer_unmap(pipe->screen, buf); util_draw_vertex_buffer(pipe, buf, PIPE_PRIM_QUADS, 4, /* verts */ 3); /* attribs/vert */ - pipe_buffer_reference(pipe->winsys, &buf, NULL); + pipe_buffer_reference(pipe->screen, &buf, NULL); } } diff --git a/src/mesa/state_tracker/st_cb_fbo.h b/src/mesa/state_tracker/st_cb_fbo.h index ff56001a4e1..44fa9fe9a4f 100644 --- a/src/mesa/state_tracker/st_cb_fbo.h +++ b/src/mesa/state_tracker/st_cb_fbo.h @@ -47,6 +47,10 @@ struct st_renderbuffer struct st_texture_object *rtt; /**< GL render to texture's texture */ int rtt_level, rtt_face, rtt_slice; + + /** Render to texture state */ + struct pipe_texture *texture_save; + struct pipe_surface *surface_save; }; diff --git a/src/mesa/state_tracker/st_cb_flush.c b/src/mesa/state_tracker/st_cb_flush.c index 5e866b0d413..d8f9537d2de 100644 --- a/src/mesa/state_tracker/st_cb_flush.c +++ b/src/mesa/state_tracker/st_cb_flush.c @@ -91,7 +91,7 @@ void st_finish( struct st_context *st ) { struct pipe_fence_handle *fence = NULL; - st_flush(st, PIPE_FLUSH_RENDER_CACHE, &fence); + st_flush(st, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence); st->pipe->winsys->fence_finish(st->pipe->winsys, fence, 0); st->pipe->winsys->fence_reference(st->pipe->winsys, &fence, NULL); diff --git a/src/mesa/state_tracker/st_cb_get.c b/src/mesa/state_tracker/st_cb_get.c new file mode 100644 index 00000000000..e7d7f03bc9b --- /dev/null +++ b/src/mesa/state_tracker/st_cb_get.c @@ -0,0 +1,97 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + + +/** + * glGet functions + * + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/context.h" + +#include "pipe/p_defines.h" + +#include "st_cb_fbo.h" +#include "st_cb_get.h" + + + +/** + * Examine the current color read buffer format to determine + * which GL pixel format/type combo is the best match. + */ +static void +get_preferred_read_format_type(GLcontext *ctx, GLint *format, GLint *type) +{ + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct st_renderbuffer *strb = st_renderbuffer(fb->_ColorReadBuffer); + + /* defaults */ + *format = ctx->Const.ColorReadFormat; + *type = ctx->Const.ColorReadType; + + if (strb) { + /* XXX could add more cases here... */ + if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM) { + *format = GL_BGRA; + if (_mesa_little_endian()) + *type = GL_UNSIGNED_INT_8_8_8_8_REV; + else + *type = GL_UNSIGNED_INT_8_8_8_8; + } + } +} + + +/** + * We only intercept the OES preferred ReadPixels format/type. + * Everything else goes to the default _mesa_GetIntegerv. + */ +static GLboolean +st_GetIntegerv(GLcontext *ctx, GLenum pname, GLint *params) +{ + GLint dummy; + + switch (pname) { + case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES: + get_preferred_read_format_type(ctx, &dummy, params); + return GL_TRUE; + case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES: + get_preferred_read_format_type(ctx, params, &dummy); + return GL_TRUE; + default: + return GL_FALSE; + } +} + + +void st_init_get_functions(struct dd_function_table *functions) +{ + functions->GetIntegerv = st_GetIntegerv; +} diff --git a/src/mesa/state_tracker/st_cb_get.h b/src/mesa/state_tracker/st_cb_get.h new file mode 100644 index 00000000000..8e9f3e93060 --- /dev/null +++ b/src/mesa/state_tracker/st_cb_get.h @@ -0,0 +1,37 @@ +/************************************************************************** + * + * 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_CB_GET_H +#define ST_CB_GET_H + + +extern void +st_init_get_functions(struct dd_function_table *functions); + + +#endif diff --git a/src/mesa/state_tracker/st_cb_readpixels.c b/src/mesa/state_tracker/st_cb_readpixels.c index eb71779cc9f..c8015327885 100644 --- a/src/mesa/state_tracker/st_cb_readpixels.c +++ b/src/mesa/state_tracker/st_cb_readpixels.c @@ -41,7 +41,7 @@ #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "pipe/p_inlines.h" -#include "util/p_tile.h" +#include "util/u_tile.h" #include "st_context.h" #include "st_cb_bitmap.h" #include "st_cb_readpixels.h" @@ -163,6 +163,124 @@ st_get_color_read_renderbuffer(GLcontext *ctx) /** + * Try to do glReadPixels in a fast manner for common cases. + * \return GL_TRUE for success, GL_FALSE for failure + */ +static GLboolean +st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + enum combination { + A8R8G8B8_UNORM_TO_RGBA_UBYTE, + A8R8G8B8_UNORM_TO_RGB_UBYTE, + A8R8G8B8_UNORM_TO_BGRA_UINT + } combo; + + if (ctx->_ImageTransferState) + return GL_FALSE; + + if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM && + format == GL_RGBA && type == GL_UNSIGNED_BYTE) { + combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE; + } + else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM && + format == GL_RGB && type == GL_UNSIGNED_BYTE) { + combo = A8R8G8B8_UNORM_TO_RGB_UBYTE; + } + else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM && + format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) { + combo = A8R8G8B8_UNORM_TO_BGRA_UINT; + } + else { + return GL_FALSE; + } + + /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/ + + { + struct pipe_context *pipe = ctx->st->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_surface *surf; + const GLubyte *map; + GLubyte *dst; + GLint row, col, dy, dstStride; + + surf = screen->get_tex_surface(screen, strb->texture, 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + if (!surf) { + return GL_FALSE; + } + + map = screen->surface_map(screen, surf, PIPE_BUFFER_USAGE_CPU_READ); + if (!map) { + pipe_surface_reference(&surf, NULL); + return GL_FALSE; + } + + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + y = surf->height - y - 1; + dy = -1; + } + else { + dy = 1; + } + + dst = _mesa_image_address2d(pack, dest, width, height, + format, type, 0, 0); + dstStride = _mesa_image_row_stride(pack, width, format, type); + + switch (combo) { + case A8R8G8B8_UNORM_TO_RGBA_UBYTE: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * surf->stride + x * 4; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*4+0] = (pixel >> 16) & 0xff; + dst[col*4+1] = (pixel >> 8) & 0xff; + dst[col*4+2] = (pixel >> 0) & 0xff; + dst[col*4+3] = (pixel >> 24) & 0xff; + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_RGB_UBYTE: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * surf->stride + x * 4; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*3+0] = (pixel >> 16) & 0xff; + dst[col*3+1] = (pixel >> 8) & 0xff; + dst[col*3+2] = (pixel >> 0) & 0xff; + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_BGRA_UINT: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * surf->stride + x * 4; + memcpy(dst, src, 4 * width); + dst += dstStride; + y += dy; + } + break; + default: + ; /* nothing */ + } + + screen->surface_unmap(screen, surf); + pipe_surface_reference(&surf, NULL); + } + + return GL_TRUE; +} + + +/** * Do glReadPixels by getting rows from the framebuffer surface with * get_tile(). Convert to requested format/type with Mesa image routines. * Image transfer ops are done in software too. @@ -219,6 +337,14 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, if (!strb) return; + /* try a fast-path readpixels before anything else */ + if (st_fast_readpixels(ctx, strb, x, y, width, height, + format, type, pack, dest)) { + /* success! */ + _mesa_unmap_readpix_pbo(ctx, &clippedPacking); + return; + } + if (format == GL_RGBA && type == GL_FLOAT) { /* write tile(row) directly into user's buffer */ df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width, diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index 147ca5b1a2f..a3e8fc992d9 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -51,20 +51,13 @@ #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "pipe/p_inlines.h" -#include "util/p_tile.h" +#include "util/u_tile.h" #include "util/u_blit.h" #define DBG if (0) printf -static INLINE struct st_texture_image * -st_texture_image(struct gl_texture_image *img) -{ - return (struct st_texture_image *) img; -} - - static enum pipe_texture_target gl_target_to_pipe(GLenum target) { @@ -933,7 +926,12 @@ fallback_copy_texsubimage(GLcontext *ctx, struct pipe_texture *pt = stImage->pt; struct pipe_surface *src_surf, *dest_surf; - src_surf = strb->surface; + /* We'd use strb->surface, here but it's created for GPU read/write only */ + src_surf = pipe->screen->get_tex_surface( pipe->screen, + strb->texture, + 0, 0, 0, + PIPE_BUFFER_USAGE_CPU_READ); + dest_surf = screen->get_tex_surface(screen, pt, face, level, destZ, PIPE_BUFFER_USAGE_CPU_WRITE); @@ -1016,6 +1014,7 @@ fallback_copy_texsubimage(GLcontext *ctx, } screen->tex_surface_release(screen, &dest_surf); + screen->tex_surface_release(screen, &src_surf); } @@ -1092,6 +1091,10 @@ st_copy_texsubimage(GLcontext *ctx, stImage->face, stImage->level, destZ, PIPE_BUFFER_USAGE_GPU_WRITE); + if (do_flip) + srcY = strb->surface->height - srcY - height; + + /* for surface_copy(), y=0=top, always */ pipe->surface_copy(pipe, do_flip, /* dest */ @@ -1455,6 +1458,49 @@ st_finalize_texture(GLcontext *ctx, } +/** + * Returns pointer to a default/dummy texture. + * This is typically used when the current shader has tex/sample instructions + * but the user has not provided a (any) texture(s). + */ +struct gl_texture_object * +st_get_default_texture(struct st_context *st) +{ + if (!st->default_texture) { + static const GLenum target = GL_TEXTURE_2D; + GLubyte pixels[16][16][4]; + struct gl_texture_object *texObj; + struct gl_texture_image *texImg; + + /* init image to gray */ + memset(pixels, 127, sizeof(pixels)); + + texObj = st->ctx->Driver.NewTextureObject(st->ctx, 0, target); + + texImg = _mesa_get_tex_image(st->ctx, texObj, target, 0); + + _mesa_init_teximage_fields(st->ctx, target, texImg, + 16, 16, 1, 0, /* w, h, d, border */ + GL_RGBA); + + st_TexImage(st->ctx, 2, target, + 0, GL_RGBA, /* level, intformat */ + 16, 16, 1, 0, /* w, h, d, border */ + GL_RGBA, GL_UNSIGNED_BYTE, pixels, + &st->ctx->DefaultPacking, + texObj, texImg, + 0, 0); + + texObj->MinFilter = GL_NEAREST; + texObj->MagFilter = GL_NEAREST; + texObj->_Complete = GL_TRUE; + + st->default_texture = texObj; + } + return st->default_texture; +} + + void st_init_texture_functions(struct dd_function_table *functions) { diff --git a/src/mesa/state_tracker/st_cb_texture.h b/src/mesa/state_tracker/st_cb_texture.h index 843745fcd67..f1fe0339cdd 100644 --- a/src/mesa/state_tracker/st_cb_texture.h +++ b/src/mesa/state_tracker/st_cb_texture.h @@ -37,6 +37,10 @@ st_finalize_texture(GLcontext *ctx, GLboolean *needFlush); +extern struct gl_texture_object * +st_get_default_texture(struct st_context *st); + + extern void st_init_texture_functions(struct dd_function_table *functions); diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c index 6e4a376d44a..08d4db7f7f4 100644 --- a/src/mesa/state_tracker/st_context.c +++ b/src/mesa/state_tracker/st_context.c @@ -49,6 +49,7 @@ #include "st_cb_drawtex.h" #endif #include "st_cb_fbo.h" +#include "st_cb_get.h" #if FEATURE_feedback #include "st_cb_feedback.h" #endif @@ -195,10 +196,15 @@ static void st_destroy_context_priv( struct st_context *st ) for (i = 0; i < Elements(st->state.constants); i++) { if (st->state.constants[i].buffer) { - pipe_reference_buffer(st->pipe, &st->state.constants[i].buffer, NULL); + pipe_buffer_reference(st->pipe->screen, &st->state.constants[i].buffer, NULL); } } + if (st->default_texture) { + st->ctx->Driver.DeleteTexture(st->ctx, st->default_texture); + st->default_texture = NULL; + } + free( st ); } @@ -223,10 +229,7 @@ void st_destroy_context( struct st_context *st ) cso_destroy_context(cso); - /* Temporary workaround for mismatched pipe create and pipe destroy */ -#if !defined(PIPE_SUBSYSTEM_WINDOWS_USER) && !defined(PIPE_SUBSYSTEM_WINDOWS_CE) pipe->destroy( pipe ); -#endif free(ctx); } @@ -291,6 +294,7 @@ void st_init_driver_functions(struct dd_function_table *functions) st_init_rasterpos_functions(functions); #endif st_init_fbo_functions(functions); + st_init_get_functions(functions); #if FEATURE_feedback st_init_feedback_functions(functions); #endif diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h index 96333902a91..4314d9af5c8 100644 --- a/src/mesa/state_tracker/st_context.h +++ b/src/mesa/state_tracker/st_context.h @@ -132,6 +132,8 @@ struct st_context struct st_vertex_program *vp; /**< Currently bound vertex program */ struct st_fragment_program *fp; /**< Currently bound fragment program */ + struct gl_texture_object *default_texture; + struct { struct gl_program_cache *cache; struct st_fragment_program *program; /**< cur pixel transfer prog */ diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c index cc3d7450a9f..bdf8648ef7c 100644 --- a/src/mesa/state_tracker/st_draw.c +++ b/src/mesa/state_tracker/st_draw.c @@ -32,6 +32,7 @@ #include "main/imports.h" #include "main/image.h" +#include "main/macros.h" #include "vbo/vbo.h" @@ -228,7 +229,7 @@ setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count, if (!vec) return NULL; - map = pipe_buffer_map(pipe, stobj->buffer, PIPE_BUFFER_USAGE_CPU_READ); + map = pipe_buffer_map(pipe->screen, stobj->buffer, PIPE_BUFFER_USAGE_CPU_READ); map = ADD_POINTERS(map, array->Ptr); for (i = 0; i < count; i++) { @@ -238,7 +239,7 @@ setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count, map += array->StrideB; } - pipe_buffer_unmap(pipe, stobj->buffer); + pipe_buffer_unmap(pipe->screen, stobj->buffer); pipe->set_edgeflags(pipe, vec); @@ -252,43 +253,174 @@ setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count, } +/** + * Examine the active arrays to determine if we have interleaved + * vertex arrays all living in one VBO, or all living in user space. + * \param userSpace returns whether the arrays are in user space. + */ +static GLboolean +is_interleaved_arrays(const struct st_vertex_program *vp, + const struct gl_client_array **arrays, + GLboolean *userSpace) +{ + GLuint attr; + const struct gl_buffer_object *firstBufObj = NULL; + GLint firstStride = -1; + GLuint num_client_arrays = 0; + const GLubyte *client_addr = NULL; + + for (attr = 0; attr < vp->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + const struct gl_buffer_object *bufObj = arrays[mesaAttr]->BufferObj; + const GLsizei stride = arrays[mesaAttr]->StrideB; /* in bytes */ + + if (firstStride < 0) { + firstStride = stride; + } + else if (firstStride != stride) { + return GL_FALSE; + } + + if (!bufObj || !bufObj->Name) { + num_client_arrays++; + /* Try to detect if the client-space arrays are + * "close" to each other. + */ + if (!client_addr) { + client_addr = arrays[mesaAttr]->Ptr; + } + else if (abs(arrays[mesaAttr]->Ptr - client_addr) > firstStride) { + /* arrays start too far apart */ + return GL_FALSE; + } + } + else if (!firstBufObj) { + firstBufObj = bufObj; + } + else if (bufObj != firstBufObj) { + return GL_FALSE; + } + } + + *userSpace = (num_client_arrays == vp->num_inputs); + /*printf("user space: %d\n", (int) *userSpace);*/ + + return GL_TRUE; +} + /** - * This function gets plugged into the VBO module and is called when - * we have something to render. - * Basically, translate the information into the format expected by pipe. + * Once we know all the arrays are in user space, this function + * computes the memory range occupied by the arrays. */ -void -st_draw_vbo(GLcontext *ctx, - const struct gl_client_array **arrays, - const struct _mesa_prim *prims, - GLuint nr_prims, - const struct _mesa_index_buffer *ib, - GLuint min_index, - GLuint max_index) +static void +get_user_arrays_bounds(const struct st_vertex_program *vp, + const struct gl_client_array **arrays, + GLuint max_index, + const GLubyte **low, const GLubyte **high) +{ + const GLubyte *low_addr = NULL; + GLuint attr; + GLint stride; + + for (attr = 0; attr < vp->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + const GLubyte *start = arrays[mesaAttr]->Ptr; + stride = arrays[mesaAttr]->StrideB; + if (attr == 0) { + low_addr = start; + } + else { + low_addr = MIN2(low_addr, start); + } + } + + *low = low_addr; + *high = low_addr + (max_index + 1) * stride; +} + + +/** + * Set up for drawing interleaved arrays that all live in one VBO + * or all live in user space. + * \param vbuffer returns vertex buffer info + * \param velements returns vertex element info + */ +static void +setup_interleaved_attribs(GLcontext *ctx, + const struct st_vertex_program *vp, + const struct gl_client_array **arrays, + GLuint max_index, + GLboolean userSpace, + struct pipe_vertex_buffer *vbuffer, + struct pipe_vertex_element velements[]) { struct pipe_context *pipe = ctx->st->pipe; - const struct st_vertex_program *vp; - const struct pipe_shader_state *vs; - struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS]; GLuint attr; - struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; + const GLubyte *offset0; - /* sanity check for pointer arithmetic below */ - assert(sizeof(arrays[0]->Ptr[0]) == 1); + for (attr = 0; attr < vp->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; + struct st_buffer_object *stobj = st_buffer_object(bufobj); + GLsizei stride = arrays[mesaAttr]->StrideB; + + /*printf("stobj %u = %p\n", attr, (void*)stobj);*/ + + if (attr == 0) { + if (userSpace) { + const GLubyte *low, *high; + get_user_arrays_bounds(vp, arrays, max_index, &low, &high); + /*printf("user buffer range: %p %p %d\n", low, high, high-low);*/ + vbuffer->buffer = + pipe_user_buffer_create(pipe->screen, (void *) low, high - low); + vbuffer->buffer_offset = 0; + offset0 = low; + } + else { + vbuffer->buffer = NULL; + pipe_buffer_reference(pipe->screen, &vbuffer->buffer, stobj->buffer); + vbuffer->buffer_offset = (unsigned) arrays[mesaAttr]->Ptr; + offset0 = arrays[mesaAttr]->Ptr; + } + vbuffer->pitch = stride; /* in bytes */ + vbuffer->max_index = max_index; + } - st_validate_state(ctx->st); + velements[attr].src_offset = + (unsigned) (arrays[mesaAttr]->Ptr - offset0); + velements[attr].vertex_buffer_index = 0; + velements[attr].nr_components = arrays[mesaAttr]->Size; + velements[attr].src_format = + pipe_vertex_format(arrays[mesaAttr]->Type, + arrays[mesaAttr]->Size, + arrays[mesaAttr]->Normalized); + assert(velements[attr].src_format); + } +} - /* must get these after state validation! */ - vp = ctx->st->vp; - vs = &ctx->st->vp->state; - /* loop over TGSI shader inputs to determine vertex buffer - * and attribute info - */ +/** + * Set up a separate pipe_vertex_buffer and pipe_vertex_element for each + * vertex attribute. + * \param vbuffer returns vertex buffer info + * \param velements returns vertex element info + */ +static void +setup_non_interleaved_attribs(GLcontext *ctx, + const struct st_vertex_program *vp, + const struct gl_client_array **arrays, + GLuint max_index, + struct pipe_vertex_buffer vbuffer[], + struct pipe_vertex_element velements[]) +{ + struct pipe_context *pipe = ctx->st->pipe; + GLuint attr; + for (attr = 0; attr < vp->num_inputs; attr++) { const GLuint mesaAttr = vp->index_to_input[attr]; struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; + GLsizei stride = arrays[mesaAttr]->StrideB; if (bufobj && bufobj->Name) { /* Attribute data is in a VBO. @@ -297,27 +429,39 @@ st_draw_vbo(GLcontext *ctx, */ struct st_buffer_object *stobj = st_buffer_object(bufobj); assert(stobj->buffer); + /*printf("stobj %u = %p\n", attr, (void*) stobj);*/ vbuffer[attr].buffer = NULL; - pipe_reference_buffer(pipe, &vbuffer[attr].buffer, stobj->buffer); + pipe_buffer_reference(pipe->screen, &vbuffer[attr].buffer, stobj->buffer); vbuffer[attr].buffer_offset = (unsigned) arrays[mesaAttr]->Ptr; velements[attr].src_offset = 0; } else { /* attribute data is in user-space memory, not a VBO */ uint bytes; + /*printf("user-space array %d stride %d\n", attr, stride);*/ - if (!arrays[mesaAttr]->StrideB) { - bytes = arrays[mesaAttr]->Size - * _mesa_sizeof_type(arrays[mesaAttr]->Type); - } else { - bytes = arrays[mesaAttr]->StrideB * (max_index + 1); + /* wrap user data */ + if (arrays[mesaAttr]->Ptr) { + /* user's vertex array */ + if (arrays[mesaAttr]->StrideB) { + bytes = arrays[mesaAttr]->StrideB * (max_index + 1); + } + else { + bytes = arrays[mesaAttr]->Size + * _mesa_sizeof_type(arrays[mesaAttr]->Type); + } + vbuffer[attr].buffer = pipe_user_buffer_create(pipe->screen, + (void *) arrays[mesaAttr]->Ptr, bytes); + } + else { + /* no array, use ctx->Current.Attrib[] value */ + bytes = sizeof(ctx->Current.Attrib[0]); + vbuffer[attr].buffer = pipe_user_buffer_create(pipe->screen, + (void *) ctx->Current.Attrib[mesaAttr], bytes); + stride = 0; } - /* wrap user data */ - vbuffer[attr].buffer - = pipe_user_buffer_create(pipe, (void *) arrays[mesaAttr]->Ptr, - bytes); vbuffer[attr].buffer_offset = 0; velements[attr].src_offset = 0; } @@ -325,7 +469,7 @@ st_draw_vbo(GLcontext *ctx, assert(velements[attr].src_offset <= 2048); /* 11-bit field */ /* common-case setup */ - vbuffer[attr].pitch = arrays[mesaAttr]->StrideB; /* in bytes */ + vbuffer[attr].pitch = stride; /* in bytes */ vbuffer[attr].max_index = max_index; velements[attr].vertex_buffer_index = attr; velements[attr].nr_components = arrays[mesaAttr]->Size; @@ -335,27 +479,81 @@ st_draw_vbo(GLcontext *ctx, arrays[mesaAttr]->Normalized); assert(velements[attr].src_format); } +} + + + + +/** + * This function gets plugged into the VBO module and is called when + * we have something to render. + * Basically, translate the information into the format expected by gallium. + */ +void +st_draw_vbo(GLcontext *ctx, + const struct gl_client_array **arrays, + const struct _mesa_prim *prims, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLuint min_index, + GLuint max_index) +{ + struct pipe_context *pipe = ctx->st->pipe; + const struct st_vertex_program *vp; + const struct pipe_shader_state *vs; + struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS]; + GLuint attr; + struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; + unsigned num_vbuffers, num_velements; + GLboolean userSpace; + + /* sanity check for pointer arithmetic below */ + assert(sizeof(arrays[0]->Ptr[0]) == 1); + + st_validate_state(ctx->st); + + /* must get these after state validation! */ + vp = ctx->st->vp; + vs = &ctx->st->vp->state; + + /* + * Setup the vbuffer[] and velements[] arrays. + */ + if (is_interleaved_arrays(vp, arrays, &userSpace)) { + /*printf("Draw interleaved\n");*/ + setup_interleaved_attribs(ctx, vp, arrays, max_index, userSpace, + vbuffer, velements); + num_vbuffers = 1; + num_velements = vp->num_inputs; + } + else { + /*printf("Draw non-interleaved\n");*/ + setup_non_interleaved_attribs(ctx, vp, arrays, max_index, + vbuffer, velements); + num_vbuffers = vp->num_inputs; + num_velements = vp->num_inputs; + } #if 0 { GLuint i; - for (i = 0; i < vp->num_inputs; i++) { + for (i = 0; i < num_vbuffers; i++) { printf("buffers[%d].pitch = %u\n", i, vbuffer[i].pitch); printf("buffers[%d].max_index = %u\n", i, vbuffer[i].max_index); printf("buffers[%d].buffer_offset = %u\n", i, vbuffer[i].buffer_offset); printf("buffers[%d].buffer = %p\n", i, (void*) vbuffer[i].buffer); } - for (i = 0; i < vp->num_inputs; i++) { - printf("vlements[%d].src_offset = %u\n", i, velements[i].src_offset); + for (i = 0; i < num_velements; i++) { printf("vlements[%d].vbuffer_index = %u\n", i, velements[i].vertex_buffer_index); + printf("vlements[%d].src_offset = %u\n", i, velements[i].src_offset); printf("vlements[%d].nr_comps = %u\n", i, velements[i].nr_components); printf("vlements[%d].format = %s\n", i, pf_name(velements[i].src_format)); } } #endif - pipe->set_vertex_buffers(pipe, vp->num_inputs, vbuffer); - pipe->set_vertex_elements(pipe, vp->num_inputs, velements); + pipe->set_vertex_buffers(pipe, num_vbuffers, vbuffer); + pipe->set_vertex_elements(pipe, num_velements, velements); /* do actual drawing */ if (ib) { @@ -383,12 +581,12 @@ st_draw_vbo(GLcontext *ctx, if (bufobj && bufobj->Name) { /* elements/indexes are in a real VBO */ struct st_buffer_object *stobj = st_buffer_object(bufobj); - pipe_reference_buffer(pipe, &indexBuf, stobj->buffer); + pipe_buffer_reference(pipe->screen, &indexBuf, stobj->buffer); indexOffset = (unsigned) ib->ptr / indexSize; } else { /* element/indicies are in user space memory */ - indexBuf = pipe_user_buffer_create(pipe, (void *) ib->ptr, + indexBuf = pipe_user_buffer_create(pipe->screen, (void *) ib->ptr, ib->count * indexSize); indexOffset = 0; } @@ -423,7 +621,7 @@ st_draw_vbo(GLcontext *ctx, } } - pipe_reference_buffer(pipe, &indexBuf, NULL); + pipe_buffer_reference(pipe->screen, &indexBuf, NULL); } else { /* non-indexed */ @@ -438,8 +636,8 @@ st_draw_vbo(GLcontext *ctx, } /* unreference buffers (frees wrapped user-space buffer objects) */ - for (attr = 0; attr < vp->num_inputs; attr++) { - pipe_reference_buffer(pipe, &vbuffer[attr].buffer, NULL); + for (attr = 0; attr < num_vbuffers; attr++) { + pipe_buffer_reference(pipe->screen, &vbuffer[attr].buffer, NULL); assert(!vbuffer[attr].buffer); } pipe->set_vertex_buffers(pipe, vp->num_inputs, vbuffer); @@ -552,7 +750,7 @@ st_feedback_draw_vbo(GLcontext *ctx, assert(stobj->buffer); vbuffers[attr].buffer = NULL; - pipe_reference_buffer(pipe, &vbuffers[attr].buffer, stobj->buffer); + pipe_buffer_reference(pipe->screen, &vbuffers[attr].buffer, stobj->buffer); vbuffers[attr].buffer_offset = (unsigned) arrays[0]->Ptr;/* in bytes */ velements[attr].src_offset = arrays[mesaAttr]->Ptr - arrays[0]->Ptr; } @@ -564,7 +762,7 @@ st_feedback_draw_vbo(GLcontext *ctx, /* wrap user data */ vbuffers[attr].buffer - = pipe_user_buffer_create(pipe, (void *) arrays[mesaAttr]->Ptr, + = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, bytes); vbuffers[attr].buffer_offset = 0; velements[attr].src_offset = 0; @@ -586,7 +784,7 @@ st_feedback_draw_vbo(GLcontext *ctx, #endif /* map the attrib buffer */ - map = pipe_buffer_map(pipe, vbuffers[attr].buffer, + map = pipe_buffer_map(pipe->screen, vbuffers[attr].buffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_vertex_buffer(draw, attr, map); } @@ -614,7 +812,7 @@ st_feedback_draw_vbo(GLcontext *ctx, return; } - map = pipe_buffer_map(pipe, index_buffer_handle, + map = pipe_buffer_map(pipe->screen, index_buffer_handle, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_element_buffer(draw, indexSize, map); } @@ -625,7 +823,7 @@ st_feedback_draw_vbo(GLcontext *ctx, /* map constant buffers */ - mapped_constants = pipe_buffer_map(pipe, + mapped_constants = pipe_buffer_map(pipe->screen, st->state.constants[PIPE_SHADER_VERTEX].buffer, PIPE_BUFFER_USAGE_CPU_READ); draw_set_mapped_constant_buffer(st->draw, mapped_constants, @@ -639,20 +837,20 @@ st_feedback_draw_vbo(GLcontext *ctx, /* unmap constant buffers */ - pipe_buffer_unmap(pipe, st->state.constants[PIPE_SHADER_VERTEX].buffer); + pipe_buffer_unmap(pipe->screen, st->state.constants[PIPE_SHADER_VERTEX].buffer); /* * unmap vertex/index buffers */ for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { if (draw->pt.vertex_buffer[i].buffer) { - pipe_buffer_unmap(pipe, draw->pt.vertex_buffer[i].buffer); - pipe_reference_buffer(pipe, &draw->pt.vertex_buffer[i].buffer, NULL); + pipe_buffer_unmap(pipe->screen, draw->pt.vertex_buffer[i].buffer); + pipe_buffer_reference(pipe->screen, &draw->pt.vertex_buffer[i].buffer, NULL); draw_set_mapped_vertex_buffer(draw, i, NULL); } } if (ib) { - pipe_buffer_unmap(pipe, index_buffer_handle); + pipe_buffer_unmap(pipe->screen, index_buffer_handle); draw_set_mapped_element_buffer(draw, 0, NULL); } } diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c index b7444b298cf..60fd440ef77 100644 --- a/src/mesa/state_tracker/st_extensions.c +++ b/src/mesa/state_tracker/st_extensions.c @@ -218,6 +218,26 @@ void st_init_extensions(struct st_context *st) /*ctx->Extensions.ARB_shadow_ambient = GL_TRUE;*/ } + /* GL_EXT_packed_depth_stencil requires both the ability to render to + * a depth/stencil buffer and texture from depth/stencil source. + */ + if (screen->is_format_supported(screen, PIPE_FORMAT_Z24S8_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0) && + screen->is_format_supported(screen, PIPE_FORMAT_Z24S8_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)) { + ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE; + } + else if (screen->is_format_supported(screen, PIPE_FORMAT_S8Z24_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0) && + screen->is_format_supported(screen, PIPE_FORMAT_S8Z24_UNORM, + PIPE_TEXTURE_2D, + PIPE_TEXTURE_USAGE_SAMPLER, 0)) { + ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE; + } + if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8B8A8_SRGB, PIPE_TEXTURE_2D, PIPE_TEXTURE_USAGE_SAMPLER, 0)) { diff --git a/src/mesa/state_tracker/st_format.c b/src/mesa/state_tracker/st_format.c index 2461f396223..a8ae30a454f 100644 --- a/src/mesa/state_tracker/st_format.c +++ b/src/mesa/state_tracker/st_format.c @@ -342,6 +342,9 @@ default_depth_format(struct pipe_screen *screen, /** * Given an OpenGL internalFormat value for a texture or surface, return * the best matching PIPE_FORMAT_x, or PIPE_FORMAT_NONE if there's no match. + * \param target one of PIPE_TEXTURE_x + * \param tex_usage either PIPE_TEXTURE_USAGE_RENDER_TARGET + * or PIPE_TEXTURE_USAGE_SAMPLER */ enum pipe_format st_choose_format(struct pipe_context *pipe, GLint internalFormat, @@ -515,14 +518,35 @@ st_choose_format(struct pipe_context *pipe, GLint internalFormat, } +static GLboolean +is_stencil_format(GLenum format) +{ + switch (format) { + case GL_STENCIL_INDEX: + case GL_STENCIL_INDEX1_EXT: + case GL_STENCIL_INDEX4_EXT: + case GL_STENCIL_INDEX8_EXT: + case GL_STENCIL_INDEX16_EXT: + case GL_DEPTH_STENCIL_EXT: + case GL_DEPTH24_STENCIL8_EXT: + return GL_TRUE; + default: + return GL_FALSE; + } +} + /** * Called by FBO code to choose a PIPE_FORMAT_ for drawing surfaces. */ enum pipe_format st_choose_renderbuffer_format(struct pipe_context *pipe, GLint internalFormat) { - return st_choose_format(pipe, internalFormat, PIPE_TEXTURE_2D, - PIPE_TEXTURE_USAGE_RENDER_TARGET); + uint usage; + if (is_stencil_format(internalFormat)) + usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL; + else + usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; + return st_choose_format(pipe, internalFormat, PIPE_TEXTURE_2D, usage); } diff --git a/src/mesa/state_tracker/st_framebuffer.c b/src/mesa/state_tracker/st_framebuffer.c index 039a9cfe899..0f4a03fa484 100644 --- a/src/mesa/state_tracker/st_framebuffer.c +++ b/src/mesa/state_tracker/st_framebuffer.c @@ -74,7 +74,7 @@ st_create_framebuffer( const __GLcontextModes *visual, _mesa_add_renderbuffer(&stfb->Base, BUFFER_BACK_LEFT, rb); } - if (visual->depthBits == 24 && visual->stencilBits == 8) { + if (depthFormat == stencilFormat && depthFormat != PIPE_FORMAT_NONE) { /* combined depth/stencil buffer */ struct gl_renderbuffer *depthStencilRb = st_new_renderbuffer_fb(depthFormat, samples); @@ -265,7 +265,9 @@ st_notify_swapbuffers(struct st_framebuffer *stfb) if (ctx && ctx->DrawBuffer == &stfb->Base) { st_flush( ctx->st, - PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_SWAPBUFFERS, + PIPE_FLUSH_RENDER_CACHE | + PIPE_FLUSH_SWAPBUFFERS | + PIPE_FLUSH_FRAME, NULL ); ctx->st->frontbuffer_status = FRONT_STATUS_COPY_OF_BACK; } diff --git a/src/mesa/state_tracker/st_gen_mipmap.c b/src/mesa/state_tracker/st_gen_mipmap.c index 6db9bc0dd58..b9d114b1c97 100644 --- a/src/mesa/state_tracker/st_gen_mipmap.c +++ b/src/mesa/state_tracker/st_gen_mipmap.c @@ -128,10 +128,10 @@ fallback_generate_mipmap(GLcontext *ctx, GLenum target, dstSurf = screen->get_tex_surface(screen, pt, face, dstLevel, zslice, PIPE_BUFFER_USAGE_CPU_WRITE); - srcData = (ubyte *) pipe_buffer_map(pipe, srcSurf->buffer, + srcData = (ubyte *) pipe_buffer_map(pipe->screen, srcSurf->buffer, PIPE_BUFFER_USAGE_CPU_READ) + srcSurf->offset; - dstData = (ubyte *) pipe_buffer_map(pipe, dstSurf->buffer, + dstData = (ubyte *) pipe_buffer_map(pipe->screen, dstSurf->buffer, PIPE_BUFFER_USAGE_CPU_WRITE) + dstSurf->offset; @@ -144,8 +144,8 @@ fallback_generate_mipmap(GLcontext *ctx, GLenum target, dstSurf->stride, /* stride in bytes */ dstData); - pipe_buffer_unmap(pipe, srcSurf->buffer); - pipe_buffer_unmap(pipe, dstSurf->buffer); + pipe_buffer_unmap(pipe->screen, srcSurf->buffer); + pipe_buffer_unmap(pipe->screen, dstSurf->buffer); pipe_surface_reference(&srcSurf, NULL); pipe_surface_reference(&dstSurf, NULL); diff --git a/src/mesa/state_tracker/st_mesa_to_tgsi.c b/src/mesa/state_tracker/st_mesa_to_tgsi.c index 198d406b593..5ec9fddd7f4 100644 --- a/src/mesa/state_tracker/st_mesa_to_tgsi.c +++ b/src/mesa/state_tracker/st_mesa_to_tgsi.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -47,7 +47,8 @@ static GLuint map_register_file( enum register_file file, GLuint index, - const GLuint immediateMapping[] ) + const GLuint immediateMapping[], + GLboolean indirectAccess ) { switch( file ) { case PROGRAM_UNDEFINED: @@ -66,11 +67,13 @@ map_register_file( case PROGRAM_STATE_VAR: case PROGRAM_NAMED_PARAM: case PROGRAM_UNIFORM: - if (immediateMapping && immediateMapping[index] != ~0) + if (!indirectAccess && immediateMapping && immediateMapping[index] != ~0) return TGSI_FILE_IMMEDIATE; else return TGSI_FILE_CONSTANT; case PROGRAM_CONSTANT: + if (indirectAccess) + return TGSI_FILE_CONSTANT; return TGSI_FILE_IMMEDIATE; case PROGRAM_INPUT: return TGSI_FILE_INPUT; @@ -98,7 +101,8 @@ map_register_file_index( GLuint index, const GLuint inputMapping[], const GLuint outputMapping[], - const GLuint immediateMapping[]) + const GLuint immediateMapping[], + GLboolean indirectAccess ) { switch( file ) { case TGSI_FILE_INPUT: @@ -109,6 +113,8 @@ map_register_file_index( return outputMapping[index]; case TGSI_FILE_IMMEDIATE: + if (indirectAccess) + return index; return immediateMapping[index]; default: @@ -175,10 +181,11 @@ static struct tgsi_full_immediate make_immediate(const float *value, uint size) { struct tgsi_full_immediate imm; - imm.Immediate.Type = TGSI_TOKEN_TYPE_IMMEDIATE; - imm.Immediate.Size = 1 + size; /* one for the token itself */ + + imm = tgsi_default_full_immediate(); + imm.Immediate.Size += size; imm.Immediate.DataType = TGSI_IMM_FLOAT32; - imm.u.ImmediateFloat32 = (struct tgsi_immediate_float32 *) value; + imm.u.Pointer = value; return imm; } @@ -189,6 +196,7 @@ compile_instruction( const GLuint inputMapping[], const GLuint outputMapping[], const GLuint immediateMapping[], + GLboolean indirectAccess, GLuint preamble_size, GLuint processor, GLboolean *insideSubroutine) @@ -204,29 +212,32 @@ compile_instruction( fullinst->Instruction.NumSrcRegs = _mesa_num_inst_src_regs( inst->Opcode ); fulldst = &fullinst->FullDstRegisters[0]; - fulldst->DstRegister.File = map_register_file( inst->DstReg.File, 0, NULL ); + fulldst->DstRegister.File = map_register_file( inst->DstReg.File, 0, NULL, GL_FALSE ); fulldst->DstRegister.Index = map_register_file_index( fulldst->DstRegister.File, inst->DstReg.Index, inputMapping, outputMapping, - NULL - ); + NULL, + GL_FALSE ); fulldst->DstRegister.WriteMask = convert_writemask( inst->DstReg.WriteMask ); - for( i = 0; i < fullinst->Instruction.NumSrcRegs; i++ ) { + for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) { GLuint j; fullsrc = &fullinst->FullSrcRegisters[i]; - fullsrc->SrcRegister.File = map_register_file( inst->SrcReg[i].File, - inst->SrcReg[i].Index, - immediateMapping ); + fullsrc->SrcRegister.File = map_register_file( + inst->SrcReg[i].File, + inst->SrcReg[i].Index, + immediateMapping, + indirectAccess ); fullsrc->SrcRegister.Index = map_register_file_index( fullsrc->SrcRegister.File, inst->SrcReg[i].Index, inputMapping, outputMapping, - immediateMapping); + immediateMapping, + indirectAccess ); /* swizzle (ext swizzle also depends on negation) */ { @@ -609,6 +620,19 @@ make_temp_decl( return decl; } +static struct tgsi_full_declaration +make_addr_decl( + GLuint start_index, + GLuint end_index ) +{ + struct tgsi_full_declaration decl; + + decl = tgsi_default_full_declaration(); + decl.Declaration.File = TGSI_FILE_ADDRESS; + decl.DeclarationRange.First = start_index; + decl.DeclarationRange.Last = end_index; + return decl; +} static struct tgsi_full_declaration make_sampler_decl(GLuint index) @@ -707,6 +731,7 @@ tgsi_translate_mesa_program( GLuint immediates[1000]; GLuint numImmediates = 0; GLboolean insideSubroutine = GL_FALSE; + GLboolean indirectAccess = GL_FALSE; assert(procType == TGSI_PROCESSOR_FRAGMENT || procType == TGSI_PROCESSOR_VERTEX); @@ -819,45 +844,78 @@ tgsi_translate_mesa_program( inside_range = GL_FALSE; fulldecl = make_temp_decl( start_range, i - 1 ); ti += tgsi_build_full_declaration( - &fulldecl, - &tokens[ti], - header, - maxTokens - ti ); + &fulldecl, + &tokens[ti], + header, + maxTokens - ti ); } } } + /* Declare address register. + */ + if (program->NumAddressRegs > 0) { + struct tgsi_full_declaration fulldecl; + + assert( program->NumAddressRegs == 1 ); + + fulldecl = make_addr_decl( 0, 0 ); + ti += tgsi_build_full_declaration( + &fulldecl, + &tokens[ti], + header, + maxTokens - ti ); + + indirectAccess = GL_TRUE; + } + /* immediates/literals */ memset(immediates, ~0, sizeof(immediates)); - for (i = 0; program->Parameters && i < program->Parameters->NumParameters; - i++) { - if (program->Parameters->Parameters[i].Type == PROGRAM_CONSTANT) { - struct tgsi_full_immediate fullimm - = make_immediate(program->Parameters->ParameterValues[i], 4); - ti += tgsi_build_full_immediate(&fullimm, - &tokens[ti], - header, - maxTokens - ti); - immediates[i] = numImmediates; - numImmediates++; + /* Emit immediates only when there is no address register in use. + * FIXME: Be smarter and recognize param arrays -- indirect addressing is + * only valid within the referenced array. + */ + if (program->Parameters && !indirectAccess) { + for (i = 0; i < program->Parameters->NumParameters; i++) { + if (program->Parameters->Parameters[i].Type == PROGRAM_CONSTANT) { + struct tgsi_full_immediate fullimm; + + fullimm = make_immediate( program->Parameters->ParameterValues[i], 4 ); + ti += tgsi_build_full_immediate( + &fullimm, + &tokens[ti], + header, + maxTokens - ti ); + immediates[i] = numImmediates; + numImmediates++; + } } } /* constant buffer refs */ - { + if (program->Parameters) { GLint start = -1, end = -1; - for (i = 0; - program->Parameters && i < program->Parameters->NumParameters; - i++) { + for (i = 0; i < program->Parameters->NumParameters; i++) { GLboolean emit = (i == program->Parameters->NumParameters - 1); + GLboolean matches; switch (program->Parameters->Parameters[i].Type) { case PROGRAM_ENV_PARAM: case PROGRAM_STATE_VAR: case PROGRAM_NAMED_PARAM: case PROGRAM_UNIFORM: + matches = GL_TRUE; + break; + case PROGRAM_CONSTANT: + matches = indirectAccess; + break; + default: + matches = GL_FALSE; + } + + if (matches) { if (start == -1) { /* begin a sequence */ start = i; @@ -867,8 +925,8 @@ tgsi_translate_mesa_program( /* continue sequence */ end = i; } - break; - default: + } + else { if (start != -1) { /* end of sequence */ emit = GL_TRUE; @@ -877,11 +935,13 @@ tgsi_translate_mesa_program( if (emit && start >= 0) { struct tgsi_full_declaration fulldecl; + fulldecl = make_constant_decl( start, end ); - ti += tgsi_build_full_declaration(&fulldecl, - &tokens[ti], - header, - maxTokens - ti); + ti += tgsi_build_full_declaration( + &fulldecl, + &tokens[ti], + header, + maxTokens - ti ); start = end = -1; } } @@ -891,25 +951,27 @@ tgsi_translate_mesa_program( for (i = 0; i < 8; i++) { if (program->SamplersUsed & (1 << i)) { struct tgsi_full_declaration fulldecl; + fulldecl = make_sampler_decl( i ); - ti += tgsi_build_full_declaration(&fulldecl, - &tokens[ti], - header, - maxTokens - ti ); + ti += tgsi_build_full_declaration( + &fulldecl, + &tokens[ti], + header, + maxTokens - ti ); } } - - for( i = 0; i < program->NumInstructions; i++ ) { + for (i = 0; i < program->NumInstructions; i++) { compile_instruction( - &program->Instructions[i], - &fullinst, - inputMapping, - outputMapping, - immediates, - preamble_size, - procType, - &insideSubroutine); + &program->Instructions[i], + &fullinst, + inputMapping, + outputMapping, + immediates, + indirectAccess, + preamble_size, + procType, + &insideSubroutine ); ti += tgsi_build_full_instruction( &fullinst, @@ -920,4 +982,3 @@ tgsi_translate_mesa_program( return ti; } - diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c index 59314a32322..936a6e32ea1 100644 --- a/src/mesa/state_tracker/st_program.c +++ b/src/mesa/state_tracker/st_program.c @@ -55,7 +55,7 @@ #define TGSI_DEBUG 0 -/** XXX we should use the version of this from p_util.h but including +/** XXX we should use the version of this from u_memory.h but including * that header causes symbol collisions. */ static INLINE void * @@ -71,15 +71,17 @@ mem_dup(const void *src, uint size) /** * Translate a Mesa vertex shader into a TGSI shader. - * \param outputMapping to map vertex program output registers to TGSI - * output slots + * \param outputMapping to map vertex program output registers (VERT_RESULT_x) + * to TGSI output slots * \param tokensOut destination for TGSI tokens * \return pointer to cached pipe_shader object. */ void st_translate_vertex_program(struct st_context *st, struct st_vertex_program *stvp, - const GLuint outputMapping[]) + const GLuint outputMapping[], + const ubyte *outputSemanticName, + const ubyte *outputSemanticIndex) { struct pipe_context *pipe = st->pipe; struct tgsi_token tokens[ST_MAX_SHADER_TOKENS]; @@ -172,6 +174,20 @@ st_translate_vertex_program(struct st_context *st, } } +#if 0 + if (outputMapping && outputSemanticName) { + printf("VERT_RESULT written out_slot semantic_name semantic_index\n"); + for (attr = 0; attr < VERT_RESULT_MAX; attr++) { + printf(" %-2d %c %3d %2d %2d\n", + attr, + ((stvp->Base.Base.OutputsWritten & (1 << attr)) ? 'Y' : ' '), + outputMapping[attr], + outputSemanticName[attr], + outputSemanticIndex[attr]); + } + } +#endif + /* initialize output semantics to defaults */ for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) { vs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC; @@ -203,10 +219,6 @@ st_translate_vertex_program(struct st_context *st, defaultOutputMapping[attr] = slot; } - /* - printf("Output %u -> slot %u\n", attr, slot); - */ - switch (attr) { case VERT_RESULT_HPOS: assert(slot == 0); @@ -248,15 +260,21 @@ st_translate_vertex_program(struct st_context *st, case VERT_RESULT_TEX5: case VERT_RESULT_TEX6: case VERT_RESULT_TEX7: - vs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - vs_output_semantic_index[slot] = num_generic++; - break; + /* fall-through */ case VERT_RESULT_VAR0: /* fall-through */ default: - assert(attr - VERT_RESULT_VAR0 < MAX_VARYING); - vs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - vs_output_semantic_index[slot] = num_generic++; + if (outputSemanticName) { + /* use provided semantic into */ + assert(outputSemanticName[attr] != TGSI_SEMANTIC_COUNT); + vs_output_semantic_name[slot] = outputSemanticName[attr]; + vs_output_semantic_index[slot] = outputSemanticIndex[attr]; + } + else { + /* use default semantic info */ + vs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + vs_output_semantic_index[slot] = num_generic++; + } } } } @@ -347,8 +365,6 @@ st_translate_fragment_program(struct st_context *st, GLuint num_generic = 0; GLuint num_tokens; - ubyte fs_input_semantic_name[PIPE_MAX_SHADER_INPUTS]; - ubyte fs_input_semantic_index[PIPE_MAX_SHADER_INPUTS]; uint fs_num_inputs = 0; ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; @@ -378,23 +394,23 @@ st_translate_fragment_program(struct st_context *st, switch (attr) { case FRAG_ATTRIB_WPOS: - fs_input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; - fs_input_semantic_index[slot] = 0; + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + stfp->input_semantic_index[slot] = 0; interpMode[slot] = TGSI_INTERPOLATE_LINEAR; break; case FRAG_ATTRIB_COL0: - fs_input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - fs_input_semantic_index[slot] = 0; + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stfp->input_semantic_index[slot] = 0; interpMode[slot] = TGSI_INTERPOLATE_LINEAR; break; case FRAG_ATTRIB_COL1: - fs_input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; - fs_input_semantic_index[slot] = 1; + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stfp->input_semantic_index[slot] = 1; interpMode[slot] = TGSI_INTERPOLATE_LINEAR; break; case FRAG_ATTRIB_FOGC: - fs_input_semantic_name[slot] = TGSI_SEMANTIC_FOG; - fs_input_semantic_index[slot] = 0; + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG; + stfp->input_semantic_index[slot] = 0; interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; break; case FRAG_ATTRIB_TEX0: @@ -405,15 +421,15 @@ st_translate_fragment_program(struct st_context *st, case FRAG_ATTRIB_TEX5: case FRAG_ATTRIB_TEX6: case FRAG_ATTRIB_TEX7: - fs_input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - fs_input_semantic_index[slot] = num_generic++; + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stfp->input_semantic_index[slot] = num_generic++; interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; break; case FRAG_ATTRIB_VAR0: /* fall-through */ default: - fs_input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - fs_input_semantic_index[slot] = num_generic++; + stfp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stfp->input_semantic_index[slot] = num_generic++; interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; } } @@ -467,8 +483,8 @@ st_translate_fragment_program(struct st_context *st, /* inputs */ fs_num_inputs, inputMapping, - fs_input_semantic_name, - fs_input_semantic_index, + stfp->input_semantic_name, + stfp->input_semantic_index, interpMode, /* outputs */ fs_num_outputs, diff --git a/src/mesa/state_tracker/st_program.h b/src/mesa/state_tracker/st_program.h index 086e9391aa9..078e2c42a69 100644 --- a/src/mesa/state_tracker/st_program.h +++ b/src/mesa/state_tracker/st_program.h @@ -58,6 +58,9 @@ struct st_fragment_program /** map FP input back to VP output */ GLuint input_map[PIPE_MAX_SHADER_INPUTS]; + ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; + ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; + struct pipe_shader_state state; void *driver_shader; @@ -143,6 +146,9 @@ st_translate_fragment_program(struct st_context *st, extern void st_translate_vertex_program(struct st_context *st, struct st_vertex_program *vp, - const GLuint vert_output_to_slot[]); + const GLuint vert_output_to_slot[], + const ubyte *fs_input_semantic_name, + const ubyte *fs_input_semantic_index); + #endif diff --git a/src/mesa/state_tracker/st_public.h b/src/mesa/state_tracker/st_public.h index ca4e9577b1b..5cfb2e41f24 100644 --- a/src/mesa/state_tracker/st_public.h +++ b/src/mesa/state_tracker/st_public.h @@ -41,6 +41,10 @@ #define ST_SURFACE_BACK_RIGHT 3 #define ST_SURFACE_DEPTH 8 +#define ST_TEXTURE_2D 0x2 +#define ST_TEXTURE_RGB 0x1 +#define ST_TEXTURE_RGBA 0x2 + struct st_context; struct st_framebuffer; @@ -93,6 +97,15 @@ void st_notify_swapbuffers(struct st_framebuffer *stfb); void st_notify_swapbuffers_complete(struct st_framebuffer *stfb); +/** Redirect rendering into stfb's surface to a texture image */ +int st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex, + int target, int format, int level); + +/** Undo surface-to-texture binding */ +int st_release_teximage(struct st_framebuffer *stfb, uint surfIndex, + int target, int format, int level); + + /** Generic function type */ typedef void (*st_proc)(); diff --git a/src/mesa/state_tracker/st_texture.c b/src/mesa/state_tracker/st_texture.c index 289b78b38b3..29b16347625 100644 --- a/src/mesa/state_tracker/st_texture.c +++ b/src/mesa/state_tracker/st_texture.c @@ -27,8 +27,11 @@ #include "st_context.h" #include "st_format.h" +#include "st_public.h" #include "st_texture.h" +#include "st_cb_fbo.h" #include "main/enums.h" +#include "main/teximage.h" #undef Elements /* fix re-defined macro warning */ @@ -36,8 +39,8 @@ #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "pipe/p_inlines.h" -#include "pipe/p_util.h" #include "pipe/p_inlines.h" +#include "util/u_rect.h" #define DBG if(0) printf @@ -301,9 +304,6 @@ st_texture_image_copy(struct pipe_context *pipe, struct pipe_surface *dst_surface; GLuint i; - /* XXX this is a hack */ - const GLuint copyHeight = dst->compressed ? height / 4 : height; - for (i = 0; i < depth; i++) { GLuint srcLevel; @@ -345,9 +345,97 @@ st_texture_image_copy(struct pipe_context *pipe, 0, 0, /* destX, Y */ src_surface, 0, 0, /* srcX, Y */ - width, copyHeight); + width, height); screen->tex_surface_release(screen, &src_surface); screen->tex_surface_release(screen, &dst_surface); } } + + +/** Redirect rendering into stfb's surface to a texture image */ +int +st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex, + int target, int format, int level) +{ + GET_CURRENT_CONTEXT(ctx); + struct st_context *st = ctx->st; + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + const GLuint unit = ctx->Texture.CurrentUnit; + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *texObj; + struct gl_texture_image *texImage; + struct st_texture_image *stImage; + struct st_renderbuffer *strb; + GLint face = 0, slice = 0; + + assert(surfIndex <= ST_SURFACE_DEPTH); + + strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); + + if (strb->texture_save || strb->surface_save) { + /* Error! */ + return 0; + } + + if (target == ST_TEXTURE_2D) { + texObj = texUnit->Current2D; + texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, level); + stImage = st_texture_image(texImage); + } + else { + /* unsupported target */ + return 0; + } + + st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); + + /* save the renderbuffer's surface/texture info */ + pipe_texture_reference(&strb->texture_save, strb->texture); + pipe_surface_reference(&strb->surface_save, strb->surface); + + /* plug in new surface/texture info */ + pipe_texture_reference(&strb->texture, stImage->pt); + strb->surface = screen->get_tex_surface(screen, strb->texture, + face, level, slice, + (PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE)); + + st->dirty.st |= ST_NEW_FRAMEBUFFER; + + return 1; +} + + +/** Undo surface-to-texture binding */ +int +st_release_teximage(struct st_framebuffer *stfb, uint surfIndex, + int target, int format, int level) +{ + GET_CURRENT_CONTEXT(ctx); + struct st_context *st = ctx->st; + struct st_renderbuffer *strb; + + assert(surfIndex <= ST_SURFACE_DEPTH); + + strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); + + if (!strb->texture_save || !strb->surface_save) { + /* Error! */ + return 0; + } + + st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); + + /* free tex surface, restore original */ + pipe_surface_reference(&strb->surface, strb->surface_save); + pipe_texture_reference(&strb->texture, strb->texture_save); + + pipe_surface_reference(&strb->surface_save, NULL); + pipe_texture_reference(&strb->texture_save, NULL); + + st->dirty.st |= ST_NEW_FRAMEBUFFER; + + return 1; +} diff --git a/src/mesa/state_tracker/st_texture.h b/src/mesa/state_tracker/st_texture.h index 3febe6a7cb0..31f66ad52cf 100644 --- a/src/mesa/state_tracker/st_texture.h +++ b/src/mesa/state_tracker/st_texture.h @@ -72,6 +72,12 @@ struct st_texture_object }; +static INLINE struct st_texture_image * +st_texture_image(struct gl_texture_image *img) +{ + return (struct st_texture_image *) img; +} + static INLINE struct st_texture_object * st_texture_object(struct gl_texture_object *obj) { |