/** * gl_renderbuffer::Delete() */ static void st_renderbuffer_delete(struct gl_context *ctx, struct gl_renderbuffer *rb) { struct st_renderbuffer *strb = st_renderbuffer(rb); if (ctx) { struct st_context *st = st_context(ctx); pipe_surface_release(st->pipe, &strb->surface); } pipe_resource_reference(&strb->texture, NULL); free(strb->data); _mesa_delete_renderbuffer(ctx, rb); }
/** * Called by ctx->Driver.RenderTexture */ static void st_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct gl_renderbuffer *rb = att->Renderbuffer; struct st_renderbuffer *strb = st_renderbuffer(rb); struct pipe_resource *pt; if (!st_finalize_texture(ctx, pipe, att->Texture)) return; pt = st_get_texobj_resource(att->Texture); assert(pt); /* point renderbuffer at texobject */ strb->is_rtt = TRUE; strb->rtt_face = att->CubeMapFace; strb->rtt_slice = att->Zoffset; strb->rtt_layered = att->Layered; pipe_resource_reference(&strb->texture, pt); pipe_surface_release(pipe, &strb->surface); st_update_renderbuffer_surface(st, strb); strb->Base.Format = st_pipe_format_to_mesa_format(pt->format); /* Invalidate buffer state so that the pipe's framebuffer state * gets updated. * That's where the new renderbuffer (which we just created) gets * passed to the pipe as a (color/depth) render target. */ st_invalidate_state(ctx, _NEW_BUFFERS); /* Need to trigger a call to update_framebuffer() since we just * attached a new renderbuffer. */ ctx->NewState |= _NEW_BUFFERS; }
/** * Called by ctx->Driver.RenderTexture */ static void st_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct gl_renderbuffer *rb = att->Renderbuffer; struct st_renderbuffer *strb = st_renderbuffer(rb); struct pipe_resource *pt; struct st_texture_object *stObj; const struct gl_texture_image *texImage; struct pipe_surface surf_tmpl; if (!st_finalize_texture(ctx, pipe, att->Texture)) return; pt = st_get_texobj_resource(att->Texture); assert(pt); /* get pointer to texture image we're rendeing to */ texImage = _mesa_get_attachment_teximage(att); /* 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; pipe_resource_reference( &strb->texture, pt ); pipe_surface_release(pipe, &strb->surface); assert(strb->rtt_level <= strb->texture->last_level); /* new surface for rendering into the texture */ memset(&surf_tmpl, 0, sizeof(surf_tmpl)); surf_tmpl.format = ctx->Color.sRGBEnabled ? strb->texture->format : util_format_linear(strb->texture->format); surf_tmpl.u.tex.level = strb->rtt_level; surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice; surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice; strb->surface = pipe->create_surface(pipe, strb->texture, &surf_tmpl); strb->Base.Format = st_pipe_format_to_mesa_format(pt->format); /* Invalidate buffer state so that the pipe's framebuffer state * gets updated. * That's where the new renderbuffer (which we just created) gets * passed to the pipe as a (color/depth) render target. */ st_invalidate_state(ctx, _NEW_BUFFERS); /* Need to trigger a call to update_framebuffer() since we just * attached a new renderbuffer. */ ctx->NewState |= _NEW_BUFFERS; }
/** * Called by ctx->Driver.RenderTexture */ static void st_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_renderbuffer *strb; struct gl_renderbuffer *rb; struct pipe_resource *pt; struct st_texture_object *stObj; const struct gl_texture_image *texImage; struct pipe_surface surf_tmpl; if (!st_finalize_texture(ctx, pipe, att->Texture)) return; pt = st_get_texobj_resource(att->Texture); assert(pt); /* get pointer to texture image we're rendeing to */ texImage = _mesa_get_attachment_teximage(att); /* create new renderbuffer which wraps the texture image. * Use the texture's name as the renderbuffer's name so that we have * something that's non-zero (to determine vertical orientation) and * possibly helpful for debugging. */ rb = st_new_renderbuffer(ctx, att->Texture->Name); if (!rb) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); return; } _mesa_reference_renderbuffer(&att->Renderbuffer, rb); assert(rb->RefCount == 1); 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); /* 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; rb->_BaseFormat = texImage->_BaseFormat; rb->InternalFormat = texImage->InternalFormat; pipe_resource_reference( &strb->texture, pt ); pipe_surface_release(pipe, &strb->surface); assert(strb->rtt_level <= strb->texture->last_level); /* new surface for rendering into the texture */ memset(&surf_tmpl, 0, sizeof(surf_tmpl)); surf_tmpl.format = ctx->Color.sRGBEnabled ? strb->texture->format : util_format_linear(strb->texture->format); surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; surf_tmpl.u.tex.level = strb->rtt_level; surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice; surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice; strb->surface = pipe->create_surface(pipe, strb->texture, &surf_tmpl); strb->Base.Format = st_pipe_format_to_mesa_format(pt->format); /* Invalidate buffer state so that the pipe's framebuffer state * gets updated. * That's where the new renderbuffer (which we just created) gets * passed to the pipe as a (color/depth) render target. */ st_invalidate_state(ctx, _NEW_BUFFERS); /* Need to trigger a call to update_framebuffer() since we just * attached a new renderbuffer. */ ctx->NewState |= _NEW_BUFFERS; }
/** * Create or update the pipe_surface of a FBO renderbuffer. * This is usually called after st_finalize_texture. */ void st_update_renderbuffer_surface(struct st_context *st, struct st_renderbuffer *strb) { struct pipe_context *pipe = st->pipe; struct pipe_resource *resource = strb->texture; struct st_texture_object *stTexObj = NULL; unsigned rtt_width = strb->Base.Width; unsigned rtt_height = strb->Base.Height; unsigned rtt_depth = strb->Base.Depth; /* * For winsys fbo, it is possible that the renderbuffer is sRGB-capable but * the format of strb->texture is linear (because we have no control over * the format). Check strb->Base.Format instead of strb->texture->format * to determine if the rb is sRGB-capable. */ boolean enable_srgb = (st->ctx->Color.sRGBEnabled && _mesa_get_format_color_encoding(strb->Base.Format) == GL_SRGB); enum pipe_format format = resource->format; if (strb->is_rtt) { stTexObj = st_texture_object(strb->Base.TexImage->TexObject); if (stTexObj->surface_based) format = stTexObj->surface_format; } format = (enable_srgb) ? util_format_srgb(format) : util_format_linear(format); unsigned first_layer, last_layer, level; if (resource->target == PIPE_TEXTURE_1D_ARRAY) { rtt_depth = rtt_height; rtt_height = 1; } /* find matching mipmap level size */ for (level = 0; level <= resource->last_level; level++) { if (u_minify(resource->width0, level) == rtt_width && u_minify(resource->height0, level) == rtt_height && (resource->target != PIPE_TEXTURE_3D || u_minify(resource->depth0, level) == rtt_depth)) { break; } } assert(level <= resource->last_level); /* determine the layer bounds */ if (strb->rtt_layered) { first_layer = 0; last_layer = util_max_layer(strb->texture, level); } else { first_layer = last_layer = strb->rtt_face + strb->rtt_slice; } /* Adjust for texture views */ if (strb->is_rtt && resource->array_size > 1 && stTexObj->base.Immutable) { struct gl_texture_object *tex = &stTexObj->base; first_layer += tex->MinLayer; if (!strb->rtt_layered) last_layer += tex->MinLayer; else last_layer = MIN2(first_layer + tex->NumLayers - 1, last_layer); } if (!strb->surface || strb->surface->texture->nr_samples != strb->Base.NumSamples || strb->surface->format != format || strb->surface->texture != resource || strb->surface->width != rtt_width || strb->surface->height != rtt_height || strb->surface->u.tex.level != level || strb->surface->u.tex.first_layer != first_layer || strb->surface->u.tex.last_layer != last_layer) { /* create a new pipe_surface */ struct pipe_surface surf_tmpl; memset(&surf_tmpl, 0, sizeof(surf_tmpl)); surf_tmpl.format = format; surf_tmpl.u.tex.level = level; surf_tmpl.u.tex.first_layer = first_layer; surf_tmpl.u.tex.last_layer = last_layer; pipe_surface_release(pipe, &strb->surface); strb->surface = pipe->create_surface(pipe, resource, &surf_tmpl); } }