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:
parent
8f76459f62
commit
1a82d9648b
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue