diff options
Diffstat (limited to 'src/mesa/state_tracker/st_cb_fbo.c')
-rw-r--r-- | src/mesa/state_tracker/st_cb_fbo.c | 145 |
1 files changed, 144 insertions, 1 deletions
diff --git a/src/mesa/state_tracker/st_cb_fbo.c b/src/mesa/state_tracker/st_cb_fbo.c index 1590f275e2a..c249f3b3578 100644 --- a/src/mesa/state_tracker/st_cb_fbo.c +++ b/src/mesa/state_tracker/st_cb_fbo.c @@ -125,6 +125,8 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, strb->Base.Height = height; init_renderbuffer_bits(strb, template.format); + strb->defined = GL_FALSE; /* undefined contents now */ + /* Probably need dedicated flags for surface usage too: */ surface_usage = (PIPE_BUFFER_USAGE_GPU_READ | @@ -343,6 +345,7 @@ st_render_texture(GLcontext *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { + struct pipe_screen *screen = ctx->st->pipe->screen; struct st_renderbuffer *strb; struct gl_renderbuffer *rb; struct pipe_texture *pt = st_get_texobj_texture(att->Texture); @@ -365,6 +368,8 @@ st_render_texture(GLcontext *ctx, rb->AllocStorage = NULL; /* should not get called */ strb = st_renderbuffer(rb); + assert(strb->Base.RefCount > 0); + /* get the texture for the texture object */ stObj = st_texture_object(att->Texture); @@ -384,7 +389,14 @@ st_render_texture(GLcontext *ctx, pipe_surface_reference(&strb->surface, NULL); - /* the new surface will be created during framebuffer validation */ + /* new surface for rendering into the texture */ + strb->surface = screen->get_tex_surface(screen, + strb->texture, + strb->rtt_face, + strb->rtt_level, + strb->rtt_slice, + PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE); init_renderbuffer_bits(strb, pt->format); @@ -452,6 +464,134 @@ st_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb) } +/** + * Copy back color buffer to front color buffer. + */ +static void +copy_back_to_front(struct st_context *st, + struct gl_framebuffer *fb, + gl_buffer_index frontIndex, + gl_buffer_index backIndex) + +{ + struct st_framebuffer *stfb = (struct st_framebuffer *) fb; + struct pipe_surface *surf_front, *surf_back; + + (void) st_get_framebuffer_surface(stfb, frontIndex, &surf_front); + (void) st_get_framebuffer_surface(stfb, backIndex, &surf_back); + + if (surf_front && surf_back) { + st->pipe->surface_copy(st->pipe, + surf_front, 0, 0, /* dest */ + surf_back, 0, 0, /* src */ + fb->Width, fb->Height); + } +} + + +/** + * Check if we're drawing into, or read from, a front color buffer. If the + * front buffer is missing, create it now. + * + * The back color buffer must exist since we'll use its format/samples info + * for creating the front buffer. + * + * \param frontIndex either BUFFER_FRONT_LEFT or BUFFER_FRONT_RIGHT + * \param backIndex either BUFFER_BACK_LEFT or BUFFER_BACK_RIGHT + */ +static void +check_create_front_buffer(GLcontext *ctx, struct gl_framebuffer *fb, + gl_buffer_index frontIndex, + gl_buffer_index backIndex) +{ + if (fb->Attachment[frontIndex].Renderbuffer == NULL) { + GLboolean create = GL_FALSE; + + /* check if drawing to or reading from front buffer */ + if (fb->_ColorReadBufferIndex == frontIndex) { + create = GL_TRUE; + } + else { + GLuint b; + for (b = 0; b < fb->_NumColorDrawBuffers; b++) { + if (fb->_ColorDrawBufferIndexes[b] == frontIndex) { + create = GL_TRUE; + break; + } + } + } + + if (create) { + struct st_renderbuffer *back; + struct gl_renderbuffer *front; + enum pipe_format colorFormat; + uint samples; + + if (0) + _mesa_debug(ctx, "Allocate new front buffer\n"); + + /* get back renderbuffer info */ + back = st_renderbuffer(fb->Attachment[backIndex].Renderbuffer); + colorFormat = back->format; + samples = back->Base.NumSamples; + + /* create front renderbuffer */ + front = st_new_renderbuffer_fb(colorFormat, samples); + _mesa_add_renderbuffer(fb, frontIndex, front); + + /* alloc texture/surface for new front buffer */ + front->AllocStorage(ctx, front, front->InternalFormat, + fb->Width, fb->Height); + + /* initialize the front color buffer contents by copying + * the back buffer. + */ + copy_back_to_front(ctx->st, fb, frontIndex, backIndex); + } + } +} + + +/** + * If front left/right color buffers are missing, create them now. + */ +static void +check_create_front_buffers(GLcontext *ctx, struct gl_framebuffer *fb) +{ + /* check if we need to create the front left buffer now */ + check_create_front_buffer(ctx, fb, BUFFER_FRONT_LEFT, BUFFER_BACK_LEFT); + + if (fb->Visual.stereoMode) { + check_create_front_buffer(ctx, fb, BUFFER_FRONT_RIGHT, BUFFER_BACK_RIGHT); + } + + st_invalidate_state(ctx, _NEW_BUFFERS); +} + + +/** + * Called via glDrawBuffer. + */ +static void +st_DrawBuffers(GLcontext *ctx, GLsizei count, const GLenum *buffers) +{ + (void) count; + (void) buffers; + check_create_front_buffers(ctx, ctx->DrawBuffer); +} + + +/** + * Called via glReadBuffer. + */ +static void +st_ReadBuffer(GLcontext *ctx, GLenum buffer) +{ + (void) buffer; + check_create_front_buffers(ctx, ctx->ReadBuffer); +} + + void st_init_fbo_functions(struct dd_function_table *functions) { functions->NewFramebuffer = st_new_framebuffer; @@ -464,4 +604,7 @@ void st_init_fbo_functions(struct dd_function_table *functions) /* no longer needed by core Mesa, drivers handle resizes... functions->ResizeBuffers = st_resize_buffers; */ + + functions->DrawBuffers = st_DrawBuffers; + functions->ReadBuffer = st_ReadBuffer; } |