/** * Apply depth (Z) buffer testing to the span. * \return approx number of pixels that passed (only zero is reliable) */ GLuint _swrast_depth_test_span(struct gl_context *ctx, SWspan *span) { struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; const GLint bpp = _mesa_get_format_bytes(rb->Format); void *zStart; const GLuint count = span->end; const GLuint *fragZ = span->array->z; GLubyte *mask = span->array->mask; void *zBufferVals; GLuint *zBufferTemp = NULL; GLuint passed; GLuint zBits = _mesa_get_format_bits(rb->Format, GL_DEPTH_BITS); GLboolean ztest16 = GL_FALSE; if (span->arrayMask & SPAN_XY) zStart = NULL; else zStart = _swrast_pixel_address(rb, span->x, span->y); if (rb->Format == MESA_FORMAT_Z_UNORM16 && !(span->arrayMask & SPAN_XY)) { /* directly read/write row of 16-bit Z values */ zBufferVals = zStart; ztest16 = GL_TRUE; } else if (rb->Format == MESA_FORMAT_Z_UNORM32 && !(span->arrayMask & SPAN_XY)) { /* directly read/write row of 32-bit Z values */ zBufferVals = zStart; } else { if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) { _mesa_problem(ctx, "Incorrectly writing swrast's integer depth " "values to %s depth buffer", _mesa_get_format_name(rb->Format)); } /* copy Z buffer values into temp buffer (32-bit Z values) */ zBufferTemp = malloc(count * sizeof(GLuint)); if (!zBufferTemp) return 0; if (span->arrayMask & SPAN_XY) { get_z32_values(ctx, rb, count, span->array->x, span->array->y, zBufferTemp); } else { _mesa_unpack_uint_z_row(rb->Format, count, zStart, zBufferTemp); } if (zBits == 24) { GLuint i; /* Convert depth buffer values from 32 to 24 bits to match the * fragment Z values generated by rasterization. */ for (i = 0; i < count; i++) { zBufferTemp[i] >>= 8; } } else if (zBits == 16) {
/** * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc). * Compressed textures are handled here as well. */ static void get_tex_rgba(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); GLbitfield transferOps = 0x0; /* In general, clamping does not apply to glGetTexImage, except when * the returned type of the image can't hold negative values. */ if (type_needs_clamping(type)) { /* the returned image type can't have negative values */ if (dataType == GL_FLOAT || dataType == GL_SIGNED_NORMALIZED || format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) { transferOps |= IMAGE_CLAMP_BIT; } } /* This applies to RGB, RGBA textures. if the format is either LUMINANCE * or LUMINANCE ALPHA, luminance (L) is computed as L=R+G+B .we need to * clamp the sum to [0,1]. */ else if ((format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) && dataType == GL_UNSIGNED_NORMALIZED) { transferOps |= IMAGE_CLAMP_BIT; } get_tex_rgba_uncompressed(ctx, dimensions, format, type, pixels, texImage, transferOps); }
/** * Used to answer the GL_IMPLEMENTATION_COLOR_READ_TYPE_OES query. */ GLenum _mesa_get_color_read_type(struct gl_context *ctx) { if (!ctx->ReadBuffer || !ctx->ReadBuffer->_ColorReadBuffer) { /* The spec is unclear how to handle this case, but NVIDIA's * driver generates GL_INVALID_OPERATION. */ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE: " "no GL_READ_BUFFER)"); return GL_NONE; } else { const GLenum format = ctx->ReadBuffer->_ColorReadBuffer->Format; const GLenum data_type = _mesa_get_format_datatype(format); if (format == MESA_FORMAT_RGB565) return GL_UNSIGNED_SHORT_5_6_5_REV; switch (data_type) { case GL_SIGNED_NORMALIZED: return GL_BYTE; case GL_UNSIGNED_INT: case GL_INT: case GL_FLOAT: return data_type; case GL_UNSIGNED_NORMALIZED: default: return GL_UNSIGNED_BYTE; } } }
/** * Used to answer the GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES queries (using * GetIntegerv, GetFramebufferParameteriv, etc) * * If @fb is NULL, the method returns the value for the current bound * framebuffer. */ GLenum _mesa_get_color_read_format(struct gl_context *ctx, struct gl_framebuffer *fb, const char *caller) { if (ctx->NewState) _mesa_update_state(ctx); if (fb == NULL) fb = ctx->ReadBuffer; if (!fb || !fb->_ColorReadBuffer) { /* * From OpenGL 4.5 spec, section 18.2.2 "ReadPixels": * * "An INVALID_OPERATION error is generated by GetIntegerv if pname * is IMPLEMENTATION_COLOR_READ_FORMAT or IMPLEMENTATION_COLOR_- * READ_TYPE and any of: * * the read framebuffer is not framebuffer complete. * * the read framebuffer is a framebuffer object, and the selected * read buffer (see section 18.2.1) has no image attached. * * the selected read buffer is NONE." * * There is not equivalent quote for GetFramebufferParameteriv or * GetNamedFramebufferParameteriv, but from section 9.2.3 "Framebuffer * Object Queries": * * "Values of framebuffer-dependent state are identical to those that * would be obtained were the framebuffer object bound and queried * using the simple state queries in that table." * * Where "using the simple state queries" refer to use GetIntegerv. So * we will assume that on that situation the same error should be * triggered too. */ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(GL_IMPLEMENTATION_COLOR_READ_FORMAT: no GL_READ_BUFFER)", caller); return GL_NONE; } else { const mesa_format format = fb->_ColorReadBuffer->Format; const GLenum data_type = _mesa_get_format_datatype(format); if (format == MESA_FORMAT_B8G8R8A8_UNORM) return GL_BGRA; else if (format == MESA_FORMAT_B5G6R5_UNORM) return GL_RGB; else if (format == MESA_FORMAT_R_UNORM8) return GL_RED; switch (data_type) { case GL_UNSIGNED_INT: case GL_INT: return GL_RGBA_INTEGER; default: return GL_RGBA; } } }
/** * glGetTexImage for color formats (RGBA, RGB, alpha, LA, etc). * Compressed textures are handled here as well. */ static void get_tex_rgba(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { const GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); GLbitfield transferOps = 0x0; /* In general, clamping does not apply to glGetTexImage, except when * the returned type of the image can't hold negative values. */ if (type_needs_clamping(type)) { /* the returned image type can't have negative values */ if (dataType == GL_FLOAT || dataType == GL_SIGNED_NORMALIZED || format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) { transferOps |= IMAGE_CLAMP_BIT; } } if (_mesa_is_format_compressed(texImage->TexFormat)) { get_tex_rgba_compressed(ctx, dimensions, format, type, pixels, texImage, transferOps); } else { get_tex_rgba_uncompressed(ctx, dimensions, format, type, pixels, texImage, transferOps); } }
GLboolean _mesa_texstore_needs_transfer_ops(struct gl_context *ctx, GLenum baseInternalFormat, mesa_format dstFormat) { GLenum dstType; /* There are different rules depending on the base format. */ switch (baseInternalFormat) { case GL_DEPTH_COMPONENT: case GL_DEPTH_STENCIL: return ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f; case GL_STENCIL_INDEX: return GL_FALSE; default: /* Color formats. * Pixel transfer ops (scale, bias, table lookup) do not apply * to integer formats. */ dstType = _mesa_get_format_datatype(dstFormat); return dstType != GL_INT && dstType != GL_UNSIGNED_INT && ctx->_ImageTransferState; } }
/** * For non-float-depth and stencil buffers being read as 24/8 depth/stencil, * copy the integer data directly instead of converting depth to float and * re-packing. */ static GLboolean fast_read_depth_stencil_pixels_separate(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, uint32_t *dst, int dstStride) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; GLubyte *depthMap, *stencilMap, *stencilVals; int depthStride, stencilStride, i, j; if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED) return GL_FALSE; ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height, GL_MAP_READ_BIT, &depthMap, &depthStride); if (!depthMap) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return GL_TRUE; /* don't bother trying the slow path */ } ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height, GL_MAP_READ_BIT, &stencilMap, &stencilStride); if (!stencilMap) { ctx->Driver.UnmapRenderbuffer(ctx, depthRb); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return GL_TRUE; /* don't bother trying the slow path */ } stencilVals = malloc(width * sizeof(GLubyte)); if (stencilVals) { for (j = 0; j < height; j++) { _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst); _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width, stencilMap, stencilVals); for (i = 0; i < width; i++) { dst[i] = (dst[i] & 0xffffff00) | stencilVals[i]; } depthMap += depthStride; stencilMap += stencilStride; dst += dstStride / 4; } } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); } free(stencilVals); ctx->Driver.UnmapRenderbuffer(ctx, depthRb); ctx->Driver.UnmapRenderbuffer(ctx, stencilRb); return GL_TRUE; }
/** * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the * mapping. */ static GLboolean fast_read_depth_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing ) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; GLubyte *map, *dst; int stride, dstStride, j; if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) return GL_FALSE; if (packing->SwapBytes) return GL_FALSE; if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) return GL_FALSE; if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) || type == GL_UNSIGNED_INT)) return GL_FALSE; ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return GL_TRUE; /* don't bother trying the slow path */ } dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type); dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, GL_DEPTH_COMPONENT, type, 0, 0); for (j = 0; j < height; j++) { if (type == GL_UNSIGNED_INT) { _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst); } else { ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16); memcpy(dst, map, width * 2); } map += stride; dst += dstStride; } ctx->Driver.UnmapRenderbuffer(ctx, rb); return GL_TRUE; }
/** * Return true if memcpy cannot be used for ReadPixels. * * If uses_blit is true, the function returns true if a simple 3D engine blit * cannot be used for ReadPixels packing. * * NOTE: This doesn't take swizzling and format conversions between * the readbuffer and the pixel pack buffer into account. */ GLboolean _mesa_readpixels_needs_slow_path(const struct gl_context *ctx, GLenum format, GLenum type, GLboolean uses_blit) { struct gl_renderbuffer *rb = _mesa_get_read_renderbuffer_for_format(ctx, format); GLenum srcType; ASSERT(rb); /* There are different rules depending on the base format. */ switch (format) { case GL_DEPTH_STENCIL: return !_mesa_has_depthstencil_combined(ctx->ReadBuffer) || ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f || ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag; case GL_DEPTH_COMPONENT: return ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f; case GL_STENCIL_INDEX: return ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag; default: /* Color formats. */ if (need_rgb_to_luminance_conversion(rb->Format, format)) { return GL_TRUE; } /* Conversion between signed and unsigned integers needs masking * (it isn't just memcpy). */ srcType = _mesa_get_format_datatype(rb->Format); if ((srcType == GL_INT && (type == GL_UNSIGNED_INT || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE)) || (srcType == GL_UNSIGNED_INT && (type == GL_INT || type == GL_SHORT || type == GL_BYTE))) { return GL_TRUE; } /* And finally, see if there are any transfer ops. */ return get_readpixels_transfer_ops(ctx, rb->Format, format, type, uses_blit) != 0; } return GL_FALSE; }
/** * Return transfer op flags for this ReadPixels operation. */ GLbitfield _mesa_get_readpixels_transfer_ops(const struct gl_context *ctx, mesa_format texFormat, GLenum format, GLenum type, GLboolean uses_blit) { GLbitfield transferOps = ctx->_ImageTransferState; GLenum srcBaseFormat = _mesa_get_format_base_format(texFormat); GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format); if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL || format == GL_STENCIL_INDEX) { return 0; } /* Pixel transfer ops (scale, bias, table lookup) do not apply * to integer formats. */ if (_mesa_is_enum_format_integer(format)) { return 0; } if (uses_blit) { /* For blit-based ReadPixels packing, the clamping is done automatically * unless the type is float. */ if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) && (type == GL_FLOAT || type == GL_HALF_FLOAT)) { transferOps |= IMAGE_CLAMP_BIT; } } else { /* For CPU-based ReadPixels packing, the clamping must always be done * for non-float types, */ if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) || (type != GL_FLOAT && type != GL_HALF_FLOAT)) { transferOps |= IMAGE_CLAMP_BIT; } } /* If the format is unsigned normalized, we can ignore clamping * because the values are already in the range [0,1] so it won't * have any effect anyway. */ if (_mesa_get_format_datatype(texFormat) == GL_UNSIGNED_NORMALIZED && !_mesa_need_rgb_to_luminance_conversion(srcBaseFormat, dstBaseFormat)) { transferOps &= ~IMAGE_CLAMP_BIT; } return transferOps; }
/** * Helper function for checking if the datatypes of color buffers are * compatible for glBlitFramebuffer. From the 3.1 spec, page 198: * * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT * and any of the following conditions hold: * - The read buffer contains fixed-point or floating-point values and any * draw buffer contains neither fixed-point nor floating-point values. * - The read buffer contains unsigned integer values and any draw buffer * does not contain unsigned integer values. * - The read buffer contains signed integer values and any draw buffer * does not contain signed integer values." */ static GLboolean compatible_color_datatypes(mesa_format srcFormat, mesa_format dstFormat) { GLenum srcType = _mesa_get_format_datatype(srcFormat); GLenum dstType = _mesa_get_format_datatype(dstFormat); if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) { assert(srcType == GL_UNSIGNED_NORMALIZED || srcType == GL_SIGNED_NORMALIZED || srcType == GL_FLOAT); /* Boil any of those types down to GL_FLOAT */ srcType = GL_FLOAT; } if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) { assert(dstType == GL_UNSIGNED_NORMALIZED || dstType == GL_SIGNED_NORMALIZED || dstType == GL_FLOAT); /* Boil any of those types down to GL_FLOAT */ dstType = GL_FLOAT; } return srcType == dstType; }
/** * Determine what type to use (ubyte vs. float) for span colors for the * given renderbuffer. * See also _swrast_write_rgba_span(). */ static void find_renderbuffer_colortype(struct gl_renderbuffer *rb) { struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); GLuint rbMaxBits = _mesa_get_format_max_bits(rb->Format); GLenum rbDatatype = _mesa_get_format_datatype(rb->Format); if (rbDatatype == GL_UNSIGNED_NORMALIZED && rbMaxBits <= 8) { /* the buffer's values fit in GLubyte values */ srb->ColorType = GL_UNSIGNED_BYTE; } else { /* use floats otherwise */ srb->ColorType = GL_FLOAT; } }
static GLenum read_pixels_es3_error_check(GLenum format, GLenum type, const struct gl_renderbuffer *rb) { const GLenum internalFormat = rb->InternalFormat; const GLenum data_type = _mesa_get_format_datatype(rb->Format); GLboolean is_unsigned_int = GL_FALSE; GLboolean is_signed_int = GL_FALSE; if (!_mesa_is_color_format(internalFormat)) { return GL_INVALID_OPERATION; } is_unsigned_int = _mesa_is_enum_format_unsigned_int(internalFormat); if (!is_unsigned_int) { is_signed_int = _mesa_is_enum_format_signed_int(internalFormat); } switch (format) { case GL_RGBA: if (type == GL_FLOAT && data_type == GL_FLOAT) return GL_NO_ERROR; /* EXT_color_buffer_float */ if (type == GL_UNSIGNED_BYTE && data_type == GL_UNSIGNED_NORMALIZED) return GL_NO_ERROR; if (internalFormat == GL_RGB10_A2 && type == GL_UNSIGNED_INT_2_10_10_10_REV) return GL_NO_ERROR; if (internalFormat == GL_RGB10_A2UI && type == GL_UNSIGNED_BYTE) return GL_NO_ERROR; break; case GL_BGRA: /* GL_EXT_read_format_bgra */ if (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT_4_4_4_4_REV || type == GL_UNSIGNED_SHORT_1_5_5_5_REV) return GL_NO_ERROR; break; case GL_RGBA_INTEGER: if ((is_signed_int && type == GL_INT) || (is_unsigned_int && type == GL_UNSIGNED_INT)) return GL_NO_ERROR; break; } return GL_INVALID_OPERATION; }
static bool need_signed_unsigned_int_conversion(mesa_format mesaFormat, GLenum format, GLenum type) { const GLenum mesaFormatType = _mesa_get_format_datatype(mesaFormat); const bool is_format_integer = _mesa_is_enum_format_integer(format); return (mesaFormatType == GL_INT && is_format_integer && (type == GL_UNSIGNED_INT || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE)) || (mesaFormatType == GL_UNSIGNED_INT && is_format_integer && (type == GL_INT || type == GL_SHORT || type == GL_BYTE)); }
/** * Used to answer the GL_IMPLEMENTATION_COLOR_READ_TYPE_OES queries (using * GetIntegerv, GetFramebufferParameteriv, etc) * * If @fb is NULL, the method returns the value for the current bound * framebuffer. */ GLenum _mesa_get_color_read_type(struct gl_context *ctx, struct gl_framebuffer *fb, const char *caller) { if (ctx->NewState) _mesa_update_state(ctx); if (fb == NULL) fb = ctx->ReadBuffer; if (!fb || !fb->_ColorReadBuffer) { /* * See comment on _mesa_get_color_read_format */ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(GL_IMPLEMENTATION_COLOR_READ_TYPE: no GL_READ_BUFFER)", caller); return GL_NONE; } else { const GLenum format = fb->_ColorReadBuffer->Format; const GLenum data_type = _mesa_get_format_datatype(format); if (format == MESA_FORMAT_B5G6R5_UNORM) return GL_UNSIGNED_SHORT_5_6_5; switch (data_type) { case GL_SIGNED_NORMALIZED: return GL_BYTE; case GL_UNSIGNED_INT: case GL_INT: case GL_FLOAT: return data_type; case GL_UNSIGNED_NORMALIZED: default: return GL_UNSIGNED_BYTE; } } }
static boolean needs_integer_signed_unsigned_conversion(const struct gl_context *ctx, GLenum format, GLenum type) { struct gl_renderbuffer *rb = _mesa_get_read_renderbuffer_for_format(ctx, format); assert(rb); GLenum srcType = _mesa_get_format_datatype(rb->Format); if ((srcType == GL_INT && (type == GL_UNSIGNED_INT || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE)) || (srcType == GL_UNSIGNED_INT && (type == GL_INT || type == GL_SHORT || type == GL_BYTE))) { return TRUE; } return FALSE; }
void _mesa_blit_framebuffer(struct gl_context *ctx, struct gl_framebuffer *readFb, struct gl_framebuffer *drawFb, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter, const char *func) { const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); FLUSH_VERTICES(ctx, 0); /* Update completeness status of readFb and drawFb. */ _mesa_update_framebuffer(ctx, readFb, drawFb); /* Make sure drawFb has an initialized bounding box. */ _mesa_update_draw_buffer_bounds(ctx, drawFb); if (!readFb || !drawFb) { /* This will normally never happen but someday we may want to * support MakeCurrent() with no drawables. */ return; } /* check for complete framebuffers */ if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "%s(incomplete draw/read buffers)", func); return; } if (!is_valid_blit_filter(ctx, filter)) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid filter %s)", func, _mesa_enum_to_string(filter)); return; } if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT || filter == GL_SCALED_RESOLVE_NICEST_EXT) && (readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s: invalid samples)", func, _mesa_enum_to_string(filter)); return; } if (mask & ~legalMaskBits) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid mask bits set)", func); return; } /* depth/stencil must be blitted with nearest filtering */ if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) && filter != GL_NEAREST) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(depth/stencil requires GL_NEAREST filter)", func); return; } /* get color read/draw renderbuffers */ if (mask & GL_COLOR_BUFFER_BIT) { const GLuint numColorDrawBuffers = drawFb->_NumColorDrawBuffers; const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; const struct gl_renderbuffer *colorDrawRb = NULL; GLuint i; /* From the EXT_framebuffer_object spec: * * "If a buffer is specified in <mask> and does not exist in both * the read and draw framebuffers, the corresponding bit is silently * ignored." */ if (!colorReadRb || numColorDrawBuffers == 0) { mask &= ~GL_COLOR_BUFFER_BIT; } else { for (i = 0; i < numColorDrawBuffers; i++) { colorDrawRb = drawFb->_ColorDrawBuffers[i]; if (!colorDrawRb) continue; /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL * ES 3.0.1 spec says: * * "If the source and destination buffers are identical, an * INVALID_OPERATION error is generated. Different mipmap * levels of a texture, different layers of a three- * dimensional texture or two-dimensional array texture, and * different faces of a cube map texture do not constitute * identical buffers." */ if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(source and destination color " "buffer cannot be the same)", func); return; } if (!compatible_color_datatypes(colorReadRb->Format, colorDrawRb->Format)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(color buffer datatypes mismatch)", func); return; } /* extra checks for multisample copies... */ if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { /* color formats must match on GLES. This isn't checked on * desktop GL because the GL 4.4 spec was changed to allow it. * In the section entitled “Changes in the released * Specification of July 22, 2013” it says: * * “Relax BlitFramebuffer in section 18.3.1 so that format * conversion can take place during multisample blits, since * drivers already allow this and some apps depend on it.” */ if (_mesa_is_gles(ctx) && !compatible_resolve_formats(colorReadRb, colorDrawRb)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(bad src/dst multisample pixel formats)", func); return; } } } if (filter != GL_NEAREST) { /* From EXT_framebuffer_multisample_blit_scaled specification: * "Calling BlitFramebuffer will result in an INVALID_OPERATION error * if filter is not NEAREST and read buffer contains integer data." */ GLenum type = _mesa_get_format_datatype(colorReadRb->Format); if (type == GL_INT || type == GL_UNSIGNED_INT) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(integer color type)", func); return; } } } } if (mask & GL_STENCIL_BUFFER_BIT) { struct gl_renderbuffer *readRb = readFb->Attachment[BUFFER_STENCIL].Renderbuffer; struct gl_renderbuffer *drawRb = drawFb->Attachment[BUFFER_STENCIL].Renderbuffer; /* From the EXT_framebuffer_object spec: * * "If a buffer is specified in <mask> and does not exist in both * the read and draw framebuffers, the corresponding bit is silently * ignored." */ if ((readRb == NULL) || (drawRb == NULL)) { mask &= ~GL_STENCIL_BUFFER_BIT; } else { int read_z_bits, draw_z_bits; if (_mesa_is_gles3(ctx) && (drawRb == readRb)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(source and destination stencil " "buffer cannot be the same)", func); return; } if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { /* There is no need to check the stencil datatype here, because * there is only one: GL_UNSIGNED_INT. */ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(stencil attachment format mismatch)", func); return; } read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS); draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS); /* If both buffers also have depth data, the depth formats must match * as well. If one doesn't have depth, it's not blitted, so we should * ignore the depth format check. */ if (read_z_bits > 0 && draw_z_bits > 0 && (read_z_bits != draw_z_bits || _mesa_get_format_datatype(readRb->Format) != _mesa_get_format_datatype(drawRb->Format))) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(stencil attachment depth format mismatch)", func); return; } } } if (mask & GL_DEPTH_BUFFER_BIT) { struct gl_renderbuffer *readRb = readFb->Attachment[BUFFER_DEPTH].Renderbuffer; struct gl_renderbuffer *drawRb = drawFb->Attachment[BUFFER_DEPTH].Renderbuffer; /* From the EXT_framebuffer_object spec: * * "If a buffer is specified in <mask> and does not exist in both * the read and draw framebuffers, the corresponding bit is silently * ignored." */ if ((readRb == NULL) || (drawRb == NULL)) { mask &= ~GL_DEPTH_BUFFER_BIT; } else { int read_s_bit, draw_s_bit; if (_mesa_is_gles3(ctx) && (drawRb == readRb)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(source and destination depth " "buffer cannot be the same)", func); return; } if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) || (_mesa_get_format_datatype(readRb->Format) != _mesa_get_format_datatype(drawRb->Format))) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(depth attachment format mismatch)", func); return; } read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS); draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS); /* If both buffers also have stencil data, the stencil formats must * match as well. If one doesn't have stencil, it's not blitted, so * we should ignore the stencil format check. */ if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(depth attachment stencil bits mismatch)", func); return; } } } if (_mesa_is_gles3(ctx)) { /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES * 3.0.1 spec says: * * "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero, * an INVALID_OPERATION error is generated." */ if (drawFb->Visual.samples > 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(destination samples must be 0)", func); return; } /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES * 3.0.1 spec says: * * "If SAMPLE_BUFFERS for the read framebuffer is greater than zero, * no copy is performed and an INVALID_OPERATION error is generated * if the formats of the read and draw framebuffers are not * identical or if the source and destination rectangles are not * defined with the same (X0, Y0) and (X1, Y1) bounds." * * The format check was made above because desktop OpenGL has the same * requirement. */ if (readFb->Visual.samples > 0 && (srcX0 != dstX0 || srcY0 != dstY0 || srcX1 != dstX1 || srcY1 != dstY1)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(bad src/dst multisample region)", func); return; } } else { if (readFb->Visual.samples > 0 && drawFb->Visual.samples > 0 && readFb->Visual.samples != drawFb->Visual.samples) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(mismatched samples)", func); return; } /* extra checks for multisample copies... */ if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) && (filter == GL_NEAREST || filter == GL_LINEAR)) { /* src and dest region sizes must be the same */ if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) || abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(bad src/dst multisample region sizes)", func); return; } } } /* Debug code */ if (DEBUG_BLIT) { const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; const struct gl_renderbuffer *colorDrawRb = NULL; GLuint i = 0; printf("%s(%d, %d, %d, %d, %d, %d, %d, %d," " 0x%x, 0x%x)\n", func, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); if (colorReadRb) { const struct gl_renderbuffer_attachment *att; att = find_attachment(readFb, colorReadRb); printf(" Src FBO %u RB %u (%dx%d) ", readFb->Name, colorReadRb->Name, colorReadRb->Width, colorReadRb->Height); if (att && att->Texture) { printf("Tex %u tgt 0x%x level %u face %u", att->Texture->Name, att->Texture->Target, att->TextureLevel, att->CubeMapFace); } printf("\n"); /* Print all active color render buffers */ for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) { colorDrawRb = drawFb->_ColorDrawBuffers[i]; if (!colorDrawRb) continue; att = find_attachment(drawFb, colorDrawRb); printf(" Dst FBO %u RB %u (%dx%d) ", drawFb->Name, colorDrawRb->Name, colorDrawRb->Width, colorDrawRb->Height); if (att && att->Texture) { printf("Tex %u tgt 0x%x level %u face %u", att->Texture->Name, att->Texture->Target, att->TextureLevel, att->CubeMapFace); } printf("\n"); } } } if (!mask || (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 || (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) { return; } assert(ctx->Driver.BlitFramebuffer); ctx->Driver.BlitFramebuffer(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); }
/** * Bilinear filtered blit (color only, non-integer values). */ static void blit_linear(struct gl_context *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) { struct gl_renderbuffer *readRb = ctx->ReadBuffer->_ColorReadBuffer; struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; const GLint srcWidth = ABS(srcX1 - srcX0); const GLint dstWidth = ABS(dstX1 - dstX0); const GLint srcHeight = ABS(srcY1 - srcY0); const GLint dstHeight = ABS(dstY1 - dstY0); const GLfloat dstHeightF = (GLfloat) dstHeight; const GLint srcXpos = MIN2(srcX0, srcX1); const GLint srcYpos = MIN2(srcY0, srcY1); const GLint dstXpos = MIN2(dstX0, dstX1); const GLint dstYpos = MIN2(dstY0, dstY1); const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); GLint dstRow; GLint pixelSize; GLvoid *srcBuffer0, *srcBuffer1; GLint srcBufferY0 = -1, srcBufferY1 = -1; GLvoid *dstBuffer; gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format); gl_format drawFormat = _mesa_get_srgb_format_linear(drawRb->Format); GLuint bpp = _mesa_get_format_bytes(readFormat); GLenum pixelType; GLubyte *srcMap, *dstMap; GLint srcRowStride, dstRowStride; /* Determine datatype for resampling */ if (_mesa_get_format_max_bits(readFormat) == 8 && _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) { pixelType = GL_UNSIGNED_BYTE; pixelSize = 4 * sizeof(GLubyte); } else { pixelType = GL_FLOAT; pixelSize = 4 * sizeof(GLfloat); } /* Allocate the src/dst row buffers. * Keep two adjacent src rows around for bilinear sampling. */ srcBuffer0 = malloc(pixelSize * srcWidth); if (!srcBuffer0) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } srcBuffer1 = malloc(pixelSize * srcWidth); if (!srcBuffer1) { free(srcBuffer0); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } dstBuffer = malloc(pixelSize * dstWidth); if (!dstBuffer) { free(srcBuffer0); free(srcBuffer1); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } /* * Map src / dst renderbuffers */ if (readRb == drawRb) { /* map whole buffer for read/write */ ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0, readRb->Width, readRb->Height, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, &srcMap, &srcRowStride); if (!srcMap) { free(srcBuffer0); free(srcBuffer1); free(dstBuffer); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); return; } dstMap = srcMap; dstRowStride = srcRowStride; } else { /* different src/dst buffers */ /* XXX with a bit of work we could just map the regions to be * read/written instead of the whole buffers. */ ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0, readRb->Width, readRb->Height, GL_MAP_READ_BIT, &srcMap, &srcRowStride); if (!srcMap) { free(srcBuffer0); free(srcBuffer1); free(dstBuffer); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); return; } ctx->Driver.MapRenderbuffer(ctx, drawRb, 0, 0, drawRb->Width, drawRb->Height, GL_MAP_WRITE_BIT, &dstMap, &dstRowStride); if (!dstMap) { ctx->Driver.UnmapRenderbuffer(ctx, readRb); free(srcBuffer0); free(srcBuffer1); free(dstBuffer); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); return; } } for (dstRow = 0; dstRow < dstHeight; dstRow++) { const GLint dstY = dstYpos + dstRow; const GLfloat srcRow = (dstRow * srcHeight) / dstHeightF; GLint srcRow0 = IFLOOR(srcRow); GLint srcRow1 = srcRow0 + 1; GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */ ASSERT(srcRow >= 0); ASSERT(srcRow < srcHeight); if (srcRow1 == srcHeight) { /* last row fudge */ srcRow1 = srcRow0; rowWeight = 0.0; } if (invertY) { srcRow0 = srcHeight - 1 - srcRow0; srcRow1 = srcHeight - 1 - srcRow1; } srcY0 = srcYpos + srcRow0; srcY1 = srcYpos + srcRow1; /* get the two source rows */ if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) { /* use same source row buffers again */ } else if (srcY0 == srcBufferY1) { /* move buffer1 into buffer0 by swapping pointers */ GLvoid *tmp = srcBuffer0; srcBuffer0 = srcBuffer1; srcBuffer1 = tmp; /* get y1 row */ { GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp; if (pixelType == GL_UNSIGNED_BYTE) { _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, src, srcBuffer1); } else { _mesa_unpack_rgba_row(readFormat, srcWidth, src, srcBuffer1); } } srcBufferY0 = srcY0; srcBufferY1 = srcY1; } else { /* get both new rows */ { GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp; GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp; if (pixelType == GL_UNSIGNED_BYTE) { _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, src0, srcBuffer0); _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, src1, srcBuffer1); } else { _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0); _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1); } } srcBufferY0 = srcY0; srcBufferY1 = srcY1; } if (pixelType == GL_UNSIGNED_BYTE) { resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1, dstBuffer, invertX, rowWeight); } else { resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1, dstBuffer, invertX, rowWeight); } /* store pixel row in destination */ { GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp; if (pixelType == GL_UNSIGNED_BYTE) { _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst); } else { _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst); } } } free(srcBuffer0); free(srcBuffer1); free(dstBuffer); ctx->Driver.UnmapRenderbuffer(ctx, readRb); if (drawRb != readRb) { ctx->Driver.UnmapRenderbuffer(ctx, drawRb); } }
/** * Software fallback for generate mipmap levels. */ static void fallback_generate_mipmap(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj) { struct pipe_context *pipe = st_context(ctx)->pipe; struct pipe_resource *pt = st_get_texobj_resource(texObj); const uint baseLevel = texObj->BaseLevel; const uint lastLevel = pt->last_level; const uint face = _mesa_tex_target_to_face(target); uint dstLevel; GLenum datatype; GLuint comps; GLboolean compressed; if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback processing\n", __FUNCTION__); assert(target != GL_TEXTURE_3D); /* not done yet */ compressed = _mesa_is_format_compressed(texObj->Image[face][baseLevel]->TexFormat); if (compressed) { GLenum type = _mesa_get_format_datatype(texObj->Image[face][baseLevel]->TexFormat); datatype = type == GL_UNSIGNED_NORMALIZED ? GL_UNSIGNED_BYTE : GL_FLOAT; comps = 4; } else { _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat, &datatype, &comps); assert(comps > 0 && "bad texture format in fallback_generate_mipmap()"); } for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { const uint srcLevel = dstLevel - 1; const uint srcWidth = u_minify(pt->width0, srcLevel); const uint srcHeight = u_minify(pt->height0, srcLevel); const uint srcDepth = u_minify(pt->depth0, srcLevel); const uint dstWidth = u_minify(pt->width0, dstLevel); const uint dstHeight = u_minify(pt->height0, dstLevel); const uint dstDepth = u_minify(pt->depth0, dstLevel); struct pipe_transfer *srcTrans, *dstTrans; const ubyte *srcData; ubyte *dstData; int srcStride, dstStride; srcTrans = pipe_get_transfer(pipe, pt, srcLevel, face, PIPE_TRANSFER_READ, 0, 0, srcWidth, srcHeight); dstTrans = pipe_get_transfer(pipe, pt, dstLevel, face, PIPE_TRANSFER_WRITE, 0, 0, dstWidth, dstHeight); srcData = (ubyte *) pipe_transfer_map(pipe, srcTrans); dstData = (ubyte *) pipe_transfer_map(pipe, dstTrans); srcStride = srcTrans->stride / util_format_get_blocksize(srcTrans->resource->format); dstStride = dstTrans->stride / util_format_get_blocksize(dstTrans->resource->format); /* this cannot work correctly for 3d since it does not respect layerStride. */ if (compressed) { const enum pipe_format format = pt->format; const uint bw = util_format_get_blockwidth(format); const uint bh = util_format_get_blockheight(format); const uint srcWidth2 = align(srcWidth, bw); const uint srcHeight2 = align(srcHeight, bh); const uint dstWidth2 = align(dstWidth, bw); const uint dstHeight2 = align(dstHeight, bh); uint8_t *srcTemp, *dstTemp; assert(comps == 4); srcTemp = malloc(srcWidth2 * srcHeight2 * comps * (datatype == GL_FLOAT ? 4 : 1)); dstTemp = malloc(dstWidth2 * dstHeight2 * comps * (datatype == GL_FLOAT ? 4 : 1)); /* decompress the src image: srcData -> srcTemp */ decompress_image(format, datatype, srcData, srcTemp, srcWidth2, srcHeight2, srcTrans->stride); _mesa_generate_mipmap_level(target, datatype, comps, 0 /*border*/, srcWidth2, srcHeight2, srcDepth, srcTemp, srcWidth2, /* stride in texels */ dstWidth2, dstHeight2, dstDepth, dstTemp, dstWidth2); /* stride in texels */ /* compress the new image: dstTemp -> dstData */ compress_image(format, datatype, dstTemp, dstData, dstWidth2, dstHeight2, dstTrans->stride); free(srcTemp); free(dstTemp); } else { _mesa_generate_mipmap_level(target, datatype, comps, 0 /*border*/, srcWidth, srcHeight, srcDepth, srcData, srcStride, /* stride in texels */ dstWidth, dstHeight, dstDepth, dstData, dstStride); /* stride in texels */ } pipe_transfer_unmap(pipe, srcTrans); pipe_transfer_unmap(pipe, dstTrans); pipe->transfer_destroy(pipe, srcTrans); pipe->transfer_destroy(pipe, dstTrans); } }
/** * Convert the given color to a bitfield suitable for ORing into DWORD 7 of * SURFACE_STATE (DWORD 12-15 on SKL+). */ union isl_color_value brw_meta_convert_fast_clear_color(const struct brw_context *brw, const struct intel_mipmap_tree *mt, const union gl_color_union *color) { union isl_color_value override_color = { .u32 = { color->ui[0], color->ui[1], color->ui[2], color->ui[3], }, }; /* The sampler doesn't look at the format of the surface when the fast * clear color is used so we need to implement luminance, intensity and * missing components manually. */ switch (_mesa_get_format_base_format(mt->format)) { case GL_INTENSITY: override_color.u32[3] = override_color.u32[0]; /* flow through */ case GL_LUMINANCE: case GL_LUMINANCE_ALPHA: override_color.u32[1] = override_color.u32[0]; override_color.u32[2] = override_color.u32[0]; break; default: for (int i = 0; i < 3; i++) { if (!_mesa_format_has_color_component(mt->format, i)) override_color.u32[i] = 0; } break; } switch (_mesa_get_format_datatype(mt->format)) { case GL_UNSIGNED_NORMALIZED: for (int i = 0; i < 4; i++) override_color.f32[i] = CLAMP(override_color.f32[i], 0.0f, 1.0f); break; case GL_SIGNED_NORMALIZED: for (int i = 0; i < 4; i++) override_color.f32[i] = CLAMP(override_color.f32[i], -1.0f, 1.0f); break; case GL_UNSIGNED_INT: for (int i = 0; i < 4; i++) { unsigned bits = _mesa_get_format_bits(mt->format, GL_RED_BITS + i); if (bits < 32) { uint32_t max = (1u << bits) - 1; override_color.u32[i] = MIN2(override_color.u32[i], max); } } break; case GL_INT: for (int i = 0; i < 4; i++) { unsigned bits = _mesa_get_format_bits(mt->format, GL_RED_BITS + i); if (bits < 32) { int32_t max = (1 << (bits - 1)) - 1; int32_t min = -(1 << (bits - 1)); override_color.i32[i] = CLAMP(override_color.i32[i], min, max); } } break; case GL_FLOAT: if (!_mesa_is_format_signed(mt->format)) { for (int i = 0; i < 4; i++) override_color.f32[i] = MAX2(override_color.f32[i], 0.0f); } break; } if (!_mesa_format_has_color_component(mt->format, 3)) { if (_mesa_is_format_integer_color(mt->format)) override_color.u32[3] = 1; else override_color.f32[3] = 1.0f; } /* Handle linear to SRGB conversion */ if (brw->ctx.Color.sRGBEnabled && _mesa_get_srgb_format_linear(mt->format) != mt->format) { for (int i = 0; i < 3; i++) { override_color.f32[i] = util_format_linear_to_srgb_float(override_color.f32[i]); } } return override_color; }
/** * The glGet queries of the framebuffer red/green/blue size, stencil size, * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can * change depending on the renderbuffer bindings. This function updates * the given framebuffer's Visual from the current renderbuffer bindings. * * This may apply to user-created framebuffers or window system framebuffers. * * Also note: ctx->DrawBuffer->Visual.depthBits might not equal * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits. * The former one is used to convert floating point depth values into * integer Z values. */ void _mesa_update_framebuffer_visual(struct gl_context *ctx, struct gl_framebuffer *fb) { GLuint i; memset(&fb->Visual, 0, sizeof(fb->Visual)); fb->Visual.rgbMode = GL_TRUE; /* assume this */ /* find first RGB renderbuffer */ for (i = 0; i < BUFFER_COUNT; i++) { if (fb->Attachment[i].Renderbuffer) { const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); const mesa_format fmt = rb->Format; /* Grab samples and sampleBuffers from any attachment point (assuming * the framebuffer is complete, we'll get the same answer from all * attachments). */ fb->Visual.samples = rb->NumSamples; fb->Visual.sampleBuffers = rb->NumSamples > 0 ? 1 : 0; if (_mesa_is_legal_color_format(ctx, baseFormat)) { fb->Visual.redBits = _mesa_get_format_bits(fmt, GL_RED_BITS); fb->Visual.greenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); fb->Visual.blueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); fb->Visual.alphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); fb->Visual.rgbBits = fb->Visual.redBits + fb->Visual.greenBits + fb->Visual.blueBits; if (_mesa_get_format_color_encoding(fmt) == GL_SRGB) fb->Visual.sRGBCapable = ctx->Extensions.EXT_framebuffer_sRGB; break; } } } fb->Visual.floatMode = GL_FALSE; for (i = 0; i < BUFFER_COUNT; i++) { if (fb->Attachment[i].Renderbuffer) { const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; const mesa_format fmt = rb->Format; if (_mesa_get_format_datatype(fmt) == GL_FLOAT) { fb->Visual.floatMode = GL_TRUE; break; } } } if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { const struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; const mesa_format fmt = rb->Format; fb->Visual.haveDepthBuffer = GL_TRUE; fb->Visual.depthBits = _mesa_get_format_bits(fmt, GL_DEPTH_BITS); } if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { const struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; const mesa_format fmt = rb->Format; fb->Visual.haveStencilBuffer = GL_TRUE; fb->Visual.stencilBits = _mesa_get_format_bits(fmt, GL_STENCIL_BITS); } if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) { const struct gl_renderbuffer *rb = fb->Attachment[BUFFER_ACCUM].Renderbuffer; const mesa_format fmt = rb->Format; fb->Visual.haveAccumBuffer = GL_TRUE; fb->Visual.accumRedBits = _mesa_get_format_bits(fmt, GL_RED_BITS); fb->Visual.accumGreenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); fb->Visual.accumBlueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); fb->Visual.accumAlphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); } compute_depth_max(fb); }
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 void setup_glsl_msaa_blit_shader(struct gl_context *ctx, struct blit_state *blit, const struct gl_framebuffer *drawFb, struct gl_renderbuffer *src_rb, GLenum target) { const char *vs_source; char *fs_source; void *mem_ctx; enum blit_msaa_shader shader_index; bool dst_is_msaa = false; GLenum src_datatype; const char *vec4_prefix; const char *sampler_array_suffix = ""; char *name; const char *texcoord_type = "vec2"; int samples; int shader_offset = 0; if (src_rb) { samples = MAX2(src_rb->NumSamples, 1); src_datatype = _mesa_get_format_datatype(src_rb->Format); } else { /* depth-or-color glCopyTexImage fallback path that passes a NULL rb and * doesn't handle integer. */ samples = 1; src_datatype = GL_UNSIGNED_NORMALIZED; } /* We expect only power of 2 samples in source multisample buffer. */ assert(samples > 0 && _mesa_is_pow_two(samples)); while (samples >> (shader_offset + 1)) { shader_offset++; } /* Update the assert if we plan to support more than 16X MSAA. */ assert(shader_offset >= 0 && shader_offset <= 4); if (drawFb->Visual.samples > 1) { /* If you're calling meta_BlitFramebuffer with the destination * multisampled, this is the only path that will work -- swrast and * CopyTexImage won't work on it either. */ assert(ctx->Extensions.ARB_sample_shading); dst_is_msaa = true; /* We need shader invocation per sample, not per pixel */ _mesa_set_enable(ctx, GL_MULTISAMPLE, GL_TRUE); _mesa_set_enable(ctx, GL_SAMPLE_SHADING, GL_TRUE); _mesa_MinSampleShading(1.0); } switch (target) { case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: if (src_rb && (src_rb->_BaseFormat == GL_DEPTH_COMPONENT || src_rb->_BaseFormat == GL_DEPTH_STENCIL)) { if (dst_is_msaa) shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_COPY; else shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_RESOLVE; } else { if (dst_is_msaa) shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_COPY; else { shader_index = BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + shader_offset; } } if (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { shader_index += (BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_RESOLVE - BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE); sampler_array_suffix = "Array"; texcoord_type = "vec3"; } break; default: _mesa_problem(ctx, "Unkown texture target %s\n", _mesa_enum_to_string(target)); shader_index = BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE; } /* We rely on the enum being sorted this way. */ STATIC_ASSERT(BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_INT == BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 5); STATIC_ASSERT(BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_UINT == BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 10); if (src_datatype == GL_INT) { shader_index += 5; vec4_prefix = "i"; } else if (src_datatype == GL_UNSIGNED_INT) { shader_index += 10; vec4_prefix = "u"; } else { vec4_prefix = ""; } if (blit->msaa_shaders[shader_index]) { _mesa_UseProgram(blit->msaa_shaders[shader_index]); return; } mem_ctx = ralloc_context(NULL); if (shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_RESOLVE || shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_DEPTH_RESOLVE || shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_DEPTH_COPY || shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_COPY) { char *sample_index; const char *arb_sample_shading_extension_string; if (dst_is_msaa) { arb_sample_shading_extension_string = "#extension GL_ARB_sample_shading : enable"; sample_index = "gl_SampleID"; name = "depth MSAA copy"; } else { /* Don't need that extension, since we're drawing to a single-sampled * destination. */ arb_sample_shading_extension_string = ""; /* From the GL 4.3 spec: * * "If there is a multisample buffer (the value of SAMPLE_BUFFERS * is one), then values are obtained from the depth samples in * this buffer. It is recommended that the depth value of the * centermost sample be used, though implementations may choose * any function of the depth sample values at each pixel. * * We're slacking and instead of choosing centermost, we've got 0. */ sample_index = "0"; name = "depth MSAA resolve"; } vs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "in vec2 position;\n" "in %s textureCoords;\n" "out %s texCoords;\n" "void main()\n" "{\n" " texCoords = textureCoords;\n" " gl_Position = vec4(position, 0.0, 1.0);\n" "}\n", texcoord_type, texcoord_type); fs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "#extension GL_ARB_texture_multisample : enable\n" "%s\n" "uniform sampler2DMS%s texSampler;\n" "in %s texCoords;\n" "out vec4 out_color;\n" "\n" "void main()\n" "{\n" " gl_FragDepth = texelFetch(texSampler, i%s(texCoords), %s).r;\n" "}\n", arb_sample_shading_extension_string, sampler_array_suffix, texcoord_type, texcoord_type, sample_index); } else { /* You can create 2D_MULTISAMPLE textures with 0 sample count (meaning 1 * sample). Yes, this is ridiculous. */ char *sample_resolve; const char *arb_sample_shading_extension_string; const char *merge_function; name = ralloc_asprintf(mem_ctx, "%svec4 MSAA %s", vec4_prefix, dst_is_msaa ? "copy" : "resolve"); if (dst_is_msaa) { arb_sample_shading_extension_string = "#extension GL_ARB_sample_shading : enable"; sample_resolve = ralloc_asprintf(mem_ctx, " out_color = texelFetch(texSampler, i%s(texCoords), gl_SampleID);", texcoord_type); merge_function = ""; } else { int i; int step; if (src_datatype == GL_INT || src_datatype == GL_UNSIGNED_INT) { merge_function = "gvec4 merge(gvec4 a, gvec4 b) { return (a >> gvec4(1)) + (b >> gvec4(1)) + (a & b & gvec4(1)); }\n"; } else { /* The divide will happen at the end for floats. */ merge_function = "vec4 merge(vec4 a, vec4 b) { return (a + b); }\n"; } arb_sample_shading_extension_string = ""; /* We're assuming power of two samples for this resolution procedure. * * To avoid losing any floating point precision if the samples all * happen to have the same value, we merge pairs of values at a time * (so the floating point exponent just gets increased), rather than * doing a naive sum and dividing. */ assert(_mesa_is_pow_two(samples)); /* Fetch each individual sample. */ sample_resolve = rzalloc_size(mem_ctx, 1); for (i = 0; i < samples; i++) { ralloc_asprintf_append(&sample_resolve, " gvec4 sample_1_%d = texelFetch(texSampler, i%s(texCoords), %d);\n", i, texcoord_type, i); } /* Now, merge each pair of samples, then merge each pair of those, * etc. */ for (step = 2; step <= samples; step *= 2) { for (i = 0; i < samples; i += step) { ralloc_asprintf_append(&sample_resolve, " gvec4 sample_%d_%d = merge(sample_%d_%d, sample_%d_%d);\n", step, i, step / 2, i, step / 2, i + step / 2); } } /* Scale the final result. */ if (src_datatype == GL_UNSIGNED_INT || src_datatype == GL_INT) { ralloc_asprintf_append(&sample_resolve, " out_color = sample_%d_0;\n", samples); } else { ralloc_asprintf_append(&sample_resolve, " gl_FragColor = sample_%d_0 / %f;\n", samples, (float)samples); } } vs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "in vec2 position;\n" "in %s textureCoords;\n" "out %s texCoords;\n" "void main()\n" "{\n" " texCoords = textureCoords;\n" " gl_Position = vec4(position, 0.0, 1.0);\n" "}\n", texcoord_type, texcoord_type); fs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "#extension GL_ARB_texture_multisample : enable\n" "%s\n" "#define gvec4 %svec4\n" "uniform %ssampler2DMS%s texSampler;\n" "in %s texCoords;\n" "out gvec4 out_color;\n" "\n" "%s" /* merge_function */ "void main()\n" "{\n" "%s\n" /* sample_resolve */ "}\n", arb_sample_shading_extension_string, vec4_prefix, vec4_prefix, sampler_array_suffix, texcoord_type, merge_function, sample_resolve); } _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source, name, &blit->msaa_shaders[shader_index]); ralloc_free(mem_ctx); }
static GLenum read_pixels_es3_error_check(GLenum format, GLenum type, const struct gl_renderbuffer *rb) { const GLenum internalFormat = rb->InternalFormat; const GLenum data_type = _mesa_get_format_datatype(rb->Format); GLboolean is_unsigned_int = GL_FALSE; GLboolean is_signed_int = GL_FALSE; GLboolean is_float_depth = (internalFormat == GL_DEPTH_COMPONENT32F) || (internalFormat == GL_DEPTH32F_STENCIL8); is_unsigned_int = _mesa_is_enum_format_unsigned_int(internalFormat); if (!is_unsigned_int) { is_signed_int = _mesa_is_enum_format_signed_int(internalFormat); } switch (format) { case GL_RGBA: if (type == GL_FLOAT && data_type == GL_FLOAT) return GL_NO_ERROR; /* EXT_color_buffer_float */ if (type == GL_UNSIGNED_BYTE && data_type == GL_UNSIGNED_NORMALIZED) return GL_NO_ERROR; if (internalFormat == GL_RGB10_A2 && type == GL_UNSIGNED_INT_2_10_10_10_REV) return GL_NO_ERROR; if (internalFormat == GL_RGB10_A2UI && type == GL_UNSIGNED_BYTE) return GL_NO_ERROR; break; case GL_BGRA: /* GL_EXT_read_format_bgra */ if (type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT_4_4_4_4_REV || type == GL_UNSIGNED_SHORT_1_5_5_5_REV) return GL_NO_ERROR; break; case GL_RGBA_INTEGER: if ((is_signed_int && type == GL_INT) || (is_unsigned_int && type == GL_UNSIGNED_INT)) return GL_NO_ERROR; break; case GL_DEPTH_STENCIL: switch (type) { case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: if (is_float_depth) return GL_NO_ERROR; break; case GL_UNSIGNED_INT_24_8: if (!is_float_depth) return GL_NO_ERROR; break; default: return GL_INVALID_ENUM; } break; case GL_DEPTH_COMPONENT: switch (type) { case GL_FLOAT: if (is_float_depth) return GL_NO_ERROR; break; case GL_UNSIGNED_SHORT: case GL_UNSIGNED_INT: case GL_UNSIGNED_INT_24_8: if (!is_float_depth) return GL_NO_ERROR; break; default: return GL_INVALID_ENUM; } break; case GL_STENCIL_INDEX: switch (type) { case GL_UNSIGNED_BYTE: return GL_NO_ERROR; default: return GL_INVALID_ENUM; } break; } return GL_INVALID_OPERATION; }
static void gen6_upload_blend_state(struct brw_context *brw) { bool is_buffer_zero_integer_format = false; struct gl_context *ctx = &brw->intel.ctx; struct gen6_blend_state *blend; int b; int nr_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers; int size; /* We need at least one BLEND_STATE written, because we might do * thread dispatch even if _NumColorDrawBuffers is 0 (for example * for computed depth or alpha test), which will do an FB write * with render target 0, which will reference BLEND_STATE[0] for * alpha test enable. */ if (nr_draw_buffers == 0 && ctx->Color.AlphaEnabled) nr_draw_buffers = 1; size = sizeof(*blend) * nr_draw_buffers; blend = brw_state_batch(brw, AUB_TRACE_BLEND_STATE, size, 64, &brw->cc.blend_state_offset); memset(blend, 0, size); for (b = 0; b < nr_draw_buffers; b++) { /* _NEW_BUFFERS */ struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[b]; GLenum rb_type; bool integer; if (rb) rb_type = _mesa_get_format_datatype(rb->Format); else rb_type = GL_UNSIGNED_NORMALIZED; /* Used for implementing the following bit of GL_EXT_texture_integer: * "Per-fragment operations that require floating-point color * components, including multisample alpha operations, alpha test, * blending, and dithering, have no effect when the corresponding * colors are written to an integer color buffer." */ integer = (rb_type == GL_INT || rb_type == GL_UNSIGNED_INT); if(b == 0 && integer) is_buffer_zero_integer_format = true; /* _NEW_COLOR */ if (ctx->Color.ColorLogicOpEnabled) { /* Floating point RTs should have no effect from LogicOp, * except for disabling of blending, but other types should. * * However, from the Sandy Bridge PRM, Vol 2 Par 1, Section 8.1.11, * "Logic Ops", * * "Logic Ops are only supported on *_UNORM surfaces (excluding * _SRGB variants), otherwise Logic Ops must be DISABLED." */ WARN_ONCE(ctx->Color.LogicOp != GL_COPY && rb_type != GL_UNSIGNED_NORMALIZED && rb_type != GL_FLOAT, "Ignoring %s logic op on %s " "renderbuffer\n", _mesa_lookup_enum_by_nr(ctx->Color.LogicOp), _mesa_lookup_enum_by_nr(rb_type)); if (rb_type == GL_UNSIGNED_NORMALIZED) { blend[b].blend1.logic_op_enable = 1; blend[b].blend1.logic_op_func = intel_translate_logic_op(ctx->Color.LogicOp); } } else if (ctx->Color.BlendEnabled & (1 << b) && !integer) { GLenum eqRGB = ctx->Color.Blend[b].EquationRGB; GLenum eqA = ctx->Color.Blend[b].EquationA; GLenum srcRGB = ctx->Color.Blend[b].SrcRGB; GLenum dstRGB = ctx->Color.Blend[b].DstRGB; GLenum srcA = ctx->Color.Blend[b].SrcA; GLenum dstA = ctx->Color.Blend[b].DstA; if (eqRGB == GL_MIN || eqRGB == GL_MAX) { srcRGB = dstRGB = GL_ONE; } if (eqA == GL_MIN || eqA == GL_MAX) { srcA = dstA = GL_ONE; } blend[b].blend0.dest_blend_factor = brw_translate_blend_factor(dstRGB); blend[b].blend0.source_blend_factor = brw_translate_blend_factor(srcRGB); blend[b].blend0.blend_func = brw_translate_blend_equation(eqRGB); blend[b].blend0.ia_dest_blend_factor = brw_translate_blend_factor(dstA); blend[b].blend0.ia_source_blend_factor = brw_translate_blend_factor(srcA); blend[b].blend0.ia_blend_func = brw_translate_blend_equation(eqA); blend[b].blend0.blend_enable = 1; blend[b].blend0.ia_blend_enable = (srcA != srcRGB || dstA != dstRGB || eqA != eqRGB); } /* See section 8.1.6 "Pre-Blend Color Clamping" of the * SandyBridge PRM Volume 2 Part 1 for HW requirements. * * We do our ARB_color_buffer_float CLAMP_FRAGMENT_COLOR * clamping in the fragment shader. For its clamping of * blending, the spec says: * * "RESOLVED: For fixed-point color buffers, the inputs and * the result of the blending equation are clamped. For * floating-point color buffers, no clamping occurs." * * So, generally, we want clamping to the render target's range. * And, good news, the hardware tables for both pre- and * post-blend color clamping are either ignored, or any are * allowed, or clamping is required but RT range clamping is a * valid option. */ blend[b].blend1.pre_blend_clamp_enable = 1; blend[b].blend1.post_blend_clamp_enable = 1; blend[b].blend1.clamp_range = BRW_RENDERTARGET_CLAMPRANGE_FORMAT; /* _NEW_COLOR */ if (ctx->Color.AlphaEnabled && !integer) { blend[b].blend1.alpha_test_enable = 1; blend[b].blend1.alpha_test_func = intel_translate_compare_func(ctx->Color.AlphaFunc); } /* _NEW_COLOR */ if (ctx->Color.DitherFlag && !integer) { blend[b].blend1.dither_enable = 1; blend[b].blend1.y_dither_offset = 0; blend[b].blend1.x_dither_offset = 0; } blend[b].blend1.write_disable_r = !ctx->Color.ColorMask[b][0]; blend[b].blend1.write_disable_g = !ctx->Color.ColorMask[b][1]; blend[b].blend1.write_disable_b = !ctx->Color.ColorMask[b][2]; blend[b].blend1.write_disable_a = !ctx->Color.ColorMask[b][3]; /* OpenGL specification 3.3 (page 196), section 4.1.3 says: * "If drawbuffer zero is not NONE and the buffer it references has an * integer format, the SAMPLE_ALPHA_TO_COVERAGE and SAMPLE_ALPHA_TO_ONE * operations are skipped." */ if(!is_buffer_zero_integer_format) { /* _NEW_MULTISAMPLE */ blend[b].blend1.alpha_to_coverage = ctx->Multisample._Enabled && ctx->Multisample.SampleAlphaToCoverage; /* From SandyBridge PRM, volume 2 Part 1, section 8.2.3, BLEND_STATE: * DWord 1, Bit 30 (AlphaToOne Enable): * "If Dual Source Blending is enabled, this bit must be disabled" */ WARN_ONCE(ctx->Color.Blend[b]._UsesDualSrc && ctx->Multisample._Enabled && ctx->Multisample.SampleAlphaToOne, "HW workaround: disabling alpha to one with dual src " "blending\n"); if (ctx->Color.Blend[b]._UsesDualSrc) blend[b].blend1.alpha_to_one = false; else blend[b].blend1.alpha_to_one = ctx->Multisample._Enabled && ctx->Multisample.SampleAlphaToOne; blend[b].blend1.alpha_to_coverage_dither = (brw->intel.gen >= 7); } else { blend[b].blend1.alpha_to_coverage = false; blend[b].blend1.alpha_to_one = false; } } brw->state.dirty.cache |= CACHE_NEW_BLEND_STATE; }
void GLAPIENTRY _mesa_GetTexLevelParameteriv( GLenum target, GLint level, GLenum pname, GLint *params ) { struct gl_texture_object *texObj; const struct gl_texture_image *img = NULL; GLint maxLevels; gl_format texFormat; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); /* this will catch bad target values */ maxLevels = _mesa_max_texture_levels(ctx, target); if (maxLevels == 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(target=0x%x)", target); return; } if (level < 0 || level >= maxLevels) { _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexLevelParameter[if]v" ); return; } texObj = _mesa_select_tex_object(ctx, target); img = _mesa_select_tex_image(ctx, texObj, target, level); if (!img || img->TexFormat == MESA_FORMAT_NONE) { /* undefined texture image */ if (pname == GL_TEXTURE_COMPONENTS) *params = 1; else *params = 0; return; } texFormat = img->TexFormat; switch (pname) { case GL_TEXTURE_WIDTH: *params = img->Width; break; case GL_TEXTURE_HEIGHT: *params = img->Height; break; case GL_TEXTURE_DEPTH: *params = img->Depth; break; case GL_TEXTURE_INTERNAL_FORMAT: *params = img->InternalFormat; break; case GL_TEXTURE_BORDER: *params = img->Border; break; case GL_TEXTURE_RED_SIZE: case GL_TEXTURE_GREEN_SIZE: case GL_TEXTURE_BLUE_SIZE: case GL_TEXTURE_ALPHA_SIZE: if (_mesa_base_format_has_channel(img->_BaseFormat, pname)) *params = _mesa_get_format_bits(texFormat, pname); else *params = 0; break; case GL_TEXTURE_INTENSITY_SIZE: case GL_TEXTURE_LUMINANCE_SIZE: if (_mesa_base_format_has_channel(img->_BaseFormat, pname)) { *params = _mesa_get_format_bits(texFormat, pname); if (*params == 0) { /* intensity or luminance is probably stored as RGB[A] */ *params = MIN2(_mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE), _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE)); } } else { *params = 0; } break; /* GL_ARB_texture_float */ case GL_TEXTURE_RED_TYPE_ARB: case GL_TEXTURE_GREEN_TYPE_ARB: case GL_TEXTURE_BLUE_TYPE_ARB: case GL_TEXTURE_ALPHA_TYPE_ARB: case GL_TEXTURE_LUMINANCE_TYPE_ARB: case GL_TEXTURE_INTENSITY_TYPE_ARB: case GL_TEXTURE_DEPTH_TYPE_ARB: if (!ctx->Extensions.ARB_texture_float) goto invalid_pname; if (_mesa_base_format_has_channel(img->_BaseFormat, pname)) *params = _mesa_get_format_datatype(texFormat); else *params = GL_NONE; break; default: goto invalid_pname; } /* no error if we get here */ return; invalid_pname: _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname=%s)", _mesa_lookup_enum_by_nr(pname)); }
static void prepare_blend_state(struct brw_context *brw) { struct gl_context *ctx = &brw->intel.ctx; struct gen6_blend_state *blend; int b; int nr_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers; int size; /* We need at least one BLEND_STATE written, because we might do * thread dispatch even if _NumColorDrawBuffers is 0 (for example * for computed depth or alpha test), which will do an FB write * with render target 0, which will reference BLEND_STATE[0] for * alpha test enable. */ if (nr_draw_buffers == 0 && ctx->Color.AlphaEnabled) nr_draw_buffers = 1; size = sizeof(*blend) * nr_draw_buffers; blend = brw_state_batch(brw, AUB_TRACE_BLEND_STATE, size, 64, &brw->cc.blend_state_offset); memset(blend, 0, size); for (b = 0; b < nr_draw_buffers; b++) { /* _NEW_COLOR */ if (ctx->Color._LogicOpEnabled) { struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[b]; /* _NEW_BUFFERS */ /* Floating point RTs should have no effect from LogicOp, * except for disabling of blending */ if (_mesa_get_format_datatype(rb->Format) != GL_FLOAT) { blend[b].blend1.logic_op_enable = 1; blend[b].blend1.logic_op_func = intel_translate_logic_op(ctx->Color.LogicOp); } } else if (ctx->Color.BlendEnabled & (1 << b)) { GLenum eqRGB = ctx->Color.Blend[0].EquationRGB; GLenum eqA = ctx->Color.Blend[0].EquationA; GLenum srcRGB = ctx->Color.Blend[0].SrcRGB; GLenum dstRGB = ctx->Color.Blend[0].DstRGB; GLenum srcA = ctx->Color.Blend[0].SrcA; GLenum dstA = ctx->Color.Blend[0].DstA; if (eqRGB == GL_MIN || eqRGB == GL_MAX) { srcRGB = dstRGB = GL_ONE; } if (eqA == GL_MIN || eqA == GL_MAX) { srcA = dstA = GL_ONE; } blend[b].blend0.dest_blend_factor = brw_translate_blend_factor(dstRGB); blend[b].blend0.source_blend_factor = brw_translate_blend_factor(srcRGB); blend[b].blend0.blend_func = brw_translate_blend_equation(eqRGB); blend[b].blend0.ia_dest_blend_factor = brw_translate_blend_factor(dstA); blend[b].blend0.ia_source_blend_factor = brw_translate_blend_factor(srcA); blend[b].blend0.ia_blend_func = brw_translate_blend_equation(eqA); blend[b].blend0.blend_enable = 1; blend[b].blend0.ia_blend_enable = (srcA != srcRGB || dstA != dstRGB || eqA != eqRGB); } /* _NEW_COLOR */ if (ctx->Color.AlphaEnabled) { blend[b].blend1.alpha_test_enable = 1; blend[b].blend1.alpha_test_func = intel_translate_compare_func(ctx->Color.AlphaFunc); } /* _NEW_COLOR */ if (ctx->Color.DitherFlag) { blend[b].blend1.dither_enable = 1; blend[b].blend1.y_dither_offset = 0; blend[b].blend1.x_dither_offset = 0; } blend[b].blend1.write_disable_r = !ctx->Color.ColorMask[b][0]; blend[b].blend1.write_disable_g = !ctx->Color.ColorMask[b][1]; blend[b].blend1.write_disable_b = !ctx->Color.ColorMask[b][2]; blend[b].blend1.write_disable_a = !ctx->Color.ColorMask[b][3]; } brw->state.dirty.cache |= CACHE_NEW_BLEND_STATE; }
/** * The glGet queries of the framebuffer red/green/blue size, stencil size, * etc. are satisfied by the fields of ctx->DrawBuffer->Visual. These can * change depending on the renderbuffer bindings. This function updates * the given framebuffer's Visual from the current renderbuffer bindings. * * This may apply to user-created framebuffers or window system framebuffers. * * Also note: ctx->DrawBuffer->Visual.depthBits might not equal * ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer.DepthBits. * The former one is used to convert floating point depth values into * integer Z values. */ void _mesa_update_framebuffer_visual(struct gl_context *ctx, struct gl_framebuffer *fb) { GLuint i; memset(&fb->Visual, 0, sizeof(fb->Visual)); fb->Visual.rgbMode = GL_TRUE; /* assume this */ #if 0 /* this _might_ be needed */ if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { /* leave visual fields zero'd */ return; } #endif /* find first RGB renderbuffer */ for (i = 0; i < BUFFER_COUNT; i++) { if (fb->Attachment[i].Renderbuffer) { const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); const gl_format fmt = rb->Format; if (_mesa_is_legal_color_format(ctx, baseFormat)) { fb->Visual.redBits = _mesa_get_format_bits(fmt, GL_RED_BITS); fb->Visual.greenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); fb->Visual.blueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); fb->Visual.alphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); fb->Visual.rgbBits = fb->Visual.redBits + fb->Visual.greenBits + fb->Visual.blueBits; fb->Visual.samples = rb->NumSamples; fb->Visual.sampleBuffers = rb->NumSamples > 0 ? 1 : 0; if (_mesa_get_format_color_encoding(fmt) == GL_SRGB) fb->Visual.sRGBCapable = ctx->Const.sRGBCapable; break; } } } fb->Visual.floatMode = GL_FALSE; for (i = 0; i < BUFFER_COUNT; i++) { if (fb->Attachment[i].Renderbuffer) { const struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer; const gl_format fmt = rb->Format; if (_mesa_get_format_datatype(fmt) == GL_FLOAT) { fb->Visual.floatMode = GL_TRUE; break; } } } if (fb->Attachment[BUFFER_DEPTH].Renderbuffer) { const struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; const gl_format fmt = rb->Format; fb->Visual.haveDepthBuffer = GL_TRUE; fb->Visual.depthBits = _mesa_get_format_bits(fmt, GL_DEPTH_BITS); } if (fb->Attachment[BUFFER_STENCIL].Renderbuffer) { const struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; const gl_format fmt = rb->Format; fb->Visual.haveStencilBuffer = GL_TRUE; fb->Visual.stencilBits = _mesa_get_format_bits(fmt, GL_STENCIL_BITS); } if (fb->Attachment[BUFFER_ACCUM].Renderbuffer) { const struct gl_renderbuffer *rb = fb->Attachment[BUFFER_ACCUM].Renderbuffer; const gl_format fmt = rb->Format; fb->Visual.haveAccumBuffer = GL_TRUE; fb->Visual.accumRedBits = _mesa_get_format_bits(fmt, GL_RED_BITS); fb->Visual.accumGreenBits = _mesa_get_format_bits(fmt, GL_GREEN_BITS); fb->Visual.accumBlueBits = _mesa_get_format_bits(fmt, GL_BLUE_BITS); fb->Visual.accumAlphaBits = _mesa_get_format_bits(fmt, GL_ALPHA_BITS); } compute_depth_max(fb); }
/** * Examine a texture object to determine if it is complete. * * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE * accordingly. * * \param ctx GL context. * \param t texture object. * * According to the texture target, verifies that each of the mipmaps is * present and has the expected size. */ void _mesa_test_texobj_completeness( const struct gl_context *ctx, struct gl_texture_object *t ) { const GLint baseLevel = t->BaseLevel; const struct gl_texture_image *baseImage; GLint maxLog2 = 0, maxLevels = 0; /* We'll set these to FALSE if tests fail below */ t->_BaseComplete = GL_TRUE; t->_MipmapComplete = GL_TRUE; if (t->Target == GL_TEXTURE_BUFFER) { /* Buffer textures are always considered complete. The obvious case where * they would be incomplete (no BO attached) is actually specced to be * undefined rendering results. */ return; } /* Detect cases where the application set the base level to an invalid * value. */ if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) { incomplete(t, BASE, "base level = %d is invalid", baseLevel); return; } if (t->MaxLevel < baseLevel) { incomplete(t, BASE, "MAX_LEVEL (%d) < BASE_LEVEL (%d)", t->MaxLevel, baseLevel); return; } baseImage = t->Image[0][baseLevel]; /* Always need the base level image */ if (!baseImage) { incomplete(t, BASE, "Image[baseLevel=%d] == NULL", baseLevel); return; } /* Check width/height/depth for zero */ if (baseImage->Width == 0 || baseImage->Height == 0 || baseImage->Depth == 0) { incomplete(t, BASE, "texture width or height or depth = 0"); return; } /* Check if the texture values are integer */ { GLenum datatype = _mesa_get_format_datatype(baseImage->TexFormat); t->_IsIntegerFormat = datatype == GL_INT || datatype == GL_UNSIGNED_INT; } /* Compute _MaxLevel (the maximum mipmap level we'll sample from given the * mipmap image sizes and GL_TEXTURE_MAX_LEVEL state). */ switch (t->Target) { case GL_TEXTURE_1D: case GL_TEXTURE_1D_ARRAY_EXT: maxLog2 = baseImage->WidthLog2; maxLevels = ctx->Const.MaxTextureLevels; break; case GL_TEXTURE_2D: case GL_TEXTURE_2D_ARRAY_EXT: maxLog2 = MAX2(baseImage->WidthLog2, baseImage->HeightLog2); maxLevels = ctx->Const.MaxTextureLevels; break; case GL_TEXTURE_3D: maxLog2 = MAX3(baseImage->WidthLog2, baseImage->HeightLog2, baseImage->DepthLog2); maxLevels = ctx->Const.Max3DTextureLevels; break; case GL_TEXTURE_CUBE_MAP_ARB: maxLog2 = MAX2(baseImage->WidthLog2, baseImage->HeightLog2); maxLevels = ctx->Const.MaxCubeTextureLevels; break; case GL_TEXTURE_RECTANGLE_NV: case GL_TEXTURE_BUFFER: case GL_TEXTURE_EXTERNAL_OES: maxLog2 = 0; /* not applicable */ maxLevels = 1; /* no mipmapping */ break; default: _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness"); return; } ASSERT(maxLevels > 0); t->_MaxLevel = baseLevel + maxLog2; /* 'p' in the GL spec */ t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel); t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); /* 'q' in the GL spec */ /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */ t->_MaxLambda = (GLfloat) (t->_MaxLevel - baseLevel); if (t->Immutable) { /* This texture object was created with glTexStorage1/2/3D() so we * know that all the mipmap levels are the right size and all cube * map faces are the same size. * We don't need to do any of the additional checks below. */ return; } if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { /* Make sure that all six cube map level 0 images are the same size. * Note: we know that the image's width==height (we enforce that * at glTexImage time) so we only need to test the width here. */ GLuint face; assert(baseImage->Width2 == baseImage->Height); for (face = 1; face < 6; face++) { assert(t->Image[face][baseLevel] == NULL || t->Image[face][baseLevel]->Width2 == t->Image[face][baseLevel]->Height2); if (t->Image[face][baseLevel] == NULL || t->Image[face][baseLevel]->Width2 != baseImage->Width2) { incomplete(t, BASE, "Cube face missing or mismatched size"); return; } } } /* * Do mipmap consistency checking. * Note: we don't care about the current texture sampler state here. * To determine texture completeness we'll either look at _BaseComplete * or _MipmapComplete depending on the current minification filter mode. */ { GLint i; const GLint minLevel = baseLevel; const GLint maxLevel = t->_MaxLevel; const GLuint numFaces = _mesa_num_tex_faces(t->Target); GLuint width, height, depth, face; if (minLevel > maxLevel) { incomplete(t, BASE, "minLevel > maxLevel"); return; } /* Get the base image's dimensions */ width = baseImage->Width2; height = baseImage->Height2; depth = baseImage->Depth2; /* Note: this loop will be a no-op for RECT, BUFFER, EXTERNAL textures */ for (i = baseLevel + 1; i < maxLevels; i++) { /* Compute the expected size of image at level[i] */ if (width > 1) { width /= 2; } if (height > 1 && t->Target != GL_TEXTURE_1D_ARRAY) { height /= 2; } if (depth > 1 && t->Target != GL_TEXTURE_2D_ARRAY) { depth /= 2; } /* loop over cube faces (or single face otherwise) */ for (face = 0; face < numFaces; face++) { if (i >= minLevel && i <= maxLevel) { const struct gl_texture_image *img = t->Image[face][i]; if (!img) { incomplete(t, MIPMAP, "TexImage[%d] is missing", i); return; } if (img->TexFormat != baseImage->TexFormat) { incomplete(t, MIPMAP, "Format[i] != Format[baseLevel]"); return; } if (img->Border != baseImage->Border) { incomplete(t, MIPMAP, "Border[i] != Border[baseLevel]"); return; } if (img->Width2 != width) { incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i, img->Width2); return; } if (img->Height2 != height) { incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i, img->Height2); return; } if (img->Depth2 != depth) { incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i, img->Depth2); return; } /* Extra checks for cube textures */ if (face > 0) { /* check that cube faces are the same size */ if (img->Width2 != t->Image[0][i]->Width2 || img->Height2 != t->Image[0][i]->Height2) { incomplete(t, MIPMAP, "CubeMap Image[n][i] bad size"); return; } } } } if (width == 1 && height == 1 && depth == 1) { return; /* found smallest needed mipmap, all done! */ } } } }
void GLAPIENTRY _mesa_GetTexLevelParameteriv( GLenum target, GLint level, GLenum pname, GLint *params ) { const struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; const struct gl_texture_image *img = NULL; GLint maxLevels; gl_format texFormat; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (ctx->Texture.CurrentUnit >= ctx->Const.MaxCombinedTextureImageUnits) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexLevelParameteriv(current unit)"); return; } texUnit = _mesa_get_current_tex_unit(ctx); /* this will catch bad target values */ maxLevels = _mesa_max_texture_levels(ctx, target); if (maxLevels == 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(target=0x%x)", target); return; } if (level < 0 || level >= maxLevels) { _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexLevelParameter[if]v" ); return; } texObj = _mesa_select_tex_object(ctx, texUnit, target); img = _mesa_select_tex_image(ctx, texObj, target, level); if (!img || !img->TexFormat) { /* undefined texture image */ if (pname == GL_TEXTURE_COMPONENTS) *params = 1; else *params = 0; return; } texFormat = img->TexFormat; switch (pname) { case GL_TEXTURE_WIDTH: *params = img->Width; break; case GL_TEXTURE_HEIGHT: *params = img->Height; break; case GL_TEXTURE_DEPTH: *params = img->Depth; break; case GL_TEXTURE_INTERNAL_FORMAT: if (_mesa_is_format_compressed(texFormat)) { /* need to return the actual compressed format */ *params = _mesa_compressed_format_to_glenum(ctx, texFormat); } else { /* If the true internal format is not compressed but the user * requested a generic compressed format, we have to return the * generic base format that matches. * * From page 119 (page 129 of the PDF) of the OpenGL 1.3 spec: * * "If no specific compressed format is available, * internalformat is instead replaced by the corresponding base * internal format." * * Otherwise just return the user's requested internal format */ const GLenum f = _mesa_gl_compressed_format_base_format(img->InternalFormat); *params = (f != 0) ? f : img->InternalFormat; } break; case GL_TEXTURE_BORDER: *params = img->Border; break; case GL_TEXTURE_RED_SIZE: if (img->_BaseFormat == GL_RED) { *params = _mesa_get_format_bits(texFormat, pname); break; } /* FALLTHROUGH */ case GL_TEXTURE_GREEN_SIZE: if (img->_BaseFormat == GL_RG) { *params = _mesa_get_format_bits(texFormat, pname); break; } /* FALLTHROUGH */ case GL_TEXTURE_BLUE_SIZE: if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA) *params = _mesa_get_format_bits(texFormat, pname); else *params = 0; break; case GL_TEXTURE_ALPHA_SIZE: if (img->_BaseFormat == GL_ALPHA || img->_BaseFormat == GL_LUMINANCE_ALPHA || img->_BaseFormat == GL_RGBA) *params = _mesa_get_format_bits(texFormat, pname); else *params = 0; break; case GL_TEXTURE_INTENSITY_SIZE: if (img->_BaseFormat != GL_INTENSITY) *params = 0; else { *params = _mesa_get_format_bits(texFormat, pname); if (*params == 0) { /* intensity probably stored as rgb texture */ *params = MIN2(_mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE), _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE)); } } break; case GL_TEXTURE_LUMINANCE_SIZE: if (img->_BaseFormat != GL_LUMINANCE && img->_BaseFormat != GL_LUMINANCE_ALPHA) *params = 0; else { *params = _mesa_get_format_bits(texFormat, pname); if (*params == 0) { /* luminance probably stored as rgb texture */ *params = MIN2(_mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE), _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE)); } } break; case GL_TEXTURE_INDEX_SIZE_EXT: if (img->_BaseFormat == GL_COLOR_INDEX) *params = _mesa_get_format_bits(texFormat, pname); else *params = 0; break; case GL_TEXTURE_DEPTH_SIZE_ARB: if (ctx->Extensions.ARB_depth_texture) *params = _mesa_get_format_bits(texFormat, pname); else goto invalid_pname; break; case GL_TEXTURE_STENCIL_SIZE_EXT: if (ctx->Extensions.EXT_packed_depth_stencil || ctx->Extensions.ARB_framebuffer_object) { *params = _mesa_get_format_bits(texFormat, pname); } else { goto invalid_pname; } break; case GL_TEXTURE_SHARED_SIZE: if (ctx->VersionMajor >= 3 || ctx->Extensions.EXT_texture_shared_exponent) { *params = texFormat == MESA_FORMAT_RGB9_E5_FLOAT ? 5 : 0; } else { goto invalid_pname; } break; /* GL_ARB_texture_compression */ case GL_TEXTURE_COMPRESSED_IMAGE_SIZE: if (_mesa_is_format_compressed(texFormat) && !_mesa_is_proxy_texture(target)) { *params = _mesa_format_image_size(texFormat, img->Width, img->Height, img->Depth); } else { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexLevelParameter[if]v(pname)"); } break; case GL_TEXTURE_COMPRESSED: *params = (GLint) _mesa_is_format_compressed(texFormat); break; /* GL_ARB_texture_float */ case GL_TEXTURE_RED_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE) ? _mesa_get_format_datatype(texFormat) : GL_NONE; } else { goto invalid_pname; } break; case GL_TEXTURE_GREEN_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE) ? _mesa_get_format_datatype(texFormat) : GL_NONE; } else { goto invalid_pname; } break; case GL_TEXTURE_BLUE_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_BLUE_SIZE) ? _mesa_get_format_datatype(texFormat) : GL_NONE; } else { goto invalid_pname; } break; case GL_TEXTURE_ALPHA_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_ALPHA_SIZE) ? _mesa_get_format_datatype(texFormat) : GL_NONE; } else { goto invalid_pname; } break; case GL_TEXTURE_LUMINANCE_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_LUMINANCE_SIZE) ? _mesa_get_format_datatype(texFormat) : GL_NONE; } else { goto invalid_pname; } break; case GL_TEXTURE_INTENSITY_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_INTENSITY_SIZE) ? _mesa_get_format_datatype(texFormat) : GL_NONE; } else { goto invalid_pname; } break; case GL_TEXTURE_DEPTH_TYPE_ARB: if (ctx->Extensions.ARB_texture_float) { *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_DEPTH_SIZE) ? _mesa_get_format_datatype(texFormat) : GL_NONE; } else { goto invalid_pname; } break; default: goto invalid_pname; } /* no error if we get here */ return; invalid_pname: _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(pname=%s)", _mesa_lookup_enum_by_nr(pname)); }