X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_cb_fbo.c;h=7eef5c6599430aa12256eb631d8dab80fea4177c;hb=dd6aafcf72e79d7caacd4406528da9b2003915da;hp=65ce12ccd4f8081aabbf3462073a2c29564d2d35;hpb=b605f4ff11c894500f2d0273c5d4653ff413448d;p=mesa.git diff --git a/src/mesa/state_tracker/st_cb_fbo.c b/src/mesa/state_tracker/st_cb_fbo.c index 65ce12ccd4f..7eef5c65994 100644 --- a/src/mesa/state_tracker/st_cb_fbo.c +++ b/src/mesa/state_tracker/st_cb_fbo.c @@ -37,6 +37,8 @@ #include "main/context.h" #include "main/fbobject.h" #include "main/framebuffer.h" +#include "main/macros.h" +#include "main/mfeatures.h" #include "main/renderbuffer.h" #include "pipe/p_context.h" @@ -44,131 +46,178 @@ #include "pipe/p_screen.h" #include "st_context.h" #include "st_cb_fbo.h" +#include "st_cb_flush.h" #include "st_cb_texture.h" #include "st_format.h" -#include "st_public.h" #include "st_texture.h" +#include "st_manager.h" -#include "util/u_rect.h" +#include "util/u_format.h" +#include "util/u_inlines.h" +#include "util/u_surface.h" -/** - * Compute the renderbuffer's Red/Green/EtcBit fields from the pipe format. - */ -static int -init_renderbuffer_bits(struct st_renderbuffer *strb, - enum pipe_format pipeFormat) +static GLboolean +st_renderbuffer_alloc_sw_storage(struct gl_context * ctx, + struct gl_renderbuffer *rb, + GLenum internalFormat, + GLuint width, GLuint height) { - struct pipe_format_info info; + struct pipe_screen *screen = st_context(ctx)->pipe->screen; + struct st_renderbuffer *strb = st_renderbuffer(rb); + enum pipe_format format; + size_t size; + + free(strb->data); + strb->data = NULL; - if (!st_get_format_info( pipeFormat, &info )) { - assert( 0 ); + if (internalFormat == GL_RGBA16_SNORM) { + /* Special case for software accum buffers. Otherwise, if the + * call to st_choose_renderbuffer_format() fails (because the + * driver doesn't support signed 16-bit/channel colors) we'd + * just return without allocating the software accum buffer. + */ + format = PIPE_FORMAT_R16G16B16A16_SNORM; + } + else { + format = st_choose_renderbuffer_format(screen, internalFormat, 0); + + /* Not setting gl_renderbuffer::Format here will cause + * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called. + */ + if (format == PIPE_FORMAT_NONE) { + return GL_TRUE; + } } - strb->Base.Format = info.mesa_format; - strb->Base.DataType = st_format_datatype(pipeFormat); + strb->Base.Format = st_pipe_format_to_mesa_format(format); - return info.size; + size = _mesa_format_image_size(strb->Base.Format, width, height, 1); + strb->data = malloc(size); + return strb->data != NULL; } + /** * gl_renderbuffer::AllocStorage() * This is called to allocate the original drawing surface, and * during window resize. */ static GLboolean -st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, +st_renderbuffer_alloc_storage(struct gl_context * ctx, + struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { - struct pipe_context *pipe = ctx->st->pipe; + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = st->pipe->screen; struct st_renderbuffer *strb = st_renderbuffer(rb); - enum pipe_format format; + enum pipe_format format = PIPE_FORMAT_NONE; + struct pipe_surface surf_tmpl; + struct pipe_resource templ; - if (strb->format != PIPE_FORMAT_NONE) - format = strb->format; - else - format = st_choose_renderbuffer_format(pipe->screen, internalFormat); - /* init renderbuffer fields */ strb->Base.Width = width; strb->Base.Height = height; - init_renderbuffer_bits(strb, format); - + strb->Base._BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); strb->defined = GL_FALSE; /* undefined contents now */ - if(strb->software) { - struct pipe_format_block block; - size_t size; - - _mesa_free(strb->data); - - assert(strb->format != PIPE_FORMAT_NONE); - pf_get_block(strb->format, &block); - - strb->stride = pf_get_stride(&block, width); - size = pf_get_2d_size(&block, strb->stride, height); - - strb->data = _mesa_malloc(size); - - return strb->data != NULL; + if (strb->software) { + return st_renderbuffer_alloc_sw_storage(ctx, rb, internalFormat, + width, height); } - else { - struct pipe_texture template; - unsigned surface_usage; - - /* Free the old surface and texture - */ - pipe_surface_reference( &strb->surface, NULL ); - pipe_texture_reference( &strb->texture, NULL ); - /* Setup new texture template. - */ - memset(&template, 0, sizeof(template)); - template.target = PIPE_TEXTURE_2D; - template.format = format; - pf_get_block(format, &template.block); - template.width[0] = width; - template.height[0] = height; - template.depth[0] = 1; - template.last_level = 0; - template.nr_samples = rb->NumSamples; - if (pf_is_depth_stencil(format)) { - template.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL; - } - else { - template.tex_usage = (PIPE_TEXTURE_USAGE_DISPLAY_TARGET | - PIPE_TEXTURE_USAGE_RENDER_TARGET); - } + /* Free the old surface and texture + */ + pipe_surface_reference( &strb->surface, NULL ); + pipe_resource_reference( &strb->texture, NULL ); + + /* Handle multisample renderbuffers first. + * + * From ARB_framebuffer_object: + * If is zero, then RENDERBUFFER_SAMPLES is set to zero. + * Otherwise represents a request for a desired minimum + * number of samples. Since different implementations may support + * different sample counts for multisampled rendering, the actual + * number of samples allocated for the renderbuffer image is + * implementation dependent. However, the resulting value for + * RENDERBUFFER_SAMPLES is guaranteed to be greater than or equal + * to and no more than the next larger sample count supported + * by the implementation. + * + * So let's find the supported number of samples closest to NumSamples. + * (NumSamples == 1) is treated the same as (NumSamples == 0). + */ + if (rb->NumSamples > 1) { + unsigned i; - /* Probably need dedicated flags for surface usage too: - */ - surface_usage = (PIPE_BUFFER_USAGE_GPU_READ | - PIPE_BUFFER_USAGE_GPU_WRITE); -#if 0 - PIPE_BUFFER_USAGE_CPU_READ | - PIPE_BUFFER_USAGE_CPU_WRITE); -#endif + for (i = rb->NumSamples; i <= ctx->Const.MaxSamples; i++) { + format = st_choose_renderbuffer_format(screen, internalFormat, i); - strb->texture = pipe->screen->texture_create( pipe->screen, - &template ); - - if (!strb->texture) - return FALSE; - - strb->surface = pipe->screen->get_tex_surface( pipe->screen, - strb->texture, - 0, 0, 0, - surface_usage ); - if (strb->surface) { - assert(strb->surface->texture); - assert(strb->surface->format); - assert(strb->surface->width == width); - assert(strb->surface->height == height); + if (format != PIPE_FORMAT_NONE) { + rb->NumSamples = i; + break; + } } + } else { + format = st_choose_renderbuffer_format(screen, internalFormat, 0); + } + + /* Not setting gl_renderbuffer::Format here will cause + * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called. + */ + if (format == PIPE_FORMAT_NONE) { + return GL_TRUE; + } + + strb->Base.Format = st_pipe_format_to_mesa_format(format); + + if (width == 0 || height == 0) { + /* if size is zero, nothing to allocate */ + return GL_TRUE; + } - return strb->surface != NULL; + /* Setup new texture template. + */ + memset(&templ, 0, sizeof(templ)); + templ.target = st->internal_target; + templ.format = format; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + templ.array_size = 1; + templ.nr_samples = rb->NumSamples; + if (util_format_is_depth_or_stencil(format)) { + templ.bind = PIPE_BIND_DEPTH_STENCIL; + } + else if (strb->Base.Name != 0) { + /* this is a user-created renderbuffer */ + templ.bind = PIPE_BIND_RENDER_TARGET; + } + else { + /* this is a window-system buffer */ + templ.bind = (PIPE_BIND_DISPLAY_TARGET | + PIPE_BIND_RENDER_TARGET); } + + strb->texture = screen->resource_create(screen, &templ); + + if (!strb->texture) + return FALSE; + + u_surface_default_template(&surf_tmpl, strb->texture, templ.bind); + strb->surface = pipe->create_surface(pipe, + strb->texture, + &surf_tmpl); + if (strb->surface) { + assert(strb->surface->texture); + assert(strb->surface->format); + assert(strb->surface->width == width); + assert(strb->surface->height == height); + } + + return strb->surface != NULL; } @@ -181,26 +230,9 @@ st_renderbuffer_delete(struct gl_renderbuffer *rb) struct st_renderbuffer *strb = st_renderbuffer(rb); ASSERT(strb); pipe_surface_reference(&strb->surface, NULL); - pipe_texture_reference(&strb->texture, NULL); - _mesa_free(strb->data); - _mesa_free(strb); -} - - -/** - * gl_renderbuffer::GetPointer() - */ -static void * -null_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb, - GLint x, GLint y) -{ - /* By returning NULL we force all software rendering to go through - * the span routines. - */ -#if 0 - assert(0); /* Should never get called with softpipe */ -#endif - return NULL; + pipe_resource_reference(&strb->texture, NULL); + free(strb->data); + free(strb); } @@ -208,7 +240,7 @@ null_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb, * Called via ctx->Driver.NewFramebuffer() */ static struct gl_framebuffer * -st_new_framebuffer(GLcontext *ctx, GLuint name) +st_new_framebuffer(struct gl_context *ctx, GLuint name) { /* XXX not sure we need to subclass gl_framebuffer for pipe */ return _mesa_new_framebuffer(ctx, name); @@ -219,15 +251,14 @@ st_new_framebuffer(GLcontext *ctx, GLuint name) * Called via ctx->Driver.NewRenderbuffer() */ static struct gl_renderbuffer * -st_new_renderbuffer(GLcontext *ctx, GLuint name) +st_new_renderbuffer(struct gl_context *ctx, GLuint name) { struct st_renderbuffer *strb = ST_CALLOC_STRUCT(st_renderbuffer); if (strb) { + assert(name != 0); _mesa_init_renderbuffer(&strb->Base, name); strb->Base.Delete = st_renderbuffer_delete; strb->Base.AllocStorage = st_renderbuffer_alloc_storage; - strb->Base.GetPointer = null_get_pointer; - strb->format = PIPE_FORMAT_NONE; return &strb->Base; } return NULL; @@ -252,19 +283,29 @@ st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw) _mesa_init_renderbuffer(&strb->Base, 0); strb->Base.ClassID = 0x4242; /* just a unique value */ strb->Base.NumSamples = samples; - strb->format = format; - init_renderbuffer_bits(strb, format); + strb->Base.Format = st_pipe_format_to_mesa_format(format); + strb->Base._BaseFormat = _mesa_get_format_base_format(strb->Base.Format); strb->software = sw; switch (format) { - case PIPE_FORMAT_A8R8G8B8_UNORM: + case PIPE_FORMAT_R8G8B8A8_UNORM: case PIPE_FORMAT_B8G8R8A8_UNORM: - case PIPE_FORMAT_X8R8G8B8_UNORM: + case PIPE_FORMAT_A8R8G8B8_UNORM: + strb->Base.InternalFormat = GL_RGBA8; + break; + case PIPE_FORMAT_R8G8B8X8_UNORM: case PIPE_FORMAT_B8G8R8X8_UNORM: - case PIPE_FORMAT_A1R5G5B5_UNORM: - case PIPE_FORMAT_A4R4G4B4_UNORM: - case PIPE_FORMAT_R5G6B5_UNORM: - strb->Base.InternalFormat = GL_RGBA; + case PIPE_FORMAT_X8R8G8B8_UNORM: + strb->Base.InternalFormat = GL_RGB8; + break; + case PIPE_FORMAT_B5G5R5A1_UNORM: + strb->Base.InternalFormat = GL_RGB5_A1; + break; + case PIPE_FORMAT_B4G4R4A4_UNORM: + strb->Base.InternalFormat = GL_RGBA4; + break; + case PIPE_FORMAT_B5G6R5_UNORM: + strb->Base.InternalFormat = GL_RGB565; break; case PIPE_FORMAT_Z16_UNORM: strb->Base.InternalFormat = GL_DEPTH_COMPONENT16; @@ -272,29 +313,48 @@ st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw) case PIPE_FORMAT_Z32_UNORM: strb->Base.InternalFormat = GL_DEPTH_COMPONENT32; break; - case PIPE_FORMAT_S8Z24_UNORM: - case PIPE_FORMAT_Z24S8_UNORM: - case PIPE_FORMAT_X8Z24_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_UINT: + case PIPE_FORMAT_S8_UINT_Z24_UNORM: case PIPE_FORMAT_Z24X8_UNORM: + case PIPE_FORMAT_X8Z24_UNORM: strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT; break; - case PIPE_FORMAT_S8_UNORM: + case PIPE_FORMAT_S8_UINT: strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT; break; case PIPE_FORMAT_R16G16B16A16_SNORM: - strb->Base.InternalFormat = GL_RGBA16; + /* accum buffer */ + strb->Base.InternalFormat = GL_RGBA16_SNORM; + break; + case PIPE_FORMAT_R8_UNORM: + strb->Base.InternalFormat = GL_R8; + break; + case PIPE_FORMAT_R8G8_UNORM: + strb->Base.InternalFormat = GL_RG8; + break; + case PIPE_FORMAT_R16_UNORM: + strb->Base.InternalFormat = GL_R16; + break; + case PIPE_FORMAT_R16G16_UNORM: + strb->Base.InternalFormat = GL_RG16; + break; + case PIPE_FORMAT_R32G32B32A32_FLOAT: + strb->Base.InternalFormat = GL_RGBA32F; + break; + case PIPE_FORMAT_R16G16B16A16_FLOAT: + strb->Base.InternalFormat = GL_RGBA16F; break; default: _mesa_problem(NULL, - "Unexpected format in st_new_renderbuffer_fb"); - _mesa_free(strb); + "Unexpected format %s in st_new_renderbuffer_fb", + util_format_name(format)); + free(strb); return NULL; } /* st-specific methods */ strb->Base.Delete = st_renderbuffer_delete; strb->Base.AllocStorage = st_renderbuffer_alloc_storage; - strb->Base.GetPointer = null_get_pointer; /* surface is allocated in st_renderbuffer_alloc_storage() */ strb->surface = NULL; @@ -303,29 +363,14 @@ st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw) } - - /** * Called via ctx->Driver.BindFramebufferEXT(). */ static void -st_bind_framebuffer(GLcontext *ctx, GLenum target, +st_bind_framebuffer(struct gl_context *ctx, GLenum target, struct gl_framebuffer *fb, struct gl_framebuffer *fbread) { - -} - -/** - * Called by ctx->Driver.FramebufferRenderbuffer - */ -static void -st_framebuffer_renderbuffer(GLcontext *ctx, - struct gl_framebuffer *fb, - GLenum attachment, - struct gl_renderbuffer *rb) -{ - /* XXX no need for derivation? */ - _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); + /* no-op */ } @@ -333,23 +378,34 @@ st_framebuffer_renderbuffer(GLcontext *ctx, * Called by ctx->Driver.RenderTexture */ static void -st_render_texture(GLcontext *ctx, +st_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { - struct pipe_screen *screen = ctx->st->pipe->screen; + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; struct st_renderbuffer *strb; struct gl_renderbuffer *rb; - struct pipe_texture *pt = st_get_texobj_texture(att->Texture); + struct pipe_resource *pt; struct st_texture_object *stObj; - const struct gl_texture_image *texImage = - att->Texture->Image[att->CubeMapFace][att->TextureLevel]; + const struct gl_texture_image *texImage; + struct pipe_surface surf_tmpl; - if (!pt) + if (!st_finalize_texture(ctx, pipe, att->Texture)) return; - /* create new renderbuffer which wraps the texture image */ - rb = st_new_renderbuffer(ctx, 0); + 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; @@ -374,29 +430,27 @@ st_render_texture(GLcontext *ctx, rb->Width = texImage->Width2; rb->Height = texImage->Height2; rb->_BaseFormat = texImage->_BaseFormat; - /*printf("***** render to texture level %d: %d x %d\n", att->TextureLevel, rb->Width, rb->Height);*/ + rb->InternalFormat = texImage->InternalFormat; - /*printf("***** pipe texture %d x %d\n", pt->width[0], pt->height[0]);*/ - - pipe_texture_reference( &strb->texture, pt ); + pipe_resource_reference( &strb->texture, pt ); pipe_surface_reference(&strb->surface, NULL); - /* 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); + assert(strb->rtt_level <= strb->texture->last_level); - /* - printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p %d x %d\n", - att->Texture, pt, strb->surface, rb->Width, rb->Height); - */ + /* 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. @@ -411,7 +465,7 @@ st_render_texture(GLcontext *ctx, * Called via ctx->Driver.FinishRenderTexture. */ static void -st_finish_render_texture(GLcontext *ctx, +st_finish_render_texture(struct gl_context *ctx, struct gl_renderbuffer_attachment *att) { struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer); @@ -419,53 +473,94 @@ st_finish_render_texture(GLcontext *ctx, if (!strb) return; - st_flush( ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL ); - - if (strb->surface) - pipe_surface_reference( &strb->surface, NULL ); - strb->rtt = NULL; - /* - printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface); - */ - - _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); - /* restore previous framebuffer state */ st_invalidate_state(ctx, _NEW_BUFFERS); } +/** Debug helper */ +static void +st_fbo_invalid(const char *reason) +{ + if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) { + _mesa_debug(NULL, "Invalid FBO: %s\n", reason); + } +} + + /** - * Validate a renderbuffer attachment for a particular usage. + * Validate a renderbuffer attachment for a particular set of bindings. */ - static GLboolean -st_validate_attachment(struct pipe_screen *screen, +st_validate_attachment(struct gl_context *ctx, + struct pipe_screen *screen, const struct gl_renderbuffer_attachment *att, - GLuint usage) + unsigned bindings) { - const struct st_texture_object *stObj = - st_texture_object(att->Texture); + const struct st_texture_object *stObj = st_texture_object(att->Texture); + enum pipe_format format; + gl_format texFormat; + GLboolean valid; - /** - * Only validate texture attachments for now, since + /* Only validate texture attachments for now, since * st_renderbuffer_alloc_storage makes sure that * the format is supported. */ - if (att->Type != GL_TEXTURE) return GL_TRUE; if (!stObj) return GL_FALSE; - return screen->is_format_supported(screen, stObj->pt->format, - PIPE_TEXTURE_2D, - usage, 0); + format = stObj->pt->format; + texFormat = _mesa_get_attachment_teximage_const(att)->TexFormat; + + /* If the encoding is sRGB and sRGB rendering cannot be enabled, + * check for linear format support instead. + * Later when we create a surface, we change the format to a linear one. */ + if (!ctx->Extensions.EXT_framebuffer_sRGB && + _mesa_get_format_color_encoding(texFormat) == GL_SRGB) { + const gl_format linearFormat = _mesa_get_srgb_format_linear(texFormat); + format = st_mesa_format_to_pipe_format(linearFormat); + } + + valid = screen->is_format_supported(screen, format, + PIPE_TEXTURE_2D, + stObj->pt->nr_samples, bindings); + if (!valid) { + st_fbo_invalid("Invalid format"); + } + + return valid; } + +/** + * Check if two renderbuffer attachments name a combined depth/stencil + * renderbuffer. + */ +GLboolean +st_is_depth_stencil_combined(const struct gl_renderbuffer_attachment *depth, + const struct gl_renderbuffer_attachment *stencil) +{ + assert(depth && stencil); + + if (depth->Type == stencil->Type) { + if (depth->Type == GL_RENDERBUFFER_EXT && + depth->Renderbuffer == stencil->Renderbuffer) + return GL_TRUE; + + if (depth->Type == GL_TEXTURE && + depth->Texture == stencil->Texture) + return GL_TRUE; + } + + return GL_FALSE; +} + + /** * Check that the framebuffer configuration is valid in terms of what * the driver can support. @@ -473,191 +568,237 @@ st_validate_attachment(struct pipe_screen *screen, * For Gallium we only supports combined Z+stencil, not separate buffers. */ static void -st_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb) +st_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) { - struct pipe_screen *screen = ctx->st->pipe->screen; - const struct gl_renderbuffer *depthRb = - fb->Attachment[BUFFER_DEPTH].Renderbuffer; - const struct gl_renderbuffer *stencilRb = - fb->Attachment[BUFFER_STENCIL].Renderbuffer; + struct st_context *st = st_context(ctx); + struct pipe_screen *screen = st->pipe->screen; + const struct gl_renderbuffer_attachment *depth = + &fb->Attachment[BUFFER_DEPTH]; + const struct gl_renderbuffer_attachment *stencil = + &fb->Attachment[BUFFER_STENCIL]; GLuint i; + enum pipe_format first_format = PIPE_FORMAT_NONE; + boolean mixed_formats = + screen->get_param(screen, PIPE_CAP_MIXED_COLORBUFFER_FORMATS) != 0; - if (stencilRb && depthRb && stencilRb != depthRb) { + if (depth->Type && stencil->Type && depth->Type != stencil->Type) { + st_fbo_invalid("Different Depth/Stencil buffer formats"); + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; + return; + } + if (depth->Type == GL_RENDERBUFFER_EXT && + stencil->Type == GL_RENDERBUFFER_EXT && + depth->Renderbuffer != stencil->Renderbuffer) { + st_fbo_invalid("Separate Depth/Stencil buffers"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; return; } + if (depth->Type == GL_TEXTURE && + stencil->Type == GL_TEXTURE && + depth->Texture != stencil->Texture) { + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; + st_fbo_invalid("Different Depth/Stencil textures"); + return; + } - if (!st_validate_attachment(screen, - &fb->Attachment[BUFFER_DEPTH], - PIPE_TEXTURE_USAGE_DEPTH_STENCIL)) { + if (!st_validate_attachment(ctx, + screen, + depth, + PIPE_BIND_DEPTH_STENCIL)) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; return; } - if (!st_validate_attachment(screen, - &fb->Attachment[BUFFER_STENCIL], - PIPE_TEXTURE_USAGE_DEPTH_STENCIL)) { + if (!st_validate_attachment(ctx, + screen, + stencil, + PIPE_BIND_DEPTH_STENCIL)) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; return; } for (i = 0; i < ctx->Const.MaxColorAttachments; i++) { - if (!st_validate_attachment(screen, - &fb->Attachment[BUFFER_COLOR0 + i], - PIPE_TEXTURE_USAGE_RENDER_TARGET)) { + struct gl_renderbuffer_attachment *att = + &fb->Attachment[BUFFER_COLOR0 + i]; + enum pipe_format format; + + if (!st_validate_attachment(ctx, + screen, + att, + PIPE_BIND_RENDER_TARGET)) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; return; } - } -} + if (!mixed_formats) { + /* Disallow mixed formats. */ + if (att->Type != GL_NONE) { + format = st_renderbuffer(att->Renderbuffer)->surface->format; + } else { + continue; + } -/** - * 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) { - if (st->pipe->surface_copy) { - st->pipe->surface_copy(st->pipe, - surf_front, 0, 0, /* dest */ - surf_back, 0, 0, /* src */ - fb->Width, fb->Height); - } else { - util_surface_copy(st->pipe, FALSE, - surf_front, 0, 0, - surf_back, 0, 0, - fb->Width, fb->Height); + if (first_format == PIPE_FORMAT_NONE) { + first_format = format; + } else if (format != first_format) { + fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; + st_fbo_invalid("Mixed color formats"); + return; + } } } } /** - * 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 + * Called via glDrawBuffer. */ static void -check_create_front_buffer(GLcontext *ctx, struct gl_framebuffer *fb, - gl_buffer_index frontIndex, - gl_buffer_index backIndex) +st_DrawBuffers(struct gl_context *ctx, GLsizei count, const GLenum *buffers) { - 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, FALSE); - _mesa_add_renderbuffer(fb, frontIndex, front); + struct st_context *st = st_context(ctx); + struct gl_framebuffer *fb = ctx->DrawBuffer; + GLuint i; - /* alloc texture/surface for new front buffer */ - front->AllocStorage(ctx, front, front->InternalFormat, - fb->Width, fb->Height); + (void) count; + (void) buffers; - /* initialize the front color buffer contents by copying - * the back buffer. - */ - copy_back_to_front(ctx->st, fb, frontIndex, backIndex); - } + /* add the renderbuffers on demand */ + for (i = 0; i < fb->_NumColorDrawBuffers; i++) { + gl_buffer_index idx = fb->_ColorDrawBufferIndexes[i]; + st_manager_add_color_renderbuffer(st, fb, idx); } } /** - * If front left/right color buffers are missing, create them now. + * Called via glReadBuffer. */ static void -check_create_front_buffers(GLcontext *ctx, struct gl_framebuffer *fb) +st_ReadBuffer(struct gl_context *ctx, GLenum buffer) { - /* check if we need to create the front left buffer now */ - check_create_front_buffer(ctx, fb, BUFFER_FRONT_LEFT, BUFFER_BACK_LEFT); + struct st_context *st = st_context(ctx); + struct gl_framebuffer *fb = ctx->ReadBuffer; - if (fb->Visual.stereoMode) { - check_create_front_buffer(ctx, fb, BUFFER_FRONT_RIGHT, BUFFER_BACK_RIGHT); - } + (void) buffer; - st_invalidate_state(ctx, _NEW_BUFFERS); + /* add the renderbuffer on demand */ + st_manager_add_color_renderbuffer(st, fb, fb->_ColorReadBufferIndex); } + /** - * Called via glDrawBuffer. + * Called via ctx->Driver.MapRenderbuffer. */ static void -st_DrawBuffers(GLcontext *ctx, GLsizei count, const GLenum *buffers) +st_MapRenderbuffer(struct gl_context *ctx, + struct gl_renderbuffer *rb, + GLuint x, GLuint y, GLuint w, GLuint h, + GLbitfield mode, + GLubyte **mapOut, GLint *rowStrideOut) { - (void) count; - (void) buffers; - check_create_front_buffers(ctx, ctx->DrawBuffer); + struct st_context *st = st_context(ctx); + struct st_renderbuffer *strb = st_renderbuffer(rb); + struct pipe_context *pipe = st->pipe; + const GLboolean invert = rb->Name == 0; + unsigned usage; + GLuint y2; + + if (strb->software) { + /* software-allocated renderbuffer (probably an accum buffer) */ + if (strb->data) { + GLint bpp = _mesa_get_format_bytes(strb->Base.Format); + GLint stride = _mesa_format_row_stride(strb->Base.Format, + strb->Base.Width); + *mapOut = (GLubyte *) strb->data + y * stride + x * bpp; + *rowStrideOut = stride; + } + else { + *mapOut = NULL; + *rowStrideOut = 0; + } + return; + } + + usage = 0x0; + if (mode & GL_MAP_READ_BIT) + usage |= PIPE_TRANSFER_READ; + if (mode & GL_MAP_WRITE_BIT) + usage |= PIPE_TRANSFER_WRITE; + if (mode & GL_MAP_INVALIDATE_RANGE_BIT) + usage |= PIPE_TRANSFER_DISCARD_RANGE; + + /* Note: y=0=bottom of buffer while y2=0=top of buffer. + * 'invert' will be true for window-system buffers and false for + * user-allocated renderbuffers and textures. + */ + if (invert) + y2 = strb->Base.Height - y - h; + else + y2 = y; + + strb->transfer = pipe_get_transfer(pipe, + strb->texture, + strb->rtt_level, + strb->rtt_face + strb->rtt_slice, + usage, x, y2, w, h); + if (strb->transfer) { + GLubyte *map = pipe_transfer_map(pipe, strb->transfer); + if (invert) { + *rowStrideOut = -strb->transfer->stride; + map += (h - 1) * strb->transfer->stride; + } + else { + *rowStrideOut = strb->transfer->stride; + } + *mapOut = map; + } + else { + *mapOut = NULL; + *rowStrideOut = 0; + } } /** - * Called via glReadBuffer. + * Called via ctx->Driver.UnmapRenderbuffer. */ static void -st_ReadBuffer(GLcontext *ctx, GLenum buffer) +st_UnmapRenderbuffer(struct gl_context *ctx, + struct gl_renderbuffer *rb) { - (void) buffer; - check_create_front_buffers(ctx, ctx->ReadBuffer); + struct st_context *st = st_context(ctx); + struct st_renderbuffer *strb = st_renderbuffer(rb); + struct pipe_context *pipe = st->pipe; + + if (strb->software) { + /* software-allocated renderbuffer (probably an accum buffer) */ + return; + } + + pipe_transfer_unmap(pipe, strb->transfer); + pipe->transfer_destroy(pipe, strb->transfer); + strb->transfer = NULL; } + void st_init_fbo_functions(struct dd_function_table *functions) { +#if FEATURE_EXT_framebuffer_object functions->NewFramebuffer = st_new_framebuffer; functions->NewRenderbuffer = st_new_renderbuffer; functions->BindFramebuffer = st_bind_framebuffer; - functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer; + functions->FramebufferRenderbuffer = _mesa_framebuffer_renderbuffer; functions->RenderTexture = st_render_texture; functions->FinishRenderTexture = st_finish_render_texture; functions->ValidateFramebuffer = st_validate_framebuffer; - /* no longer needed by core Mesa, drivers handle resizes... - functions->ResizeBuffers = st_resize_buffers; - */ +#endif functions->DrawBuffers = st_DrawBuffers; functions->ReadBuffer = st_ReadBuffer; + + functions->MapRenderbuffer = st_MapRenderbuffer; + functions->UnmapRenderbuffer = st_UnmapRenderbuffer; } + +