#include "main/blit.h"
#include "main/bufferobj.h"
#include "main/buffers.h"
+#include "main/clear.h"
#include "main/colortab.h"
#include "main/condrender.h"
#include "main/depth.h"
#include "main/fbobject.h"
#include "main/feedback.h"
#include "main/formats.h"
+#include "main/format_unpack.h"
#include "main/glformats.h"
#include "main/image.h"
#include "main/macros.h"
#include "main/teximage.h"
#include "main/texparam.h"
#include "main/texstate.h"
+#include "main/texstore.h"
#include "main/transformfeedback.h"
#include "main/uniforms.h"
#include "main/varray.h"
#include "drivers/common/meta.h"
#include "main/enums.h"
#include "main/glformats.h"
-#include "../glsl/ralloc.h"
+#include "util/ralloc.h"
/** Return offset in bytes of the field within a vertex struct */
#define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD))
static void meta_drawpix_cleanup(struct drawpix_state *drawpix);
void
-_mesa_meta_bind_fbo_image(GLenum attachment,
+_mesa_meta_bind_fbo_image(GLenum fboTarget, GLenum attachment,
struct gl_texture_image *texImage, GLuint layer)
{
struct gl_texture_object *texObj = texImage->TexObject;
int level = texImage->Level;
- GLenum target = texObj->Target;
+ GLenum texTarget = texObj->Target;
- switch (target) {
+ switch (texTarget) {
case GL_TEXTURE_1D:
- _mesa_FramebufferTexture1D(GL_FRAMEBUFFER,
+ _mesa_FramebufferTexture1D(fboTarget,
attachment,
- target,
+ texTarget,
texObj->Name,
level);
break;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
case GL_TEXTURE_CUBE_MAP_ARRAY:
case GL_TEXTURE_3D:
- _mesa_FramebufferTextureLayer(GL_FRAMEBUFFER,
+ _mesa_FramebufferTextureLayer(fboTarget,
attachment,
texObj->Name,
level,
layer);
break;
default: /* 2D / cube */
- if (target == GL_TEXTURE_CUBE_MAP)
- target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face;
+ if (texTarget == GL_TEXTURE_CUBE_MAP)
+ texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face;
- _mesa_FramebufferTexture2D(GL_FRAMEBUFFER,
+ _mesa_FramebufferTexture2D(fboTarget,
attachment,
- target,
+ texTarget,
texObj->Name,
level);
}
{
const char *vs_source =
"#extension GL_AMD_vertex_shader_layer : enable\n"
+ "#extension GL_ARB_draw_instanced : enable\n"
"attribute vec4 position;\n"
- "uniform int layer;\n"
"void main()\n"
"{\n"
"#ifdef GL_AMD_vertex_shader_layer\n"
- " gl_Layer = layer;\n"
+ " gl_Layer = gl_InstanceID;\n"
"#endif\n"
" gl_Position = position;\n"
"}\n";
_mesa_LinkProgram(clear->ShaderProg);
clear->ColorLocation = _mesa_GetUniformLocation(clear->ShaderProg, "color");
- clear->LayerLocation = _mesa_GetUniformLocation(clear->ShaderProg, "layer");
has_integer_textures = _mesa_is_gles3(ctx) ||
(_mesa_is_desktop_gl(ctx) && ctx->Const.GLSLVersion >= 130);
ralloc_asprintf(shader_source_mem_ctx,
"#version 130\n"
"#extension GL_AMD_vertex_shader_layer : enable\n"
+ "#extension GL_ARB_draw_instanced : enable\n"
"in vec4 position;\n"
- "uniform int layer;\n"
"void main()\n"
"{\n"
"#ifdef GL_AMD_vertex_shader_layer\n"
- " gl_Layer = layer;\n"
+ " gl_Layer = gl_InstanceID;\n"
"#endif\n"
" gl_Position = position;\n"
"}\n");
clear->IntegerColorLocation =
_mesa_GetUniformLocation(clear->IntegerShaderProg, "color");
- clear->IntegerLayerLocation =
- _mesa_GetUniformLocation(clear->IntegerShaderProg, "layer");
}
}
* Since the bitfield has no associated order, the assignment of draw buffer
* indices to color attachment indices is rather arbitrary.
*/
-static void
-drawbuffers_from_bitfield(GLbitfield bits)
+void
+_mesa_meta_drawbuffers_from_bitfield(GLbitfield bits)
{
GLenum enums[MAX_DRAW_BUFFERS];
int i = 0;
/* GL_COLOR_BUFFER_BIT */
if (buffers & BUFFER_BITS_COLOR) {
/* Only draw to the buffers we were asked to clear. */
- drawbuffers_from_bitfield(buffers & BUFFER_BITS_COLOR);
+ _mesa_meta_drawbuffers_from_bitfield(buffers & BUFFER_BITS_COLOR);
/* leave colormask state as-is */
/* draw quad(s) */
if (fb->MaxNumLayers > 0) {
- unsigned layer;
- assert(glsl && clear->LayerLocation != -1);
- for (layer = 0; layer < fb->MaxNumLayers; layer++) {
- if (fb->_IntegerColor)
- _mesa_Uniform1i(clear->IntegerLayerLocation, layer);
- else
- _mesa_Uniform1i(clear->LayerLocation, layer);
- _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
- }
+ _mesa_DrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, fb->MaxNumLayers);
} else {
_mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
static GLenum
get_temp_image_type(struct gl_context *ctx, mesa_format format)
{
- GLenum baseFormat;
-
- baseFormat = _mesa_get_format_base_format(format);
+ const GLenum baseFormat = _mesa_get_format_base_format(format);
+ const GLenum datatype = _mesa_get_format_datatype(format);
+ const GLint format_red_bits = _mesa_get_format_bits(format, GL_RED_BITS);
switch (baseFormat) {
case GL_RGBA:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
case GL_INTENSITY:
- if (ctx->DrawBuffer->Visual.redBits <= 8) {
+ if (datatype == GL_INT || datatype == GL_UNSIGNED_INT) {
+ return datatype;
+ } else if (format_red_bits <= 8) {
return GL_UNSIGNED_BYTE;
- } else if (ctx->DrawBuffer->Visual.redBits <= 16) {
+ } else if (format_red_bits <= 16) {
return GL_UNSIGNED_SHORT;
- } else {
- GLenum datatype = _mesa_get_format_datatype(format);
- if (datatype == GL_INT || datatype == GL_UNSIGNED_INT)
- return datatype;
- return GL_FLOAT;
}
- case GL_DEPTH_COMPONENT: {
- GLenum datatype = _mesa_get_format_datatype(format);
+ return GL_FLOAT;
+ case GL_DEPTH_COMPONENT:
if (datatype == GL_FLOAT)
return GL_FLOAT;
else
return GL_UNSIGNED_INT;
- }
- case GL_DEPTH_STENCIL: {
- GLenum datatype = _mesa_get_format_datatype(format);
+ case GL_DEPTH_STENCIL:
if (datatype == GL_FLOAT)
return GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
else
return GL_UNSIGNED_INT_24_8;
- }
default:
_mesa_problem(ctx, "Unexpected format %d in get_temp_image_type()",
baseFormat);
if (rb->_BaseFormat == GL_DEPTH_STENCIL ||
rb->_BaseFormat == GL_DEPTH_COMPONENT) {
- _mesa_meta_bind_fbo_image(GL_DEPTH_ATTACHMENT, texImage, zoffset);
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ texImage, zoffset);
mask = GL_DEPTH_BUFFER_BIT;
if (rb->_BaseFormat == GL_DEPTH_STENCIL &&
texImage->_BaseFormat == GL_DEPTH_STENCIL) {
- _mesa_meta_bind_fbo_image(GL_STENCIL_ATTACHMENT, texImage, zoffset);
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ texImage, zoffset);
mask |= GL_STENCIL_BUFFER_BIT;
}
_mesa_DrawBuffer(GL_NONE);
} else {
- _mesa_meta_bind_fbo_image(GL_COLOR_ATTACHMENT0, texImage, zoffset);
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ texImage, zoffset);
mask = GL_COLOR_BUFFER_BIT;
_mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
}
free(buf);
}
+static void
+meta_decompress_fbo_cleanup(struct decompress_fbo_state *decompress_fbo)
+{
+ if (decompress_fbo->FBO != 0) {
+ _mesa_DeleteFramebuffers(1, &decompress_fbo->FBO);
+ _mesa_DeleteRenderbuffers(1, &decompress_fbo->RBO);
+ }
+
+ memset(decompress_fbo, 0, sizeof(*decompress_fbo));
+}
static void
meta_decompress_cleanup(struct decompress_state *decompress)
{
- if (decompress->FBO != 0) {
- _mesa_DeleteFramebuffers(1, &decompress->FBO);
- _mesa_DeleteRenderbuffers(1, &decompress->RBO);
- }
+ meta_decompress_fbo_cleanup(&decompress->byteFBO);
+ meta_decompress_fbo_cleanup(&decompress->floatFBO);
if (decompress->VAO != 0) {
_mesa_DeleteVertexArrays(1, &decompress->VAO);
* \param dest destination buffer
* \param destRowLength dest image rowLength (ala GL_PACK_ROW_LENGTH)
*/
-static void
+static bool
decompress_texture_image(struct gl_context *ctx,
struct gl_texture_image *texImage,
GLuint slice,
GLvoid *dest)
{
struct decompress_state *decompress = &ctx->Meta->Decompress;
+ struct decompress_fbo_state *decompress_fbo;
struct gl_texture_object *texObj = texImage->TexObject;
const GLint width = texImage->Width;
const GLint height = texImage->Height;
const GLint depth = texImage->Height;
const GLenum target = texObj->Target;
+ GLenum rbFormat;
GLenum faceTarget;
struct vertex verts[4];
GLuint samplerSave;
+ GLenum status;
const bool use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
ctx->Extensions.ARB_fragment_shader;
+ switch (_mesa_get_format_datatype(texImage->TexFormat)) {
+ case GL_FLOAT:
+ decompress_fbo = &decompress->floatFBO;
+ rbFormat = GL_RGBA32F;
+ break;
+ case GL_UNSIGNED_NORMALIZED:
+ decompress_fbo = &decompress->byteFBO;
+ rbFormat = GL_RGBA;
+ break;
+ default:
+ return false;
+ }
+
if (slice > 0) {
assert(target == GL_TEXTURE_3D ||
target == GL_TEXTURE_2D_ARRAY ||
case GL_TEXTURE_1D:
case GL_TEXTURE_1D_ARRAY:
assert(!"No compressed 1D textures.");
- return;
+ return false;
case GL_TEXTURE_3D:
assert(!"No compressed 3D textures.");
- return;
+ return false;
case GL_TEXTURE_CUBE_MAP_ARRAY:
faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + (slice % 6);
ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;
/* Create/bind FBO/renderbuffer */
- if (decompress->FBO == 0) {
- _mesa_GenFramebuffers(1, &decompress->FBO);
- _mesa_GenRenderbuffers(1, &decompress->RBO);
- _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress->FBO);
- _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress->RBO);
+ if (decompress_fbo->FBO == 0) {
+ _mesa_GenFramebuffers(1, &decompress_fbo->FBO);
+ _mesa_GenRenderbuffers(1, &decompress_fbo->RBO);
+ _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress_fbo->FBO);
+ _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress_fbo->RBO);
_mesa_FramebufferRenderbuffer(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT,
GL_RENDERBUFFER_EXT,
- decompress->RBO);
+ decompress_fbo->RBO);
}
else {
- _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress->FBO);
+ _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress_fbo->FBO);
}
/* alloc dest surface */
- if (width > decompress->Width || height > decompress->Height) {
- _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress->RBO);
- _mesa_RenderbufferStorage(GL_RENDERBUFFER_EXT, GL_RGBA,
- width, height);
- decompress->Width = width;
- decompress->Height = height;
+ if (width > decompress_fbo->Width || height > decompress_fbo->Height) {
+ _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress_fbo->RBO);
+ _mesa_RenderbufferStorage(GL_RENDERBUFFER_EXT, rbFormat,
+ width, height);
+ status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ /* If the framebuffer isn't complete then we'll leave
+ * decompress_fbo->Width as zero so that it will fail again next time
+ * too */
+ _mesa_meta_end(ctx);
+ return false;
+ }
+ decompress_fbo->Width = width;
+ decompress_fbo->Height = height;
}
if (use_glsl_version) {
_mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave);
_mesa_meta_end(ctx);
+
+ return true;
}
GLenum format, GLenum type, GLvoid *pixels,
struct gl_texture_image *texImage)
{
- /* We can only use the decompress-with-blit method here if the texels are
- * unsigned, normalized values. We could handle signed and unnormalized
- * with floating point renderbuffers...
- */
- if (_mesa_is_format_compressed(texImage->TexFormat) &&
- _mesa_get_format_datatype(texImage->TexFormat)
- == GL_UNSIGNED_NORMALIZED) {
+ if (_mesa_is_format_compressed(texImage->TexFormat)) {
struct gl_texture_object *texObj = texImage->TexObject;
GLuint slice;
+ bool result;
+
/* Need to unlock the texture here to prevent deadlock... */
_mesa_unlock_texture(ctx, texObj);
for (slice = 0; slice < texImage->Depth; slice++) {
else {
dst = pixels;
}
- decompress_texture_image(ctx, texImage, slice, format, type, dst);
+ result = decompress_texture_image(ctx, texImage, slice,
+ format, type, dst);
+ if (!result)
+ break;
}
/* ... and relock it */
_mesa_lock_texture(ctx, texObj);
+
+ if (result)
+ return;
}
- else {
- _mesa_get_teximage(ctx, format, type, pixels, texImage);
- }
+
+ _mesa_get_teximage(ctx, format, type, pixels, texImage);
}
_mesa_meta_end(ctx);
}
+
+static bool
+cleartexsubimage_color(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ const GLvoid *clearValue,
+ GLint zoffset)
+{
+ mesa_format format;
+ union gl_color_union colorValue;
+ GLenum datatype;
+ GLenum status;
+
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ texImage, zoffset);
+
+ status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ return false;
+
+ /* We don't want to apply an sRGB conversion so override the format */
+ format = _mesa_get_srgb_format_linear(texImage->TexFormat);
+ datatype = _mesa_get_format_datatype(format);
+
+ switch (datatype) {
+ case GL_UNSIGNED_INT:
+ case GL_INT:
+ if (clearValue)
+ _mesa_unpack_uint_rgba_row(format, 1, clearValue,
+ (GLuint (*)[4]) colorValue.ui);
+ else
+ memset(&colorValue, 0, sizeof colorValue);
+ if (datatype == GL_INT)
+ _mesa_ClearBufferiv(GL_COLOR, 0, colorValue.i);
+ else
+ _mesa_ClearBufferuiv(GL_COLOR, 0, colorValue.ui);
+ break;
+ default:
+ if (clearValue)
+ _mesa_unpack_rgba_row(format, 1, clearValue,
+ (GLfloat (*)[4]) colorValue.f);
+ else
+ memset(&colorValue, 0, sizeof colorValue);
+ _mesa_ClearBufferfv(GL_COLOR, 0, colorValue.f);
+ break;
+ }
+
+ return true;
+}
+
+static bool
+cleartexsubimage_depth_stencil(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ const GLvoid *clearValue,
+ GLint zoffset)
+{
+ GLint stencilValue;
+ GLfloat depthValue;
+ GLenum status;
+
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ texImage, zoffset);
+
+ if (texImage->_BaseFormat == GL_DEPTH_STENCIL)
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ texImage, zoffset);
+
+ status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ return false;
+
+ if (clearValue) {
+ GLuint depthStencilValue[2];
+
+ /* Convert the clearValue from whatever format it's in to a floating
+ * point value for the depth and an integer value for the stencil index
+ */
+ _mesa_unpack_float_32_uint_24_8_depth_stencil_row(texImage->TexFormat,
+ 1, /* n */
+ clearValue,
+ depthStencilValue);
+ /* We need a memcpy here instead of a cast because we need to
+ * reinterpret the bytes as a float rather than converting it
+ */
+ memcpy(&depthValue, depthStencilValue, sizeof depthValue);
+ stencilValue = depthStencilValue[1] & 0xff;
+ } else {
+ depthValue = 0.0f;
+ stencilValue = 0;
+ }
+
+ if (texImage->_BaseFormat == GL_DEPTH_STENCIL)
+ _mesa_ClearBufferfi(GL_DEPTH_STENCIL, 0, depthValue, stencilValue);
+ else
+ _mesa_ClearBufferfv(GL_DEPTH, 0, &depthValue);
+
+ return true;
+}
+
+static bool
+cleartexsubimage_for_zoffset(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ GLint zoffset,
+ const GLvoid *clearValue)
+{
+ GLuint fbo;
+ bool success;
+
+ _mesa_GenFramebuffers(1, &fbo);
+ _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+
+ switch(texImage->_BaseFormat) {
+ case GL_DEPTH_STENCIL:
+ case GL_DEPTH_COMPONENT:
+ success = cleartexsubimage_depth_stencil(ctx, texImage,
+ clearValue, zoffset);
+ break;
+ default:
+ success = cleartexsubimage_color(ctx, texImage, clearValue, zoffset);
+ break;
+ }
+
+ _mesa_DeleteFramebuffers(1, &fbo);
+
+ return success;
+}
+
+static bool
+cleartexsubimage_using_fbo(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ const GLvoid *clearValue)
+{
+ bool success = true;
+ GLint z;
+
+ _mesa_meta_begin(ctx,
+ MESA_META_SCISSOR |
+ MESA_META_COLOR_MASK |
+ MESA_META_DITHER |
+ MESA_META_FRAMEBUFFER_SRGB);
+
+ _mesa_set_enable(ctx, GL_DITHER, GL_FALSE);
+
+ _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_TRUE);
+ _mesa_Scissor(xoffset, yoffset, width, height);
+
+ for (z = zoffset; z < zoffset + depth; z++) {
+ if (!cleartexsubimage_for_zoffset(ctx, texImage, z, clearValue)) {
+ success = false;
+ break;
+ }
+ }
+
+ _mesa_meta_end(ctx);
+
+ return success;
+}
+
+extern void
+_mesa_meta_ClearTexSubImage(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ const GLvoid *clearValue)
+{
+ bool res;
+
+ _mesa_unlock_texture(ctx, texImage->TexObject);
+
+ res = cleartexsubimage_using_fbo(ctx, texImage,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ clearValue);
+
+ _mesa_lock_texture(ctx, texImage->TexObject);
+
+ if (res)
+ return;
+
+ _mesa_warning(ctx,
+ "Falling back to mapping the texture in "
+ "glClearTexSubImage\n");
+
+ _mesa_store_cleartexsubimage(ctx, texImage,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ clearValue);
+}