static GLboolean intel_alloc_private_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *irb = intel_renderbuffer(rb); assert(rb->Format != MESA_FORMAT_NONE); rb->Width = width; rb->Height = height; rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); intel_miptree_release(&irb->mt); DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__, _mesa_lookup_enum_by_nr(internalFormat), _mesa_get_format_name(rb->Format), width, height); if (width == 0 || height == 0) return true; irb->mt = intel_miptree_create_for_renderbuffer(intel, rb->Format, width, height); if (!irb->mt) return false; return true; }
/** * Called via glRenderbufferStorageEXT() to set the format and allocate * storage for a user-created renderbuffer. */ GLboolean intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *irb = intel_renderbuffer(rb); ASSERT(rb->Name != 0); switch (internalFormat) { default: /* Use the same format-choice logic as for textures. * Renderbuffers aren't any different from textures for us, * except they're less useful because you can't texture with * them. */ rb->Format = intel->ctx.Driver.ChooseTextureFormat(ctx, internalFormat, GL_NONE, GL_NONE); break; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: /* These aren't actual texture formats, so force them here. */ if (intel->has_separate_stencil) { rb->Format = MESA_FORMAT_S8; } else { assert(!intel->must_use_separate_stencil); rb->Format = MESA_FORMAT_S8_Z24; } break; } rb->Width = width; rb->Height = height; rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); intel_miptree_release(&irb->mt); DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__, _mesa_lookup_enum_by_nr(internalFormat), _mesa_get_format_name(rb->Format), width, height); irb->mt = intel_miptree_create_for_renderbuffer(intel, rb->Format, width, height); if (!irb->mt) return false; if (intel->vtbl.is_hiz_depth_format(intel, rb->Format)) { bool ok = intel_miptree_alloc_hiz(intel, irb->mt); if (!ok) { intel_miptree_release(&irb->mt); return false; } } return true; }
/** * Called via glRenderbufferStorageEXT() to set the format and allocate * storage for a user-created renderbuffer. */ static GLboolean intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct brw_context *brw = brw_context(ctx); struct intel_screen *screen = brw->intelScreen; struct intel_renderbuffer *irb = intel_renderbuffer(rb); rb->NumSamples = intel_quantize_num_samples(screen, rb->NumSamples); switch (internalFormat) { default: /* Use the same format-choice logic as for textures. * Renderbuffers aren't any different from textures for us, * except they're less useful because you can't texture with * them. */ rb->Format = ctx->Driver.ChooseTextureFormat(ctx, GL_TEXTURE_2D, internalFormat, GL_NONE, GL_NONE); break; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: /* These aren't actual texture formats, so force them here. */ if (brw->has_separate_stencil) { rb->Format = MESA_FORMAT_S8; } else { assert(!brw->must_use_separate_stencil); rb->Format = MESA_FORMAT_S8_Z24; } break; } rb->Width = width; rb->Height = height; rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); intel_miptree_release(&irb->mt); DBG("%s: %s: %s (%dx%d)\n", __FUNCTION__, _mesa_lookup_enum_by_nr(internalFormat), _mesa_get_format_name(rb->Format), width, height); if (width == 0 || height == 0) return true; irb->mt = intel_miptree_create_for_renderbuffer(brw, rb->Format, width, height, rb->NumSamples); if (!irb->mt) return false; return true; }
/** * If the format of the src renderbuffer and the format of the dest * texture are compatible (in terms of blitting), return a TGSI writemask * to be used during the blit. * If the src/dest are incompatible, return 0. */ static unsigned compatible_src_dst_formats(struct gl_context *ctx, const struct gl_renderbuffer *src, const struct gl_texture_image *dst) { /* Get logical base formats for the src and dest. * That is, use the user-requested formats and not the actual, device- * chosen formats. * For example, the user may have requested an A8 texture but the * driver may actually be using an RGBA texture format. When we * copy/blit to that texture, we only want to copy the Alpha channel * and not the RGB channels. * * Similarly, when the src FBO was created an RGB format may have been * requested but the driver actually chose an RGBA format. In that case, * we don't want to copy the undefined Alpha channel to the dest texture * (it should be 1.0). */ const GLenum srcFormat = _mesa_base_fbo_format(ctx, src->InternalFormat); const GLenum dstFormat = _mesa_base_tex_format(ctx, dst->InternalFormat); /** * XXX when we have red-only and red/green renderbuffers we'll need * to add more cases here (or implement a general-purpose routine that * queries the existance of the R,G,B,A channels in the src and dest). */ if (srcFormat == dstFormat) { /* This is the same as matching_base_formats, which should * always pass, as it did previously. */ return TGSI_WRITEMASK_XYZW; } else if (srcFormat == GL_RGB && dstFormat == GL_RGBA) { /* Make sure that A in the dest is 1. The actual src format * may be RGBA and have undefined A values. */ return TGSI_WRITEMASK_XYZ; } else if (srcFormat == GL_RGBA && dstFormat == GL_RGB) { /* Make sure that A in the dest is 1. The actual dst format * may be RGBA and will need A=1 to provide proper alpha values * when sampled later. */ return TGSI_WRITEMASK_XYZ; } else { if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s failed for src %s, dst %s\n", __FUNCTION__, _mesa_lookup_enum_by_nr(srcFormat), _mesa_lookup_enum_by_nr(dstFormat)); /* Otherwise fail. */ return 0; } }
/** * gl_renderbuffer::AllocStorage() * This is called to allocate the original drawing surface, and * during window resize. */ static GLboolean st_renderbuffer_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { 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; struct pipe_surface surf_tmpl; format = st_choose_renderbuffer_format(screen, internalFormat, rb->NumSamples); if (format == PIPE_FORMAT_NONE) { return FALSE; } /* init renderbuffer fields */ strb->Base.Width = width; strb->Base.Height = height; strb->Base.Format = st_pipe_format_to_mesa_format(format); strb->Base._BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); strb->Base.DataType = st_format_datatype(format); strb->format = format; strb->defined = GL_FALSE; /* undefined contents now */ if (strb->software) { size_t size; free(strb->data); assert(strb->format != PIPE_FORMAT_NONE); strb->stride = util_format_get_stride(strb->format, width); size = util_format_get_2d_size(strb->format, strb->stride, height); strb->data = malloc(size); return strb->data != NULL; } else { struct pipe_resource template; /* Free the old surface and texture */ pipe_surface_reference( &strb->surface, NULL ); pipe_resource_reference( &strb->texture, NULL ); pipe_sampler_view_reference(&strb->sampler_view, NULL); /* Setup new texture template. */ memset(&template, 0, sizeof(template));
static GLboolean intel_update_wrapper(GLcontext *ctx, struct intel_renderbuffer *irb, struct gl_texture_image *texImage) { gl_format texFormat; if (texImage->TexFormat == MESA_FORMAT_ARGB8888) { irb->Base.DataType = GL_UNSIGNED_BYTE; DBG("Render to RGBA8 texture OK\n"); } else if (texImage->TexFormat == MESA_FORMAT_XRGB8888) { irb->Base.DataType = GL_UNSIGNED_BYTE; DBG("Render to XGBA8 texture OK\n"); } else if (texImage->TexFormat == MESA_FORMAT_RGB565) { irb->Base.DataType = GL_UNSIGNED_BYTE; DBG("Render to RGB5 texture OK\n"); } else if (texImage->TexFormat == MESA_FORMAT_ARGB1555) { irb->Base.DataType = GL_UNSIGNED_BYTE; DBG("Render to ARGB1555 texture OK\n"); } else if (texImage->TexFormat == MESA_FORMAT_ARGB4444) { irb->Base.DataType = GL_UNSIGNED_BYTE; DBG("Render to ARGB4444 texture OK\n"); } else if (texImage->TexFormat == MESA_FORMAT_Z16) { irb->Base.DataType = GL_UNSIGNED_SHORT; DBG("Render to DEPTH16 texture OK\n"); } else if (texImage->TexFormat == MESA_FORMAT_S8_Z24) { irb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT; DBG("Render to DEPTH_STENCIL texture OK\n"); } else { DBG("Render to texture BAD FORMAT %d\n", texImage->TexFormat); return GL_FALSE; } irb->Base.Format = texImage->TexFormat; texFormat = texImage->TexFormat; irb->Base.InternalFormat = texImage->InternalFormat; irb->Base._BaseFormat = _mesa_base_fbo_format(ctx, irb->Base.InternalFormat); irb->Base.Width = texImage->Width; irb->Base.Height = texImage->Height; irb->Base.Delete = intel_delete_renderbuffer; irb->Base.AllocStorage = intel_nop_alloc_storage; return GL_TRUE; }
static void intel_image_target_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, void *image_handle) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *irb; __DRIscreen *screen; __DRIimage *image; screen = intel->intelScreen->driScrnPriv; image = screen->dri2.image->lookupEGLImage(screen, image_handle, screen->loaderPrivate); if (image == NULL) return; /* __DRIimage is opaque to the core so it has to be checked here */ switch (image->format) { case MESA_FORMAT_R8G8B8A8_UNORM: _mesa_error(&intel->ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(unsupported image format"); return; break; default: break; } irb = intel_renderbuffer(rb); intel_miptree_release(&irb->mt); irb->mt = intel_miptree_create_for_bo(intel, image->region->bo, image->format, image->offset, image->region->width, image->region->height, image->region->pitch, image->region->tiling); if (!irb->mt) return; rb->InternalFormat = image->internal_format; rb->Width = image->region->width; rb->Height = image->region->height; rb->Format = image->format; rb->_BaseFormat = _mesa_base_fbo_format(&intel->ctx, image->internal_format); rb->NeedsFinishRenderTexture = true; }
static GLboolean radeon_update_wrapper(struct gl_context *ctx, struct radeon_renderbuffer *rrb, struct gl_texture_image *texImage) { radeon_print(RADEON_TEXTURE, RADEON_TRACE, "%s(%p, rrb %p, texImage %p, texFormat %s) \n", __func__, ctx, rrb, texImage, _mesa_get_format_name(texImage->TexFormat)); switch (texImage->TexFormat) { case MESA_FORMAT_RGBA8888: case MESA_FORMAT_RGBA8888_REV: case MESA_FORMAT_ARGB8888: case MESA_FORMAT_ARGB8888_REV: case MESA_FORMAT_XRGB8888: case MESA_FORMAT_XRGB8888_REV: case MESA_FORMAT_RGB565: case MESA_FORMAT_RGB565_REV: case MESA_FORMAT_RGBA5551: case MESA_FORMAT_ARGB1555: case MESA_FORMAT_ARGB1555_REV: case MESA_FORMAT_ARGB4444: case MESA_FORMAT_ARGB4444_REV: rrb->base.DataType = GL_UNSIGNED_BYTE; break; case MESA_FORMAT_Z16: rrb->base.DataType = GL_UNSIGNED_SHORT; break; case MESA_FORMAT_X8_Z24: rrb->base.DataType = GL_UNSIGNED_INT; break; case MESA_FORMAT_S8_Z24: rrb->base.DataType = GL_UNSIGNED_INT_24_8_EXT; break; } rrb->cpp = _mesa_get_format_bytes(texImage->TexFormat); rrb->pitch = texImage->Width * rrb->cpp; rrb->base.Format = texImage->TexFormat; rrb->base.InternalFormat = texImage->InternalFormat; rrb->base._BaseFormat = _mesa_base_fbo_format(ctx, rrb->base.InternalFormat); rrb->base.Width = texImage->Width; rrb->base.Height = texImage->Height; rrb->base.Delete = radeon_delete_renderbuffer; rrb->base.AllocStorage = radeon_nop_alloc_storage; return GL_TRUE; }
static bool _is_renderable(struct gl_context *ctx, GLenum internalformat) { /* Section 4.4.4 on page 212 of the GLES 3.0.4 spec says: * * "An internal format is color-renderable if it is one of the * formats from table 3.13 noted as color-renderable or if it * is unsized format RGBA or RGB." * * Therefore, we must accept GL_RGB and GL_RGBA here. */ if (internalformat != GL_RGB && internalformat != GL_RGBA && _mesa_base_fbo_format(ctx, internalformat) == 0) return false; return true; }
static void radeon_image_target_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, void *image_handle) { radeonContextPtr radeon = RADEON_CONTEXT(ctx); struct radeon_renderbuffer *rrb; __DRIscreen *screen; __DRIimage *image; screen = radeon->radeonScreen->driScreen; image = screen->dri2.image->lookupEGLImage(screen, image_handle, screen->loaderPrivate); if (image == NULL) return; rrb = radeon_renderbuffer(rb); if (ctx->Driver.Flush) ctx->Driver.Flush(ctx); /* +r6/r7 */ if (rrb->bo) radeon_bo_unref(rrb->bo); rrb->bo = image->bo; radeon_bo_ref(rrb->bo); fprintf(stderr, "image->bo: %p, name: %d, rbs: w %d -> p %d\n", image->bo, image->bo->handle, image->width, image->pitch); rrb->cpp = image->cpp; rrb->pitch = image->pitch * image->cpp; rb->Format = image->format; rb->InternalFormat = image->internal_format; rb->Width = image->width; rb->Height = image->height; rb->Format = image->format; rb->DataType = image->data_type; rb->_BaseFormat = _mesa_base_fbo_format(radeon->glCtx, image->internal_format); }
static bool _is_internalformat_supported(struct gl_context *ctx, GLenum target, GLenum internalformat) { /* From the ARB_internalformat_query2 specification: * * "- INTERNALFORMAT_SUPPORTED: If <internalformat> is an internal format * that is supported by the implementation in at least some subset of * possible operations, TRUE is written to <params>. If <internalformat> * if not a valid token for any internal format usage, FALSE is returned. * * <internalformats> that must be supported (in GL 4.2 or later) include * the following: * - "sized internal formats" from Table 3.12, 3.13, and 3.15, * - any specific "compressed internal format" from Table 3.14, * - any "image unit format" from Table 3.21. * - any generic "compressed internal format" from Table 3.14, if the * implementation accepts it for any texture specification commands, and * - unsized or base internal format, if the implementation accepts * it for texture or image specification. */ GLint buffer[1]; /* At this point an internalformat is valid if it is valid as a texture or * as a renderbuffer format. The checks are different because those methods * return different values when passing non supported internalformats */ if (_mesa_base_tex_format(ctx, internalformat) < 0 && _mesa_base_fbo_format(ctx, internalformat) == 0) return false; /* Let the driver have the final word */ ctx->Driver.QueryInternalFormat(ctx, target, internalformat, GL_INTERNALFORMAT_SUPPORTED, buffer); return (buffer[0] == GL_TRUE); }
void GLAPIENTRY _mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params) { GLint buffer[16]; GLsizei count = 0; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (!ctx->Extensions.ARB_internalformat_query) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInternalformativ"); return; } assert(ctx->Driver.QuerySamplesForFormat != NULL); /* The ARB_internalformat_query spec says: * * "If the <target> parameter to GetInternalformativ is not one of * TEXTURE_2D_MULTISAMPLE, TEXTURE_2D_MULTISAMPLE_ARRAY or RENDERBUFFER * then an INVALID_ENUM error is generated." */ switch (target) { case GL_RENDERBUFFER: break; case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: /* These enums are only valid if ARB_texture_multisample is supported */ if (_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample) break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetInternalformativ(target=%s)", _mesa_lookup_enum_by_nr(target)); return; } /* The ARB_internalformat_query spec says: * * "If the <internalformat> parameter to GetInternalformativ is not * color-, depth- or stencil-renderable, then an INVALID_ENUM error is * generated." * * Page 243 of the GLES 3.0.4 spec says this for GetInternalformativ: * * "internalformat must be color-renderable, depth-renderable or * stencilrenderable (as defined in section 4.4.4)." * * Section 4.4.4 on page 212 of the same spec says: * * "An internal format is color-renderable if it is one of the * formats from table 3.13 noted as color-renderable or if it * is unsized format RGBA or RGB." * * Therefore, we must accept GL_RGB and GL_RGBA here. */ if (internalformat != GL_RGB && internalformat != GL_RGBA && _mesa_base_fbo_format(ctx, internalformat) == 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetInternalformativ(internalformat=%s)", _mesa_lookup_enum_by_nr(internalformat)); return; } /* The ARB_internalformat_query spec says: * * "If the <bufSize> parameter to GetInternalformativ is negative, then * an INVALID_VALUE error is generated." */ if (bufSize < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetInternalformativ(target=%s)", _mesa_lookup_enum_by_nr(target)); return; } switch (pname) { case GL_SAMPLES: count = ctx->Driver.QuerySamplesForFormat(ctx, target, internalformat, buffer); break; case GL_NUM_SAMPLE_COUNTS: { if (_mesa_is_gles3(ctx) && _mesa_is_enum_format_integer(internalformat)) { /* From GL ES 3.0 specification, section 6.1.15 page 236: "Since * multisampling is not supported for signed and unsigned integer * internal formats, the value of NUM_SAMPLE_COUNTS will be zero * for such formats. */ buffer[0] = 0; count = 1; } else { size_t num_samples; /* The driver can return 0, and we should pass that along to the * application. The ARB decided that ARB_internalformat_query should * behave as ARB_internalformat_query2 in this situation. * * The ARB_internalformat_query2 spec says: * * "- NUM_SAMPLE_COUNTS: The number of sample counts that would be * returned by querying SAMPLES is returned in <params>. * * If <internalformat> is not color-renderable, * depth-renderable, or stencil-renderable (as defined in * section 4.4.4), or if <target> does not support multiple * samples (ie other than TEXTURE_2D_MULTISAMPLE, * TEXTURE_2D_MULTISAMPLE_ARRAY, or RENDERBUFFER), 0 is * returned." */ num_samples = ctx->Driver.QuerySamplesForFormat(ctx, target, internalformat, buffer); /* QuerySamplesForFormat writes some stuff to buffer, so we have to * separately over-write it with the requested value. */ buffer[0] = (GLint) num_samples; count = 1; } break; } default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetInternalformativ(pname=%s)", _mesa_lookup_enum_by_nr(pname)); return; } if (bufSize != 0 && params == NULL) { /* Emit a warning to aid application debugging, but go ahead and do the * memcpy (and probably crash) anyway. */ _mesa_warning(ctx, "glGetInternalformativ(bufSize = %d, but params = NULL)", bufSize); } /* Copy the data from the temporary buffer to the buffer supplied by the * application. Clamp the size of the copy to the size supplied by the * application. */ memcpy(params, buffer, MIN2(count, bufSize) * sizeof(GLint)); return; }
/** * Called via glRenderbufferStorageEXT() to set the format and allocate * storage for a user-created renderbuffer. */ static GLboolean intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *irb = intel_renderbuffer(rb); int cpp; GLuint pitch; ASSERT(rb->Name != 0); switch (internalFormat) { case GL_R3_G3_B2: case GL_RGB4: case GL_RGB5: rb->Format = MESA_FORMAT_RGB565; rb->DataType = GL_UNSIGNED_BYTE; break; case GL_RGB: case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: rb->Format = MESA_FORMAT_XRGB8888; rb->DataType = GL_UNSIGNED_BYTE; break; case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: rb->Format = MESA_FORMAT_ARGB8888; rb->DataType = GL_UNSIGNED_BYTE; break; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: /* alloc a depth+stencil buffer */ rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; break; case GL_DEPTH_COMPONENT16: rb->Format = MESA_FORMAT_Z16; rb->DataType = GL_UNSIGNED_SHORT; break; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; break; case GL_DEPTH_STENCIL_EXT: case GL_DEPTH24_STENCIL8_EXT: rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; break; default: _mesa_problem(ctx, "Unexpected format in intel_alloc_renderbuffer_storage"); return GL_FALSE; } rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); cpp = _mesa_get_format_bytes(rb->Format); intelFlush(ctx); /* free old region */ if (irb->region) { intel_region_release(&irb->region); } /* allocate new memory region/renderbuffer */ /* Choose a pitch to match hardware requirements: */ pitch = ((cpp * width + 63) & ~63) / cpp; /* alloc hardware renderbuffer */ DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width, height, pitch); irb->region = intel_region_alloc(intel, I915_TILING_NONE, cpp, width, height, pitch, GL_TRUE); if (!irb->region) return GL_FALSE; /* out of memory? */ ASSERT(irb->region->buffer); rb->Width = width; rb->Height = height; return GL_TRUE; }
void GLAPIENTRY _mesa_GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params) { GLint buffer[16]; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); /* ARB_internalformat_query is also mandatory for ARB_internalformat_query2 */ if (!(_mesa_has_ARB_internalformat_query(ctx) || _mesa_is_gles3(ctx))) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInternalformativ"); return; } assert(ctx->Driver.QueryInternalFormat != NULL); if (!_legal_parameters(ctx, target, internalformat, pname, bufSize, params)) return; /* initialize the contents of the temporary buffer */ memcpy(buffer, params, MIN2(bufSize, 16) * sizeof(GLint)); /* Use the 'unsupported' response defined by the spec for every pname * as the default answer. */ _set_default_response(pname, buffer); if (!_is_target_supported(ctx, target) || !_is_internalformat_supported(ctx, target, internalformat) || !_is_resource_supported(ctx, target, internalformat, pname)) goto end; switch (pname) { case GL_SAMPLES: /* fall-through */ case GL_NUM_SAMPLE_COUNTS: /* The ARB_internalformat_query2 sets the response as 'unsupported' for * SAMPLES and NUM_SAMPLE_COUNTS: * * "If <internalformat> is not color-renderable, depth-renderable, or * stencil-renderable (as defined in section 4.4.4), or if <target> * does not support multiple samples (ie other than * TEXTURE_2D_MULTISAMPLE, TEXTURE_2D_MULTISAMPLE_ARRAY, * or RENDERBUFFER)." */ if ((target != GL_RENDERBUFFER && target != GL_TEXTURE_2D_MULTISAMPLE && target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY) || !_is_renderable(ctx, internalformat)) goto end; /* The GL ES 3.0 specification, section 6.1.15 page 236 says: * * "Since multisampling is not supported for signed and unsigned * integer internal formats, the value of NUM_SAMPLE_COUNTS will be * zero for such formats. * * Since OpenGL ES 3.1 adds support for multisampled integer formats, we * have to check the version for 30 exactly. */ if (pname == GL_NUM_SAMPLE_COUNTS && ctx->API == API_OPENGLES2 && ctx->Version == 30 && _mesa_is_enum_format_integer(internalformat)) { goto end; } ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_INTERNALFORMAT_SUPPORTED: /* Having a supported <internalformat> is implemented as a prerequisite * for all the <pnames>. Thus, if we reach this point, the internalformat is * supported. */ buffer[0] = GL_TRUE; break; case GL_INTERNALFORMAT_PREFERRED: /* The ARB_internalformat_query2 spec says: * * "- INTERNALFORMAT_PREFERRED: The implementation-preferred internal * format for representing resources of the specified <internalformat> is * returned in <params>. * * Therefore, we let the driver answer. Note that if we reach this * point, it means that the internalformat is supported, so the driver * is called just to try to get a preferred format. If not supported, * GL_NONE was already returned and the driver is not called. */ ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_INTERNALFORMAT_RED_SIZE: case GL_INTERNALFORMAT_GREEN_SIZE: case GL_INTERNALFORMAT_BLUE_SIZE: case GL_INTERNALFORMAT_ALPHA_SIZE: case GL_INTERNALFORMAT_DEPTH_SIZE: case GL_INTERNALFORMAT_STENCIL_SIZE: case GL_INTERNALFORMAT_SHARED_SIZE: case GL_INTERNALFORMAT_RED_TYPE: case GL_INTERNALFORMAT_GREEN_TYPE: case GL_INTERNALFORMAT_BLUE_TYPE: case GL_INTERNALFORMAT_ALPHA_TYPE: case GL_INTERNALFORMAT_DEPTH_TYPE: case GL_INTERNALFORMAT_STENCIL_TYPE: { GLint baseformat; mesa_format texformat; if (target != GL_RENDERBUFFER) { if (!_mesa_legal_get_tex_level_parameter_target(ctx, target, true)) goto end; baseformat = _mesa_base_tex_format(ctx, internalformat); } else { baseformat = _mesa_base_fbo_format(ctx, internalformat); } /* Let the driver choose the texture format. * * Disclaimer: I am considering that drivers use for renderbuffers the * same format-choice logic as for textures. */ texformat = ctx->Driver.ChooseTextureFormat(ctx, target, internalformat, GL_NONE /*format */, GL_NONE /* type */); if (texformat == MESA_FORMAT_NONE || baseformat <= 0) goto end; /* Implementation based on what Mesa does for glGetTexLevelParameteriv * and glGetRenderbufferParameteriv functions. */ if (pname == GL_INTERNALFORMAT_SHARED_SIZE) { if (_mesa_has_EXT_texture_shared_exponent(ctx) && target != GL_TEXTURE_BUFFER && target != GL_RENDERBUFFER && texformat == MESA_FORMAT_R9G9B9E5_FLOAT) { buffer[0] = 5; } goto end; } if (!_mesa_base_format_has_channel(baseformat, pname)) goto end; switch (pname) { case GL_INTERNALFORMAT_DEPTH_SIZE: if (ctx->API != API_OPENGL_CORE && !_mesa_has_ARB_depth_texture(ctx) && target != GL_RENDERBUFFER && target != GL_TEXTURE_BUFFER) goto end; /* fallthrough */ case GL_INTERNALFORMAT_RED_SIZE: case GL_INTERNALFORMAT_GREEN_SIZE: case GL_INTERNALFORMAT_BLUE_SIZE: case GL_INTERNALFORMAT_ALPHA_SIZE: case GL_INTERNALFORMAT_STENCIL_SIZE: buffer[0] = _mesa_get_format_bits(texformat, pname); break; case GL_INTERNALFORMAT_DEPTH_TYPE: if (!_mesa_has_ARB_texture_float(ctx)) goto end; /* fallthrough */ case GL_INTERNALFORMAT_RED_TYPE: case GL_INTERNALFORMAT_GREEN_TYPE: case GL_INTERNALFORMAT_BLUE_TYPE: case GL_INTERNALFORMAT_ALPHA_TYPE: case GL_INTERNALFORMAT_STENCIL_TYPE: buffer[0] = _mesa_get_format_datatype(texformat); break; default: break; } break; } /* For WIDTH/HEIGHT/DEPTH/LAYERS there is no reason to think that the * returned values should be different to the values returned by * GetInteger with MAX_TEXTURE_SIZE, MAX_3D_TEXTURE_SIZE, etc.*/ case GL_MAX_WIDTH: case GL_MAX_HEIGHT: case GL_MAX_DEPTH: { GLenum get_pname; GLint dimensions; GLint min_dimensions; /* From query2:MAX_HEIGHT spec (as example): * * "If the resource does not have at least two dimensions, or if the * resource is unsupported, zero is returned." */ dimensions = _get_target_dimensions(target); min_dimensions = _get_min_dimensions(pname); if (dimensions < min_dimensions) goto end; get_pname = _equivalent_size_pname(target, pname); if (get_pname == 0) goto end; _mesa_GetIntegerv(get_pname, buffer); break; } case GL_MAX_LAYERS: if (!_mesa_has_EXT_texture_array(ctx)) goto end; if (!_mesa_is_array_texture(target)) goto end; _mesa_GetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, buffer); break; case GL_MAX_COMBINED_DIMENSIONS:{ GLint64 combined_value = 1; GLenum max_dimensions_pnames[] = { GL_MAX_WIDTH, GL_MAX_HEIGHT, GL_MAX_DEPTH, GL_SAMPLES }; unsigned i; GLint current_value; /* Combining the dimensions. Note that for array targets, this would * automatically include the value of MAX_LAYERS, as that value is * returned as MAX_HEIGHT or MAX_DEPTH */ for (i = 0; i < 4; i++) { if (max_dimensions_pnames[i] == GL_SAMPLES && !_is_multisample_target(target)) continue; _mesa_GetInternalformativ(target, internalformat, max_dimensions_pnames[i], 1, ¤t_value); if (current_value != 0) combined_value *= current_value; } if (_mesa_is_cube_map_texture(target)) combined_value *= 6; /* We pack the 64-bit value on two 32-bit values. Calling the 32-bit * query, this would work as far as the value can be hold on a 32-bit * signed integer. For the 64-bit query, the wrapper around the 32-bit * query will unpack the value */ memcpy(buffer, &combined_value, sizeof(GLint64)); break; } case GL_COLOR_COMPONENTS: /* The ARB_internalformat_query2 spec says: * * "- COLOR_COMPONENTS: If the internal format contains any color * components (R, G, B, or A), TRUE is returned in <params>. * If the internal format is unsupported or contains no color * components, FALSE is returned." */ if (_mesa_is_color_format(internalformat)) buffer[0] = GL_TRUE; break; case GL_DEPTH_COMPONENTS: /* The ARB_internalformat_query2 spec says: * * "- DEPTH_COMPONENTS: If the internal format contains a depth * component (D), TRUE is returned in <params>. If the internal format * is unsupported or contains no depth component, FALSE is returned." */ if (_mesa_is_depth_format(internalformat) || _mesa_is_depthstencil_format(internalformat)) buffer[0] = GL_TRUE; break; case GL_STENCIL_COMPONENTS: /* The ARB_internalformat_query2 spec says: * * "- STENCIL_COMPONENTS: If the internal format contains a stencil * component (S), TRUE is returned in <params>. If the internal format * is unsupported or contains no stencil component, FALSE is returned. */ if (_mesa_is_stencil_format(internalformat) || _mesa_is_depthstencil_format(internalformat)) buffer[0] = GL_TRUE; break; case GL_COLOR_RENDERABLE: case GL_DEPTH_RENDERABLE: case GL_STENCIL_RENDERABLE: if (!_is_renderable(ctx, internalformat)) goto end; if (pname == GL_COLOR_RENDERABLE) { if (!_mesa_is_color_format(internalformat)) goto end; } else { GLenum baseFormat = _mesa_base_fbo_format(ctx, internalformat); if (baseFormat != GL_DEPTH_STENCIL && ((pname == GL_DEPTH_RENDERABLE && baseFormat != GL_DEPTH_COMPONENT) || (pname == GL_STENCIL_RENDERABLE && baseFormat != GL_STENCIL_INDEX))) goto end; } buffer[0] = GL_TRUE; break; case GL_FRAMEBUFFER_RENDERABLE_LAYERED: if (!_mesa_has_EXT_texture_array(ctx) || _legal_target_for_framebuffer_texture_layer(ctx, target)) goto end; /* fallthrough */ case GL_FRAMEBUFFER_RENDERABLE: case GL_FRAMEBUFFER_BLEND: if (!_mesa_has_ARB_framebuffer_object(ctx)) goto end; if (target == GL_TEXTURE_BUFFER || !_is_renderable(ctx, internalformat)) goto end; ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_READ_PIXELS: case GL_READ_PIXELS_FORMAT: case GL_READ_PIXELS_TYPE: ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_TEXTURE_IMAGE_FORMAT: case GL_GET_TEXTURE_IMAGE_FORMAT: case GL_TEXTURE_IMAGE_TYPE: case GL_GET_TEXTURE_IMAGE_TYPE: ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_MIPMAP: case GL_MANUAL_GENERATE_MIPMAP: case GL_AUTO_GENERATE_MIPMAP: if (!_mesa_is_valid_generate_texture_mipmap_target(ctx, target) || !_mesa_is_valid_generate_texture_mipmap_internalformat(ctx, internalformat)) { goto end; } if (pname == GL_MIPMAP) { buffer[0] = GL_TRUE; goto end; } else if (pname == GL_MANUAL_GENERATE_MIPMAP) { if (!_mesa_has_ARB_framebuffer_object(ctx)) goto end; } else { /* From ARB_internalformat_query2: * "Dependencies on OpenGL 3.2 (Core Profile) * In core profiles for OpenGL 3.2 and later versions, queries * for the AUTO_GENERATE_MIPMAP <pname> return the appropriate * unsupported response." */ if (_mesa_is_desktop_gl(ctx) && ctx->Version >= 32) goto end; } ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_COLOR_ENCODING: if (!_mesa_is_color_format(internalformat)) goto end; if (_mesa_is_srgb_format(internalformat)) buffer[0] = GL_SRGB; else buffer[0] = GL_LINEAR; break; case GL_SRGB_READ: if (!_mesa_has_EXT_texture_sRGB(ctx) || !_mesa_is_srgb_format(internalformat)) { goto end; } ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_SRGB_WRITE: if (!_mesa_has_EXT_framebuffer_sRGB(ctx) || !_mesa_is_color_format(internalformat)) { goto end; } ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_SRGB_DECODE_ARB: /* Presence of EXT_texture_sRGB_decode was already verified */ if (!_mesa_has_EXT_texture_sRGB(ctx) || target == GL_RENDERBUFFER || !_mesa_is_srgb_format(internalformat)) { goto end; } ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_FILTER: /* If it doesn't allow to set sampler parameters then it would not allow * to set a filter different to GL_NEAREST. In practice, this method * only filters out MULTISAMPLE/MULTISAMPLE_ARRAY */ if (!_mesa_target_allows_setting_sampler_parameters(target)) goto end; if (_mesa_is_enum_format_integer(internalformat)) goto end; if (target == GL_TEXTURE_BUFFER) goto end; /* At this point we know that multi-texel filtering is supported. We * need to call the driver to know if it is CAVEAT_SUPPORT or * FULL_SUPPORT. */ ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_VERTEX_TEXTURE: case GL_TESS_CONTROL_TEXTURE: case GL_TESS_EVALUATION_TEXTURE: case GL_GEOMETRY_TEXTURE: case GL_FRAGMENT_TEXTURE: case GL_COMPUTE_TEXTURE: if (target == GL_RENDERBUFFER) goto end; if ((pname == GL_TESS_CONTROL_TEXTURE || pname == GL_TESS_EVALUATION_TEXTURE) && !_mesa_has_tessellation(ctx)) goto end; if (pname == GL_GEOMETRY_TEXTURE && !_mesa_has_geometry_shaders(ctx)) goto end; if (pname == GL_COMPUTE_TEXTURE && !_mesa_has_compute_shaders(ctx)) goto end; ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_TEXTURE_GATHER: case GL_TEXTURE_GATHER_SHADOW: if (!_mesa_has_ARB_texture_gather(ctx)) goto end; /* fallthrough */ case GL_TEXTURE_SHADOW: /* Only depth or depth-stencil image formats make sense in shadow samplers */ if (pname != GL_TEXTURE_GATHER && !_mesa_is_depth_format(internalformat) && !_mesa_is_depthstencil_format(internalformat)) goto end; /* Validate the target for shadow and gather operations */ switch (target) { case GL_TEXTURE_2D: case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_RECTANGLE: break; case GL_TEXTURE_1D: case GL_TEXTURE_1D_ARRAY: /* 1D and 1DArray textures are not admitted in gather operations */ if (pname != GL_TEXTURE_SHADOW) goto end; break; default: goto end; } ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_SHADER_IMAGE_LOAD: case GL_SHADER_IMAGE_STORE: if (!_mesa_has_ARB_shader_image_load_store(ctx)) goto end; /* We call to _mesa_is_shader_image_format_supported * using "internalformat" as parameter, because the * the ARB_internalformat_query2 spec says: * "In this case the <internalformat> is the value of the <format> * parameter that is passed to BindImageTexture." */ if (target == GL_RENDERBUFFER || !_mesa_is_shader_image_format_supported(ctx, internalformat)) goto end; ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_SHADER_IMAGE_ATOMIC: if (!_mesa_has_ARB_shader_image_load_store(ctx)) goto end; ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_IMAGE_TEXEL_SIZE: { mesa_format image_format; if (!_mesa_has_ARB_shader_image_load_store(ctx) || target == GL_RENDERBUFFER) goto end; image_format = _mesa_get_shader_image_format(internalformat); if (image_format == MESA_FORMAT_NONE) goto end; /* We return bits */ buffer[0] = (_mesa_get_format_bytes(image_format) * 8); break; } case GL_IMAGE_COMPATIBILITY_CLASS: if (!_mesa_has_ARB_shader_image_load_store(ctx) || target == GL_RENDERBUFFER) goto end; buffer[0] = _mesa_get_image_format_class(internalformat); break; case GL_IMAGE_PIXEL_FORMAT: { GLint base_format; if (!_mesa_has_ARB_shader_image_load_store(ctx) || target == GL_RENDERBUFFER || !_mesa_is_shader_image_format_supported(ctx, internalformat)) goto end; base_format = _mesa_base_tex_format(ctx, internalformat); if (base_format == -1) goto end; if (_mesa_is_enum_format_integer(internalformat)) buffer[0] = _mesa_base_format_to_integer_format(base_format); else buffer[0] = base_format; break; } case GL_IMAGE_PIXEL_TYPE: { mesa_format image_format; GLenum datatype; GLuint comps; if (!_mesa_has_ARB_shader_image_load_store(ctx) || target == GL_RENDERBUFFER) goto end; image_format = _mesa_get_shader_image_format(internalformat); if (image_format == MESA_FORMAT_NONE) goto end; _mesa_uncompressed_format_to_type_and_comps(image_format, &datatype, &comps); if (!datatype) goto end; buffer[0] = datatype; break; } case GL_IMAGE_FORMAT_COMPATIBILITY_TYPE: { if (!_mesa_has_ARB_shader_image_load_store(ctx)) goto end; if (!_mesa_legal_get_tex_level_parameter_target(ctx, target, true)) goto end; /* From spec: "Equivalent to calling GetTexParameter with <value> set * to IMAGE_FORMAT_COMPATIBILITY_TYPE." * * GetTexParameter just returns * tex_obj->ImageFormatCompatibilityType. We create a fake tex_obj * just with the purpose of getting the value. */ struct gl_texture_object *tex_obj = _mesa_new_texture_object(ctx, 0, target); buffer[0] = tex_obj->ImageFormatCompatibilityType; _mesa_delete_texture_object(ctx, tex_obj); break; } case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST: case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST: case GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE: case GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE: if (target == GL_RENDERBUFFER) goto end; if (!_mesa_is_depthstencil_format(internalformat)) { if (((pname == GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST || pname == GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE) && !_mesa_is_depth_format(internalformat)) || ((pname == GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST || pname == GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE) && !_mesa_is_stencil_format(internalformat))) goto end; } ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_TEXTURE_COMPRESSED: buffer[0] = _mesa_is_compressed_format(ctx, internalformat); break; case GL_TEXTURE_COMPRESSED_BLOCK_WIDTH: case GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT: case GL_TEXTURE_COMPRESSED_BLOCK_SIZE: { mesa_format mesaformat; GLint block_size; mesaformat = _mesa_glenum_to_compressed_format(internalformat); if (mesaformat == MESA_FORMAT_NONE) goto end; block_size = _mesa_get_format_bytes(mesaformat); assert(block_size > 0); if (pname == GL_TEXTURE_COMPRESSED_BLOCK_SIZE) { buffer[0] = block_size; } else { GLuint bwidth, bheight; /* Returns the width and height in pixels. We return bytes */ _mesa_get_format_block_size(mesaformat, &bwidth, &bheight); assert(bwidth > 0 && bheight > 0); if (pname == GL_TEXTURE_COMPRESSED_BLOCK_WIDTH) buffer[0] = block_size / bheight; else buffer[0] = block_size / bwidth; } break; } case GL_CLEAR_BUFFER: if (target != GL_TEXTURE_BUFFER) goto end; ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); break; case GL_TEXTURE_VIEW: case GL_VIEW_COMPATIBILITY_CLASS: if (!_mesa_has_ARB_texture_view(ctx) || target == GL_TEXTURE_BUFFER || target == GL_RENDERBUFFER) goto end; if (pname == GL_TEXTURE_VIEW) { ctx->Driver.QueryInternalFormat(ctx, target, internalformat, pname, buffer); } else { GLenum view_class = _mesa_texture_view_lookup_view_class(ctx, internalformat); if (view_class == GL_FALSE) goto end; buffer[0] = view_class; } break; default: unreachable("bad param"); } end: if (bufSize != 0 && params == NULL) { /* Emit a warning to aid application debugging, but go ahead and do the * memcpy (and probably crash) anyway. */ _mesa_warning(ctx, "glGetInternalformativ(bufSize = %d, but params = NULL)", bufSize); } /* Copy the data from the temporary buffer to the buffer supplied by the * application. Clamp the size of the copy to the size supplied by the * application. */ memcpy(params, buffer, MIN2(bufSize, 16) * sizeof(GLint)); return; }
static bool _is_resource_supported(struct gl_context *ctx, GLenum target, GLenum internalformat, GLenum pname) { /* From the ARB_internalformat_query2 spec: * * In the following descriptions, the term /resource/ is used to generically * refer to an object of the appropriate type that has been created with * <internalformat> and <target>. If the particular <target> and * <internalformat> combination do not make sense, ... the "unsupported" * answer should be given. This is not an error. */ /* In the ARB_internalformat_query2 spec wording, some <pnames> do not care * about the /resource/ being supported or not, we return 'true' for those. */ switch (pname) { case GL_INTERNALFORMAT_SUPPORTED: case GL_INTERNALFORMAT_PREFERRED: case GL_COLOR_COMPONENTS: case GL_DEPTH_COMPONENTS: case GL_STENCIL_COMPONENTS: case GL_COLOR_RENDERABLE: case GL_DEPTH_RENDERABLE: case GL_STENCIL_RENDERABLE: return true; default: break; } switch(target){ case GL_TEXTURE_1D: case GL_TEXTURE_1D_ARRAY: case GL_TEXTURE_2D: case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_3D: case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_RECTANGLE: /* Based on what Mesa does for glTexImage1D/2D/3D and * glCompressedTexImage1D/2D/3D functions. */ if (_mesa_base_tex_format(ctx, internalformat) < 0) return false; /* additional checks for depth textures */ if (!_mesa_legal_texture_base_format_for_target(ctx, target, internalformat)) return false; /* additional checks for compressed textures */ if (_mesa_is_compressed_format(ctx, internalformat) && (!_mesa_target_can_be_compressed(ctx, target, internalformat, NULL) || _mesa_format_no_online_compression(ctx, internalformat))) return false; break; case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: /* Based on what Mesa does for glTexImage2D/3DMultisample, * glTexStorage2D/3DMultisample and * glTextureStorage2D/3DMultisample functions. */ if (!_mesa_is_renderable_texture_format(ctx, internalformat)) return false; break; case GL_TEXTURE_BUFFER: /* Based on what Mesa does for the glTexBuffer function. */ if (_mesa_validate_texbuffer_format(ctx, internalformat) == MESA_FORMAT_NONE) return false; break; case GL_RENDERBUFFER: /* Based on what Mesa does for glRenderbufferStorage(Multisample) and * glNamedRenderbufferStorage functions. */ if (!_mesa_base_fbo_format(ctx, internalformat)) return false; break; default: unreachable("bad target"); } return true; }
/** * gl_renderbuffer::AllocStorage() * This is called to allocate the original drawing surface, and * during window resize. */ static GLboolean st_renderbuffer_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { 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; struct pipe_surface surf_tmpl; if (internalFormat == GL_RGBA16_SNORM && strb->software) { /* 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, rb->NumSamples); } if (format == PIPE_FORMAT_NONE) { return FALSE; } /* init renderbuffer fields */ strb->Base.Width = width; strb->Base.Height = height; strb->Base.Format = st_pipe_format_to_mesa_format(format); strb->Base._BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); strb->defined = GL_FALSE; /* undefined contents now */ if (strb->software) { size_t size; free(strb->data); size = _mesa_format_image_size(strb->Base.Format, width, height, 1); strb->data = malloc(size); return strb->data != NULL; } else { struct pipe_resource template; /* Free the old surface and texture */ pipe_surface_reference( &strb->surface, NULL ); pipe_resource_reference( &strb->texture, NULL ); if (width == 0 || height == 0) { /* if size is zero, nothing to allocate */ return GL_TRUE; } /* Setup new texture template. */ memset(&template, 0, sizeof(template));
/** * This is a software fallback for the gl_renderbuffer->AllocStorage * function. * Device drivers will typically override this function for the buffers * which it manages (typically color buffers, Z and stencil). * Other buffers (like software accumulation and aux buffers) which the driver * doesn't manage can be handled with this function. * * This one multi-purpose function can allocate stencil, depth, accum, color * or color-index buffers! */ static GLboolean soft_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); GLuint bpp; switch (internalFormat) { case GL_RGB: case GL_R3_G3_B2: case GL_RGB4: case GL_RGB5: case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: rb->Format = MESA_FORMAT_BGR_UNORM8; break; case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: case GL_RGBA8: #if 1 case GL_RGB10_A2: case GL_RGBA12: #endif if (_mesa_little_endian()) rb->Format = MESA_FORMAT_R8G8B8A8_UNORM; else rb->Format = MESA_FORMAT_A8B8G8R8_UNORM; break; case GL_RGBA16: case GL_RGBA16_SNORM: /* for accum buffer */ rb->Format = MESA_FORMAT_RGBA_SNORM16; break; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: rb->Format = MESA_FORMAT_S_UINT8; break; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT16: rb->Format = MESA_FORMAT_Z_UNORM16; break; case GL_DEPTH_COMPONENT24: rb->Format = MESA_FORMAT_Z24_UNORM_X8_UINT; break; case GL_DEPTH_COMPONENT32: rb->Format = MESA_FORMAT_Z_UNORM32; break; case GL_DEPTH_STENCIL_EXT: case GL_DEPTH24_STENCIL8_EXT: rb->Format = MESA_FORMAT_S8_UINT_Z24_UNORM; break; default: /* unsupported format */ return GL_FALSE; } bpp = _mesa_get_format_bytes(rb->Format); /* free old buffer storage */ free(srb->Buffer); srb->Buffer = NULL; srb->RowStride = width * bpp; if (width > 0 && height > 0) { /* allocate new buffer storage */ srb->Buffer = malloc(srb->RowStride * height); if (srb->Buffer == NULL) { rb->Width = 0; rb->Height = 0; _mesa_error(ctx, GL_OUT_OF_MEMORY, "software renderbuffer allocation (%d x %d x %d)", width, height, bpp); return GL_FALSE; } } rb->Width = width; rb->Height = height; rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); if (rb->Name == 0 && internalFormat == GL_RGBA16_SNORM && rb->_BaseFormat == 0) { /* NOTE: This is a special case just for accumulation buffers. * This is a very limited use case- there's no snorm texturing or * rendering going on. */ rb->_BaseFormat = GL_RGBA; } else { /* the internalFormat should have been error checked long ago */ assert(rb->_BaseFormat); } return GL_TRUE; }
/** * Called via glRenderbufferStorageEXT() to set the format and allocate * storage for a user-created renderbuffer. */ static GLboolean radeon_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct radeon_context *radeon = RADEON_CONTEXT(ctx); struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb); GLboolean software_buffer = GL_FALSE; int cpp; radeon_print(RADEON_TEXTURE, RADEON_TRACE, "%s(%p, rb %p) \n", __func__, ctx, rb); ASSERT(rb->Name != 0); switch (internalFormat) { case GL_R3_G3_B2: case GL_RGB4: case GL_RGB5: rb->Format = _dri_texformat_rgb565; rb->DataType = GL_UNSIGNED_BYTE; cpp = 2; break; case GL_RGB: case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: rb->Format = _dri_texformat_argb8888; rb->DataType = GL_UNSIGNED_BYTE; cpp = 4; break; case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: rb->Format = _dri_texformat_argb8888; rb->DataType = GL_UNSIGNED_BYTE; cpp = 4; break; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: /* alloc a depth+stencil buffer */ rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; cpp = 4; break; case GL_DEPTH_COMPONENT16: rb->Format = MESA_FORMAT_Z16; rb->DataType = GL_UNSIGNED_SHORT; cpp = 2; break; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: rb->Format = MESA_FORMAT_X8_Z24; rb->DataType = GL_UNSIGNED_INT; cpp = 4; break; case GL_DEPTH_STENCIL_EXT: case GL_DEPTH24_STENCIL8_EXT: rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; cpp = 4; break; default: _mesa_problem(ctx, "Unexpected format in radeon_alloc_renderbuffer_storage"); return GL_FALSE; } rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); if (ctx->Driver.Flush) ctx->Driver.Flush(ctx); /* +r6/r7 */ if (rrb->bo) radeon_bo_unref(rrb->bo); if (software_buffer) { return _mesa_soft_renderbuffer_storage(ctx, rb, internalFormat, width, height); } else { uint32_t size; uint32_t pitch = ((cpp * width + 63) & ~63) / cpp; if (RADEON_DEBUG & RADEON_MEMORY) fprintf(stderr,"Allocating %d x %d radeon RBO (pitch %d)\n", width, height, pitch); size = pitch * height * cpp; rrb->pitch = pitch * cpp; rrb->cpp = cpp; rrb->bo = radeon_bo_open(radeon->radeonScreen->bom, 0, size, 0, RADEON_GEM_DOMAIN_VRAM, 0); rb->Width = width; rb->Height = height; return GL_TRUE; } }
static void intel_image_target_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, void *image_handle) { struct brw_context *brw = brw_context(ctx); struct intel_renderbuffer *irb; __DRIscreen *screen; __DRIimage *image; screen = brw->intelScreen->driScrnPriv; image = screen->dri2.image->lookupEGLImage(screen, image_handle, screen->loaderPrivate); if (image == NULL) return; if (image->planar_format && image->planar_format->nplanes > 1) { _mesa_error(ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(planar buffers are not " "supported as render targets."); return; } /* Buffers originating from outside are for read-only. */ if (image->dma_buf_imported) { _mesa_error(ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(dma buffers are read-only)"); return; } /* __DRIimage is opaque to the core so it has to be checked here */ switch (image->format) { case MESA_FORMAT_RGBA8888_REV: _mesa_error(ctx, GL_INVALID_OPERATION, "glEGLImageTargetRenderbufferStorage(unsupported image format"); return; break; default: break; } irb = intel_renderbuffer(rb); intel_miptree_release(&irb->mt); irb->mt = intel_miptree_create_for_bo(brw, image->region->bo, image->format, image->offset, image->region->width, image->region->height, image->region->pitch, image->region->tiling); if (!irb->mt) return; rb->InternalFormat = image->internal_format; rb->Width = image->region->width; rb->Height = image->region->height; rb->Format = image->format; rb->_BaseFormat = _mesa_base_fbo_format(ctx, image->internal_format); rb->NeedsFinishRenderTexture = true; }
/** * gl_renderbuffer::AllocStorage() * This is called to allocate the original drawing surface, and * during window resize. */ static GLboolean st_renderbuffer_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { 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 = PIPE_FORMAT_NONE; struct pipe_surface surf_tmpl; struct pipe_resource templ; /* init renderbuffer fields */ strb->Base.Width = width; strb->Base.Height = height; strb->Base._BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); strb->defined = GL_FALSE; /* undefined contents now */ if (strb->software) { return st_renderbuffer_alloc_sw_storage(ctx, rb, internalFormat, width, height); } /* Free the old surface and texture */ pipe_surface_reference( &strb->surface, NULL ); pipe_resource_reference( &strb->texture, NULL ); /* If an sRGB framebuffer is unsupported, sRGB formats behave like linear * formats. */ if (!ctx->Extensions.EXT_framebuffer_sRGB) { internalFormat = _mesa_get_linear_internalformat(internalFormat); } /* Handle multisample renderbuffers first. * * From ARB_framebuffer_object: * If <samples> is zero, then RENDERBUFFER_SAMPLES is set to zero. * Otherwise <samples> 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 <samples> 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; for (i = rb->NumSamples; i <= ctx->Const.MaxSamples; i++) { format = st_choose_renderbuffer_format(st, internalFormat, i); if (format != PIPE_FORMAT_NONE) { rb->NumSamples = i; break; } } } else { format = st_choose_renderbuffer_format(st, 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; } /* 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); 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; }
void GLAPIENTRY _mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height) { struct gl_renderbuffer *rb; GLenum baseFormat; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (target != GL_RENDERBUFFER_EXT) { _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(target)"); return; } baseFormat = _mesa_base_fbo_format(ctx, internalFormat); if (baseFormat == 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glRenderbufferStorageEXT(internalFormat)"); return; } if (width < 1 || width > (GLsizei) ctx->Const.MaxRenderbufferSize) { _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(width)"); return; } if (height < 1 || height > (GLsizei) ctx->Const.MaxRenderbufferSize) { _mesa_error(ctx, GL_INVALID_VALUE, "glRenderbufferStorageEXT(height)"); return; } rb = ctx->CurrentRenderbuffer; if (!rb) { _mesa_error(ctx, GL_INVALID_OPERATION, "glRenderbufferStorageEXT"); return; } FLUSH_VERTICES(ctx, _NEW_BUFFERS); if (rb->InternalFormat == internalFormat && rb->Width == (GLuint) width && rb->Height == (GLuint) height) { /* no change in allocation needed */ return; } /* These MUST get set by the AllocStorage func */ rb->_ActualFormat = 0; rb->RedBits = rb->GreenBits = rb->BlueBits = rb->AlphaBits = rb->IndexBits = rb->DepthBits = rb->StencilBits = 0; /* Now allocate the storage */ ASSERT(rb->AllocStorage); if (rb->AllocStorage(ctx, rb, internalFormat, width, height)) { /* No error - check/set fields now */ assert(rb->_ActualFormat); assert(rb->Width == (GLuint) width); assert(rb->Height == (GLuint) height); assert(rb->RedBits || rb->GreenBits || rb->BlueBits || rb->AlphaBits || rb->DepthBits || rb->StencilBits || rb->IndexBits); rb->InternalFormat = internalFormat; rb->_BaseFormat = baseFormat; } else { /* Probably ran out of memory - clear the fields */ rb->Width = 0; rb->Height = 0; rb->InternalFormat = GL_NONE; rb->_ActualFormat = GL_NONE; rb->_BaseFormat = GL_NONE; rb->RedBits = rb->GreenBits = rb->BlueBits = rb->AlphaBits = rb->IndexBits = rb->DepthBits = rb->StencilBits = 0; } /* test_framebuffer_completeness(ctx, fb); */ /* XXX if this renderbuffer is attached anywhere, invalidate attachment * points??? */ }