gallium: fix some render to texture bugs

Before, we were sometimes rendering into a stale texture because
st_finalize_texture() would discard the old texture and create a new one.

Moved st_update_framebuffer atom after texture validation so that we
can create a new renderbuffer surface if the texture changes.

Also, split texture validation into two parts: finalize_textures and
update_textures.  Do finalize_textures first to avoid getting into the
situtation where we're doing a pipe->surface_copy() mid-way through
state validation.

Some debug code still in place, but disabled...
This commit is contained in:
Brian Paul 2008-05-07 16:44:33 -06:00
parent 8f76459f62
commit 1a82d9648b
11 changed files with 189 additions and 40 deletions

View File

@ -45,10 +45,10 @@
*/
static const struct st_tracked_state *atoms[] =
{
&st_update_framebuffer,
&st_update_depth_stencil_alpha,
&st_update_clip,
&st_finalize_textures,
&st_update_shader,
&st_update_rasterizer,
@ -58,6 +58,7 @@ static const struct st_tracked_state *atoms[] =
&st_update_blend,
&st_update_sampler,
&st_update_texture,
&st_update_framebuffer,
&st_update_vs_constants,
&st_update_fs_constants,
&st_update_pixel_transfer

View File

@ -55,6 +55,7 @@ extern const struct st_tracked_state st_update_scissor;
extern const struct st_tracked_state st_update_blend;
extern const struct st_tracked_state st_update_sampler;
extern const struct st_tracked_state st_update_texture;
extern const struct st_tracked_state st_finalize_textures;
extern const struct st_tracked_state st_update_fs_constants;
extern const struct st_tracked_state st_update_vs_constants;
extern const struct st_tracked_state st_update_pixel_transfer;

View File

@ -34,13 +34,60 @@
#include "st_context.h"
#include "st_atom.h"
#include "st_cb_fbo.h"
#include "st_texture.h"
#include "pipe/p_context.h"
#include "pipe/p_inlines.h"
#include "cso_cache/cso_context.h"
/**
* When doing GL render to texture, we have to be sure that finalize_texture()
* didn't yank out the pipe_texture that we earlier created a surface for.
* Check for that here and create a new surface if needed.
*/
static void
update_renderbuffer_surface(struct st_context *st,
struct st_renderbuffer *strb)
{
struct pipe_screen *screen = st->pipe->screen;
struct pipe_texture *texture = strb->rtt->pt;
int rtt_width = strb->Base.Width;
int rtt_height = strb->Base.Height;
if (!strb->surface ||
strb->surface->texture != texture ||
strb->surface->width != rtt_width ||
strb->surface->height != rtt_height) {
int level;
/* find matching mipmap level size */
for (level = 0; level <= texture->last_level; level++) {
if (texture->width[level] == rtt_width &&
texture->height[level] == rtt_height) {
pipe_surface_reference(&strb->surface, NULL);
strb->surface = screen->get_tex_surface(screen,
texture,
strb->rtt_face,
level,
strb->rtt_slice,
PIPE_BUFFER_USAGE_GPU_READ |
PIPE_BUFFER_USAGE_GPU_WRITE);
#if 0
printf("-- alloc new surface %d x %d into tex %p\n",
strb->surface->width, strb->surface->height,
texture);
#endif
break;
}
}
}
}
/**
* Update framebuffer state (color, depth, stencil, etc. buffers)
* XXX someday: separate draw/read buffers.
*/
static void
update_framebuffer_state( struct st_context *st )
@ -55,6 +102,8 @@ update_framebuffer_state( struct st_context *st )
framebuffer->width = fb->Width;
framebuffer->height = fb->Height;
/*printf("------ fb size %d x %d\n", fb->Width, fb->Height);*/
/* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state
* to determine which surfaces to draw to
*/
@ -62,6 +111,13 @@ update_framebuffer_state( struct st_context *st )
for (j = 0; j < MAX_DRAW_BUFFERS; j++) {
for (i = 0; i < fb->_NumColorDrawBuffers[j]; i++) {
strb = st_renderbuffer(fb->_ColorDrawBuffers[j][i]);
/*printf("--------- framebuffer surface rtt %p\n", strb->rtt);*/
if (strb->rtt) {
/* rendering to a GL texture, may have to update surface */
update_renderbuffer_surface(st, strb);
}
assert(strb->surface);
framebuffer->cbufs[framebuffer->num_cbufs] = strb->surface;
framebuffer->num_cbufs++;
@ -99,7 +155,7 @@ const struct st_tracked_state st_update_framebuffer = {
"st_update_framebuffer", /* name */
{ /* dirty */
_NEW_BUFFERS, /* mesa */
0, /* st */
ST_NEW_FRAMEBUFFER, /* st */
},
update_framebuffer_state /* update */
};

View File

@ -44,6 +44,8 @@
#include "pipe/p_context.h"
#include "pipe/p_shader_tokens.h"
#include "util/u_simple_shaders.h"
#include "cso_cache/cso_context.h"
#include "st_context.h"
@ -252,6 +254,20 @@ st_free_translated_vertex_programs(struct st_context *st,
}
static void *
get_passthrough_fs(struct st_context *st)
{
struct pipe_shader_state shader;
if (!st->passthrough_fs) {
st->passthrough_fs =
util_make_fragment_passthrough_shader(st->pipe, &shader);
free((void *) shader.tokens);
}
return st->passthrough_fs;
}
static void
update_linkage( struct st_context *st )
@ -277,7 +293,15 @@ update_linkage( struct st_context *st )
st_reference_fragprog(st, &st->fp, stfp);
cso_set_vertex_shader_handle(st->cso_context, stvp->driver_shader);
cso_set_fragment_shader_handle(st->cso_context, stfp->driver_shader);
if (st->missing_textures) {
/* use a pass-through frag shader that uses no textures */
void *fs = get_passthrough_fs(st);
cso_set_fragment_shader_handle(st->cso_context, fs);
}
else {
cso_set_fragment_shader_handle(st->cso_context, stfp->driver_shader);
}
st->vertex_result_to_slot = xvp->output_to_slot;
}

View File

@ -39,34 +39,13 @@
#include "pipe/p_context.h"
#include "pipe/p_inlines.h"
#include "cso_cache/cso_context.h"
#include "util/u_simple_shaders.h"
static void *
get_passthrough_fs(struct st_context *st)
{
struct pipe_shader_state shader;
if (!st->passthrough_fs) {
st->passthrough_fs =
util_make_fragment_passthrough_shader(st->pipe, &shader);
free((void *) shader.tokens);
}
return st->passthrough_fs;
}
/**
* XXX This needs some work yet....
* Need to "upload" texture images at appropriate times.
*/
static void
update_textures(struct st_context *st)
{
struct gl_fragment_program *fprog = st->ctx->FragmentProgram._Current;
GLuint su;
GLboolean missing_textures = GL_FALSE;
st->state.num_textures = 0;
@ -85,13 +64,11 @@ update_textures(struct st_context *st)
retval = st_finalize_texture(st->ctx, st->pipe, texObj, &flush);
if (!retval) {
/* out of mem */
missing_textures = GL_TRUE;
/* missing texture */
continue;
}
st->state.num_textures = su + 1;
stObj->teximage_realloc = TRUE;
}
pt = st_get_stobj_texture(stObj);
@ -103,12 +80,6 @@ update_textures(struct st_context *st)
cso_set_sampler_textures(st->cso_context,
st->state.num_textures,
st->state.sampler_texture);
if (missing_textures) {
/* use a pass-through frag shader that uses no textures */
void *fs = get_passthrough_fs(st);
cso_set_fragment_shader_handle(st->cso_context, fs);
}
}
@ -120,3 +91,52 @@ const struct st_tracked_state st_update_texture = {
},
update_textures /* update */
};
static void
finalize_textures(struct st_context *st)
{
struct gl_fragment_program *fprog = st->ctx->FragmentProgram._Current;
const GLboolean prev_missing_textures = st->missing_textures;
GLuint su;
st->missing_textures = GL_FALSE;
for (su = 0; su < st->ctx->Const.MaxTextureCoordUnits; su++) {
if (fprog->Base.SamplersUsed & (1 << su)) {
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;
retval = st_finalize_texture(st->ctx, st->pipe, texObj, &flush);
if (!retval) {
/* out of mem */
st->missing_textures = GL_TRUE;
continue;
}
stObj->teximage_realloc = TRUE;
}
}
}
if (prev_missing_textures != st->missing_textures)
st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM;
}
const struct st_tracked_state st_finalize_textures = {
"st_finalize_textures", /* name */
{ /* dirty */
_NEW_TEXTURE, /* mesa */
0, /* st */
},
finalize_textures /* update */
};

View File

@ -358,6 +358,10 @@ st_render_texture(GLcontext *ctx,
struct pipe_context *pipe = st->pipe;
struct pipe_screen *screen = pipe->screen;
struct pipe_texture *pt;
struct st_texture_object *stObj;
const struct gl_texture_image *texImage =
att->Texture->Image[att->CubeMapFace][att->TextureLevel];
assert(!att->Renderbuffer);
@ -374,27 +378,42 @@ st_render_texture(GLcontext *ctx,
strb = st_renderbuffer(rb);
/* get the texture for the texture object */
stObj = st_texture_object(att->Texture);
/* point renderbuffer at texobject */
strb->rtt = stObj;
strb->rtt_level = att->TextureLevel;
strb->rtt_face = att->CubeMapFace;
strb->rtt_slice = att->Zoffset;
rb->Width = texImage->Width2;
rb->Height = texImage->Height2;
/*printf("***** render to texture level %d: %d x %d\n", att->TextureLevel, rb->Width, rb->Height);*/
pt = st_get_texobj_texture(att->Texture);
assert(pt);
assert(pt->width[att->TextureLevel]);
rb->Width = pt->width[att->TextureLevel];
rb->Height = pt->height[att->TextureLevel];
/*printf("***** pipe texture %d x %d\n", pt->width[0], pt->height[0]);*/
pipe_texture_reference( &strb->texture, pt );
pipe_surface_reference(&strb->surface, NULL);
#if 0
/* the renderbuffer's surface is inside the texture */
strb->surface = screen->get_tex_surface(screen, pt,
att->CubeMapFace,
att->TextureLevel,
att->TextureLevel /*- att->Texture->BaseLevel*/,
att->Zoffset,
PIPE_BUFFER_USAGE_GPU_READ |
PIPE_BUFFER_USAGE_GPU_WRITE);
printf("***** surface size: %d x %d\n", strb->surface->width, strb->surface->height);
assert(strb->surface);
assert(screen->is_format_supported(screen, strb->surface->format, PIPE_TEXTURE));
assert(screen->is_format_supported(screen, strb->surface->format, PIPE_SURFACE));
init_renderbuffer_bits(strb, pt->format);
#endif
/*
printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p %d x %d\n",
@ -424,7 +443,10 @@ st_finish_render_texture(GLcontext *ctx,
ctx->st->pipe->flush(ctx->st->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
screen->tex_surface_release( screen, &strb->surface );
if (strb->surface)
screen->tex_surface_release( screen, &strb->surface );
strb->rtt = NULL;
/*
printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface);

View File

@ -44,6 +44,9 @@ struct st_renderbuffer
struct pipe_texture *texture;
struct pipe_surface *surface; /* temporary view into texture */
enum pipe_format format; /** preferred format, or PIPE_FORMAT_NONE */
struct st_texture_object *rtt; /**< GL render to texture's texture */
int rtt_level, rtt_face, rtt_slice;
};

View File

@ -183,6 +183,8 @@ st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
struct gl_pixelstore_attrib clippedPacking = *pack;
struct pipe_surface *surf;
assert(ctx->ReadBuffer->Width > 0);
/* XXX convolution not done yet */
assert((transferOps & IMAGE_CONVOLUTION_BIT) == 0);

View File

@ -1496,6 +1496,7 @@ st_finalize_texture(GLcontext *ctx,
stObj->pt->cpp != cpp ||
stObj->pt->compressed != firstImage->base.IsCompressed) {
pipe_texture_release(&stObj->pt);
ctx->st->dirty.st |= ST_NEW_FRAMEBUFFER;
}
}

View File

@ -53,6 +53,7 @@ struct bitmap_cache;
#define ST_NEW_MESA 0x1 /* Mesa state has changed */
#define ST_NEW_FRAGMENT_PROGRAM 0x2
#define ST_NEW_VERTEX_PROGRAM 0x4
#define ST_NEW_FRAMEBUFFER 0x8
struct st_state_flags {
@ -121,6 +122,8 @@ struct st_context
struct st_state_flags dirty;
GLboolean missing_textures;
GLfloat polygon_offset_scale; /* ?? */
/** Mapping from VERT_RESULT_x to post-transformed vertex slot */

View File

@ -315,6 +315,22 @@ st_texture_image_copy(struct pipe_context *pipe,
assert(src->width[srcLevel] == width);
assert(src->height[srcLevel] == height);
#if 0
{
src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i,
PIPE_BUFFER_USAGE_CPU_READ);
ubyte *map = screen->surface_map(screen, src_surface, PIPE_BUFFER_USAGE_CPU_READ);
map += src_surface->width * src_surface->height * 4 / 2;
printf("%s center pixel: %d %d %d %d (pt %p[%d] -> %p[%d])\n",
__FUNCTION__,
map[0], map[1], map[2], map[3],
src, srcLevel, dst, dstLevel);
screen->surface_unmap(screen, src_surface);
pipe_surface_reference(&src_surface, NULL);
}
#endif
dst_surface = screen->get_tex_surface(screen, dst, face, dstLevel, i,
PIPE_BUFFER_USAGE_GPU_WRITE);