gallium: fix some render to texture bugs
authorBrian Paul <brian.paul@tungstengraphics.com>
Wed, 7 May 2008 22:44:33 +0000 (16:44 -0600)
committerBrian Paul <brian.paul@tungstengraphics.com>
Wed, 7 May 2008 22:44:33 +0000 (16:44 -0600)
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...

src/mesa/state_tracker/st_atom.c
src/mesa/state_tracker/st_atom.h
src/mesa/state_tracker/st_atom_framebuffer.c
src/mesa/state_tracker/st_atom_shader.c
src/mesa/state_tracker/st_atom_texture.c
src/mesa/state_tracker/st_cb_fbo.c
src/mesa/state_tracker/st_cb_fbo.h
src/mesa/state_tracker/st_cb_readpixels.c
src/mesa/state_tracker/st_cb_texture.c
src/mesa/state_tracker/st_context.h
src/mesa/state_tracker/st_texture.c

index 18063adc79c16056d1d30620d4ede76b802a8928..ecfd1179189d86fc3abdaae6402858efb059882a 100644 (file)
  */
 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
index c6c6eba812139e301d765171a8e3ff0483636e43..c7cffd85c8a89d03b2c729622108e29bce2077a8 100644 (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;
index 0a6974d8a7fe5f9bb54105bf8db073ea3424b284..c9a30e44b2401056f129cd15db2b3c4bde57378d 100644 (file)
 #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 */
 };
index 7745591afbafb05e614c861103c146552ad7e588..8839ab380f8aeea2cea4dfa239f811e3465eb683 100644 (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;
 }
index 767654f3d0ff9a940ad5c32253fc058eaf3bde96..1ec671ed48fc9b436e356604f85751dad508bb7f 100644 (file)
 #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 */
+};
index 747d4905e6b9a3d8460d754a2da1183f9c63e2ff..2368c31f4b46060580b1ccd2cfd12555a549d50c 100644 (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);
index f9cec91314112f6f220f8849d854b34f1a9a1a54..87b0734a0c8595dcbe1c8b13e4ec6bab0a8c850e 100644 (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;
 };
 
 
index 0b2b9d544d79ac458e3f7ce4240e57ccde155bdd..3615fafc0aee27977cca20813fa7edebf2772ee7 100644 (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);
 
index 3206215b2ef743f76213ff661e5d70f28f736414..3468b5f2a131789fd4ea13b08aab5ad184e20f2e 100644 (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;
       }
    }
 
index 1ca779d0a98e5eb2d2a4db787d4a046a84b18547..69be4ebdd07b42c0f26270b25cdaba617f0340aa 100644 (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 */
index 2b3742d4e5b542e6261007a7bdd63e665c71aa25..d0f56c9717cadb088b150a2252657d52ca754cee 100644 (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);