aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa/drivers/common/meta_blit.c
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2014-03-04 08:57:07 +0100
committermarha <marha@users.sourceforge.net>2014-03-04 08:57:07 +0100
commit321c01267ae1c446f1bd22b642567fcafa016c02 (patch)
tree69f6e12bdfd1ccda5d054398321bc1876dd3fc89 /mesalib/src/mesa/drivers/common/meta_blit.c
parent982ac918afe6a1c02d5cf735d7b6c56443a048cc (diff)
downloadvcxsrv-321c01267ae1c446f1bd22b642567fcafa016c02.tar.gz
vcxsrv-321c01267ae1c446f1bd22b642567fcafa016c02.tar.bz2
vcxsrv-321c01267ae1c446f1bd22b642567fcafa016c02.zip
libX11 libxcb mesa xserver xcb-proto xkeyboard-config git update 4 Mar 2014
xserver commit b634e909895f6001e7d9543e1350b20c82c8c01c libxcb commit 4ffa6f83b92763eb901c7ddb7c20775e24d507ca libxcb/xcb-proto commit 4270141a7cb3c68f50251be19a5a628aa18553e6 xkeyboard-config commit d9e3d0ec1a48a5f61ea6dd6d20b8682eeecf3a39 libX11 commit d6bd988bc00494914b38b95ee5df77ac4f32f19f libXdmcp commit 089081dca4ba3598c6f9bf401c029378943b5854 libXext commit d5447c0156f556114dbf97d6064c0c7b0fcd5f70 libfontenc commit 0037a42107b952c9d903719615747e760e4e7247 libXinerama commit edd95182b26eb5d576d4878c559e0f17dddaa909 libXau commit 1e4635be11154dd8262f37b379511bd627defa2a xkbcomp commit 31b90ee4ffc774e0da540277907fc5540c0b012c pixman commit 82d094654a46bd97d47f1f132a01ae0a74b986f3 xextproto commit 66afec3f49e8eb0d4c2e9af7088fc3116d4bafd7 randrproto commit a4a6694c059d74247c16527eef4a0ec9f56bbef6 glproto commit f84853d97d5749308992412a215fa518b6536eb3 mkfontscale commit eac564e0fc9052a39981ea47b271f7f3d2821944 xwininfo commit ba0d1b0da21d2dbdd81098ed5778f3792b472e13 libXft commit 4acfdaf95adb0a05c2a25550bdde036c865902f4 libXmu commit 22d9c590901e121936f50dee97dc60c4f7defb63 libxtrans commit 3f0de269abe59353acbd7a5587d68ce0da91db67 fontconfig commit e310d2fac2d874d5aa76c609df70cc7b871c0b6d mesa commit 1a568e0f2b65e4e1e1d19a6dece3a792a33da825
Diffstat (limited to 'mesalib/src/mesa/drivers/common/meta_blit.c')
-rw-r--r--mesalib/src/mesa/drivers/common/meta_blit.c825
1 files changed, 825 insertions, 0 deletions
diff --git a/mesalib/src/mesa/drivers/common/meta_blit.c b/mesalib/src/mesa/drivers/common/meta_blit.c
new file mode 100644
index 000000000..907c2cdf3
--- /dev/null
+++ b/mesalib/src/mesa/drivers/common/meta_blit.c
@@ -0,0 +1,825 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "main/glheader.h"
+#include "main/mtypes.h"
+#include "main/imports.h"
+#include "main/arbprogram.h"
+#include "main/arrayobj.h"
+#include "main/blend.h"
+#include "main/condrender.h"
+#include "main/depth.h"
+#include "main/enable.h"
+#include "main/enums.h"
+#include "main/fbobject.h"
+#include "main/macros.h"
+#include "main/matrix.h"
+#include "main/multisample.h"
+#include "main/objectlabel.h"
+#include "main/readpix.h"
+#include "main/shaderapi.h"
+#include "main/texobj.h"
+#include "main/texenv.h"
+#include "main/teximage.h"
+#include "main/texparam.h"
+#include "main/varray.h"
+#include "main/viewport.h"
+#include "swrast/swrast.h"
+#include "drivers/common/meta.h"
+#include "../glsl/ralloc.h"
+
+/** Return offset in bytes of the field within a vertex struct */
+#define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD))
+
+/**
+ * One-time init for drawing depth pixels.
+ */
+static void
+init_blit_depth_pixels(struct gl_context *ctx)
+{
+ static const char *program =
+ "!!ARBfp1.0\n"
+ "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n"
+ "END \n";
+ char program2[200];
+ struct blit_state *blit = &ctx->Meta->Blit;
+ struct temp_texture *tex = _mesa_meta_get_temp_texture(ctx);
+ const char *texTarget;
+
+ assert(blit->DepthFP == 0);
+
+ /* replace %s with "RECT" or "2D" */
+ assert(strlen(program) + 4 < sizeof(program2));
+ if (tex->Target == GL_TEXTURE_RECTANGLE)
+ texTarget = "RECT";
+ else
+ texTarget = "2D";
+ _mesa_snprintf(program2, sizeof(program2), program, texTarget);
+
+ _mesa_GenProgramsARB(1, &blit->DepthFP);
+ _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP);
+ _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(program2), (const GLubyte *) program2);
+}
+
+static void
+setup_glsl_msaa_blit_shader(struct gl_context *ctx,
+ struct blit_state *blit,
+ struct gl_renderbuffer *src_rb,
+ GLenum target)
+{
+ const char *vs_source;
+ char *fs_source;
+ GLuint vs, fs;
+ void *mem_ctx;
+ enum blit_msaa_shader shader_index;
+ bool dst_is_msaa = false;
+ GLenum src_datatype;
+ const char *vec4_prefix;
+ char *name;
+
+ if (src_rb) {
+ 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.
+ */
+ src_datatype = GL_UNSIGNED_NORMALIZED;
+ }
+
+ if (ctx->DrawBuffer->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:
+ if (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_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE;
+ }
+ break;
+ default:
+ _mesa_problem(ctx, "Unkown texture target %s\n",
+ _mesa_lookup_enum_by_nr(target));
+ shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE;
+ }
+
+ /* We rely on the enum being sorted this way. */
+ STATIC_ASSERT(BLIT_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_INT ==
+ BLIT_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 1);
+ STATIC_ASSERT(BLIT_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_UINT ==
+ BLIT_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 2);
+ if (src_datatype == GL_INT) {
+ shader_index++;
+ vec4_prefix = "i";
+ } else if (src_datatype == GL_UNSIGNED_INT) {
+ shader_index += 2;
+ 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_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 vec2 textureCoords;\n"
+ "out vec2 texCoords;\n"
+ "void main()\n"
+ "{\n"
+ " texCoords = textureCoords;\n"
+ " gl_Position = vec4(position, 0.0, 1.0);\n"
+ "}\n");
+ fs_source = ralloc_asprintf(mem_ctx,
+ "#version 130\n"
+ "#extension GL_ARB_texture_multisample : enable\n"
+ "%s\n"
+ "uniform sampler2DMS texSampler;\n"
+ "in vec2 texCoords;\n"
+ "out vec4 out_color;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragDepth = texelFetch(texSampler, ivec2(texCoords), %s).r;\n"
+ "}\n",
+ arb_sample_shading_extension_string,
+ sample_index);
+ } else {
+ /* You can create 2D_MULTISAMPLE textures with 0 sample count (meaning 1
+ * sample). Yes, this is ridiculous.
+ */
+ int samples;
+ 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");
+
+ samples = MAX2(src_rb->NumSamples, 1);
+
+ 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, ivec2(texCoords), gl_SampleID);");
+ 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((samples & (samples - 1)) == 0);
+ /* 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, ivec2(texCoords), %d);\n",
+ i, 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,
+ " out_color = sample_%d_0 / %f;\n",
+ samples, (float)samples);
+ }
+ }
+
+ vs_source = ralloc_asprintf(mem_ctx,
+ "#version 130\n"
+ "in vec2 position;\n"
+ "in vec2 textureCoords;\n"
+ "out vec2 texCoords;\n"
+ "void main()\n"
+ "{\n"
+ " texCoords = textureCoords;\n"
+ " gl_Position = vec4(position, 0.0, 1.0);\n"
+ "}\n");
+ fs_source = ralloc_asprintf(mem_ctx,
+ "#version 130\n"
+ "#extension GL_ARB_texture_multisample : enable\n"
+ "%s\n"
+ "#define gvec4 %svec4\n"
+ "uniform %ssampler2DMS texSampler;\n"
+ "in vec2 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,
+ merge_function,
+ sample_resolve);
+ }
+
+ vs = _mesa_meta_compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_source);
+ fs = _mesa_meta_compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_source);
+
+ blit->msaa_shaders[shader_index] = _mesa_CreateProgramObjectARB();
+ _mesa_AttachShader(blit->msaa_shaders[shader_index], fs);
+ _mesa_DeleteObjectARB(fs);
+ _mesa_AttachShader(blit->msaa_shaders[shader_index], vs);
+ _mesa_DeleteObjectARB(vs);
+ _mesa_BindAttribLocation(blit->msaa_shaders[shader_index], 0, "position");
+ _mesa_BindAttribLocation(blit->msaa_shaders[shader_index], 1, "texcoords");
+ _mesa_meta_link_program_with_debug(ctx, blit->msaa_shaders[shader_index]);
+ _mesa_ObjectLabel(GL_PROGRAM, blit->msaa_shaders[shader_index], -1, name);
+ ralloc_free(mem_ctx);
+
+ _mesa_UseProgram(blit->msaa_shaders[shader_index]);
+}
+
+static void
+setup_glsl_blit_framebuffer(struct gl_context *ctx,
+ struct blit_state *blit,
+ struct gl_renderbuffer *src_rb,
+ GLenum target)
+{
+ /* target = GL_TEXTURE_RECTANGLE is not supported in GLES 3.0 */
+ assert(_mesa_is_desktop_gl(ctx) || target == GL_TEXTURE_2D);
+
+ _mesa_meta_setup_vertex_objects(&blit->VAO, &blit->VBO, true, 2, 2, 0);
+
+ if (target == GL_TEXTURE_2D_MULTISAMPLE) {
+ setup_glsl_msaa_blit_shader(ctx, blit, src_rb, target);
+ } else {
+ _mesa_meta_setup_blit_shader(ctx, target, &blit->shaders);
+ }
+}
+
+/**
+ * Try to do a color or depth glBlitFramebuffer using texturing.
+ *
+ * We can do this when the src renderbuffer is actually a texture, or when the
+ * driver exposes BindRenderbufferTexImage().
+ */
+static bool
+blitframebuffer_texture(struct gl_context *ctx,
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLenum filter, GLint flipX, GLint flipY,
+ GLboolean glsl_version, GLboolean do_depth)
+{
+ const struct gl_framebuffer *readFb = ctx->ReadBuffer;
+ int att_index = do_depth ? BUFFER_DEPTH : readFb->_ColorReadBufferIndex;
+ const struct gl_renderbuffer_attachment *readAtt =
+ &readFb->Attachment[att_index];
+ struct blit_state *blit = &ctx->Meta->Blit;
+ const GLint dstX = MIN2(dstX0, dstX1);
+ const GLint dstY = MIN2(dstY0, dstY1);
+ const GLint dstW = abs(dstX1 - dstX0);
+ const GLint dstH = abs(dstY1 - dstY0);
+ struct gl_texture_object *texObj;
+ GLuint srcLevel;
+ GLint baseLevelSave;
+ GLint maxLevelSave;
+ GLenum target;
+ GLuint sampler, samplerSave =
+ ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ?
+ ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;
+ GLuint tempTex = 0;
+ struct gl_renderbuffer *rb = readAtt->Renderbuffer;
+
+ if (rb->NumSamples && !ctx->Extensions.ARB_texture_multisample)
+ return false;
+
+ if (filter == GL_SCALED_RESOLVE_FASTEST_EXT ||
+ filter == GL_SCALED_RESOLVE_NICEST_EXT) {
+ filter = GL_LINEAR;
+ }
+
+ if (readAtt->Texture) {
+ /* If there's a texture attached of a type we can handle, then just use
+ * it directly.
+ */
+ srcLevel = readAtt->TextureLevel;
+ texObj = readAtt->Texture;
+ target = texObj->Target;
+
+ switch (target) {
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_RECTANGLE:
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ break;
+ default:
+ return false;
+ }
+ } else if (ctx->Driver.BindRenderbufferTexImage) {
+ /* Otherwise, we need the driver to be able to bind a renderbuffer as
+ * a texture image.
+ */
+ struct gl_texture_image *texImage;
+
+ if (rb->NumSamples > 1)
+ target = GL_TEXTURE_2D_MULTISAMPLE;
+ else
+ target = GL_TEXTURE_2D;
+
+ _mesa_GenTextures(1, &tempTex);
+ _mesa_BindTexture(target, tempTex);
+ srcLevel = 0;
+ texObj = _mesa_lookup_texture(ctx, tempTex);
+ texImage = _mesa_get_tex_image(ctx, texObj, target, srcLevel);
+
+ if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) {
+ _mesa_DeleteTextures(1, &tempTex);
+ return false;
+ } else {
+ if (ctx->Driver.FinishRenderTexture &&
+ !rb->NeedsFinishRenderTexture) {
+ rb->NeedsFinishRenderTexture = true;
+ ctx->Driver.FinishRenderTexture(ctx, rb);
+ }
+
+ if (_mesa_is_winsys_fbo(readFb)) {
+ GLint temp = srcY0;
+ srcY0 = rb->Height - srcY1;
+ srcY1 = rb->Height - temp;
+ flipY = -flipY;
+ }
+ }
+ } else {
+ return false;
+ }
+
+ baseLevelSave = texObj->BaseLevel;
+ maxLevelSave = texObj->MaxLevel;
+
+ if (glsl_version) {
+ setup_glsl_blit_framebuffer(ctx, blit, rb, target);
+ }
+ else {
+ _mesa_meta_setup_ff_tnl_for_blit(&ctx->Meta->Blit.VAO,
+ &ctx->Meta->Blit.VBO,
+ 2);
+ }
+
+ _mesa_GenSamplers(1, &sampler);
+ _mesa_BindSampler(ctx->Texture.CurrentUnit, sampler);
+
+ /*
+ printf("Blit from texture!\n");
+ printf(" srcAtt %p dstAtt %p\n", readAtt, drawAtt);
+ printf(" srcTex %p dstText %p\n", texObj, drawAtt->Texture);
+ */
+
+ /* Prepare src texture state */
+ _mesa_BindTexture(target, texObj->Name);
+ _mesa_SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, filter);
+ _mesa_SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, filter);
+ if (target != GL_TEXTURE_RECTANGLE_ARB) {
+ _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, srcLevel);
+ _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel);
+ }
+ _mesa_SamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ _mesa_SamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ /* Always do our blits with no net sRGB decode or encode.
+ *
+ * However, if both the src and dst can be srgb decode/encoded, enable them
+ * so that we do any blending (from scaling or from MSAA resolves) in the
+ * right colorspace.
+ *
+ * Our choice of not doing any net encode/decode is from the GL 3.0
+ * specification:
+ *
+ * "Blit operations bypass the fragment pipeline. The only fragment
+ * operations which affect a blit are the pixel ownership test and the
+ * scissor test."
+ *
+ * The GL 4.4 specification disagrees and says that the sRGB part of the
+ * fragment pipeline applies, but this was found to break applications.
+ */
+ if (ctx->Extensions.EXT_texture_sRGB_decode) {
+ if (_mesa_get_format_color_encoding(rb->Format) == GL_SRGB &&
+ ctx->DrawBuffer->Visual.sRGBCapable) {
+ _mesa_SamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT,
+ GL_DECODE_EXT);
+ _mesa_set_framebuffer_srgb(ctx, GL_TRUE);
+ } else {
+ _mesa_SamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT,
+ GL_SKIP_DECODE_EXT);
+ /* set_framebuffer_srgb was set by _mesa_meta_begin(). */
+ }
+ }
+
+ if (!glsl_version) {
+ _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ _mesa_set_enable(ctx, target, GL_TRUE);
+ }
+
+ /* Prepare vertex data (the VBO was previously created and bound) */
+ {
+ struct vertex verts[4];
+ GLfloat s0, t0, s1, t1;
+
+ if (target == GL_TEXTURE_2D) {
+ const struct gl_texture_image *texImage
+ = _mesa_select_tex_image(ctx, texObj, target, srcLevel);
+ s0 = srcX0 / (float) texImage->Width;
+ s1 = srcX1 / (float) texImage->Width;
+ t0 = srcY0 / (float) texImage->Height;
+ t1 = srcY1 / (float) texImage->Height;
+ }
+ else {
+ assert(target == GL_TEXTURE_RECTANGLE_ARB ||
+ target == GL_TEXTURE_2D_MULTISAMPLE);
+ s0 = (float) srcX0;
+ s1 = (float) srcX1;
+ t0 = (float) srcY0;
+ t1 = (float) srcY1;
+ }
+
+ /* Silence valgrind warnings about reading uninitialized stack. */
+ memset(verts, 0, sizeof(verts));
+
+ /* setup vertex positions */
+ verts[0].x = -1.0F * flipX;
+ verts[0].y = -1.0F * flipY;
+ verts[1].x = 1.0F * flipX;
+ verts[1].y = -1.0F * flipY;
+ verts[2].x = 1.0F * flipX;
+ verts[2].y = 1.0F * flipY;
+ verts[3].x = -1.0F * flipX;
+ verts[3].y = 1.0F * flipY;
+
+ verts[0].tex[0] = s0;
+ verts[0].tex[1] = t0;
+ verts[1].tex[0] = s1;
+ verts[1].tex[1] = t0;
+ verts[2].tex[0] = s1;
+ verts[2].tex[1] = t1;
+ verts[3].tex[0] = s0;
+ verts[3].tex[1] = t1;
+
+ _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
+ }
+
+ /* setup viewport */
+ _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH);
+ _mesa_ColorMask(!do_depth, !do_depth, !do_depth, !do_depth);
+ _mesa_set_enable(ctx, GL_DEPTH_TEST, do_depth);
+ _mesa_DepthMask(do_depth);
+ _mesa_DepthFunc(GL_ALWAYS);
+
+ _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ /* Restore texture object state, the texture binding will
+ * be restored by _mesa_meta_end().
+ */
+ if (target != GL_TEXTURE_RECTANGLE_ARB) {
+ _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave);
+ _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave);
+ }
+
+ _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave);
+ _mesa_DeleteSamplers(1, &sampler);
+ if (tempTex)
+ _mesa_DeleteTextures(1, &tempTex);
+
+ return true;
+}
+
+/**
+ * Meta implementation of ctx->Driver.BlitFramebuffer() in terms
+ * of texture mapping and polygon rendering.
+ */
+void
+_mesa_meta_BlitFramebuffer(struct gl_context *ctx,
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ struct blit_state *blit = &ctx->Meta->Blit;
+ struct temp_texture *tex = _mesa_meta_get_temp_texture(ctx);
+ struct temp_texture *depthTex = _mesa_meta_get_temp_depth_texture(ctx);
+ const GLsizei maxTexSize = tex->MaxSize;
+ const GLint srcX = MIN2(srcX0, srcX1);
+ const GLint srcY = MIN2(srcY0, srcY1);
+ const GLint srcW = abs(srcX1 - srcX0);
+ const GLint srcH = abs(srcY1 - srcY0);
+ const GLint dstX = MIN2(dstX0, dstX1);
+ const GLint dstY = MIN2(dstY0, dstY1);
+ const GLint dstW = abs(dstX1 - dstX0);
+ const GLint dstH = abs(dstY1 - dstY0);
+ const GLint srcFlipX = (srcX1 - srcX0) / srcW;
+ const GLint srcFlipY = (srcY1 - srcY0) / srcH;
+ const GLint dstFlipX = (dstX1 - dstX0) / dstW;
+ const GLint dstFlipY = (dstY1 - dstY0) / dstH;
+ const GLint flipX = srcFlipX * dstFlipX;
+ const GLint flipY = srcFlipY * dstFlipY;
+
+ struct vertex verts[4];
+ GLboolean newTex;
+ const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
+ ctx->Extensions.ARB_fragment_shader;
+
+ /* In addition to falling back if the blit size is larger than the maximum
+ * texture size, fallback if the source is multisampled. This fallback can
+ * be removed once Mesa gets support ARB_texture_multisample.
+ */
+ if (srcW > maxTexSize || srcH > maxTexSize) {
+ /* XXX avoid this fallback */
+ goto fallback;
+ }
+
+ /* Multisample texture blit support requires texture multisample. */
+ if (ctx->ReadBuffer->Visual.samples > 0 &&
+ !ctx->Extensions.ARB_texture_multisample) {
+ goto fallback;
+ }
+
+ /* only scissor effects blit so save/clear all other relevant state */
+ _mesa_meta_begin(ctx, ~MESA_META_SCISSOR);
+
+ /* Try faster, direct texture approach first */
+ if (mask & GL_COLOR_BUFFER_BIT) {
+ if (blitframebuffer_texture(ctx, srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ filter, dstFlipX, dstFlipY,
+ use_glsl_version, false)) {
+ mask &= ~GL_COLOR_BUFFER_BIT;
+ if (mask == 0x0) {
+ _mesa_meta_end(ctx);
+ return;
+ }
+ }
+ }
+
+ if (mask & GL_DEPTH_BUFFER_BIT && use_glsl_version) {
+ if (blitframebuffer_texture(ctx, srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ filter, dstFlipX, dstFlipY,
+ use_glsl_version, true)) {
+ mask &= ~GL_DEPTH_BUFFER_BIT;
+ if (mask == 0x0) {
+ _mesa_meta_end(ctx);
+ return;
+ }
+ }
+ }
+
+ /* Choose between glsl version and fixed function version of
+ * BlitFramebuffer function.
+ */
+ if (use_glsl_version) {
+ setup_glsl_blit_framebuffer(ctx, blit, NULL, tex->Target);
+ }
+ else {
+ _mesa_meta_setup_ff_tnl_for_blit(&blit->VAO, &blit->VBO, 2);
+ }
+
+ /* Silence valgrind warnings about reading uninitialized stack. */
+ memset(verts, 0, sizeof(verts));
+
+ /* Continue with "normal" approach which involves copying the src rect
+ * into a temporary texture and is "blitted" by drawing a textured quad.
+ */
+ {
+ /* setup vertex positions */
+ verts[0].x = -1.0F * flipX;
+ verts[0].y = -1.0F * flipY;
+ verts[1].x = 1.0F * flipX;
+ verts[1].y = -1.0F * flipY;
+ verts[2].x = 1.0F * flipX;
+ verts[2].y = 1.0F * flipY;
+ verts[3].x = -1.0F * flipX;
+ verts[3].y = 1.0F * flipY;
+
+ }
+
+ if (!use_glsl_version)
+ _mesa_set_enable(ctx, tex->Target, GL_TRUE);
+
+ if (mask & GL_COLOR_BUFFER_BIT) {
+ const struct gl_framebuffer *readFb = ctx->ReadBuffer;
+ const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
+ const GLenum rb_base_format =
+ _mesa_base_tex_format(ctx, colorReadRb->InternalFormat);
+
+ /* Using the exact source rectangle to create the texture does incorrect
+ * linear filtering along the edges. So, allocate the texture extended along
+ * edges by one pixel in x, y directions.
+ */
+ _mesa_meta_setup_copypix_texture(ctx, tex,
+ srcX - 1, srcY - 1, srcW + 2, srcH + 2,
+ rb_base_format, filter);
+ /* texcoords (after texture allocation!) */
+ {
+ verts[0].tex[0] = 1.0F;
+ verts[0].tex[1] = 1.0F;
+ verts[1].tex[0] = tex->Sright - 1.0F;
+ verts[1].tex[1] = 1.0F;
+ verts[2].tex[0] = tex->Sright - 1.0F;
+ verts[2].tex[1] = tex->Ttop - 1.0F;
+ verts[3].tex[0] = 1.0F;
+ verts[3].tex[1] = tex->Ttop - 1.0F;
+
+ /* upload new vertex data */
+ _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
+ }
+
+ _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH);
+ _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE);
+ _mesa_DepthMask(GL_FALSE);
+ _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ mask &= ~GL_COLOR_BUFFER_BIT;
+ }
+
+ if ((mask & GL_DEPTH_BUFFER_BIT) &&
+ _mesa_is_desktop_gl(ctx) &&
+ ctx->Extensions.ARB_depth_texture &&
+ ctx->Extensions.ARB_fragment_program) {
+
+ GLuint *tmp = malloc(srcW * srcH * sizeof(GLuint));
+
+ if (tmp) {
+
+ newTex = _mesa_meta_alloc_texture(depthTex, srcW, srcH,
+ GL_DEPTH_COMPONENT);
+ _mesa_ReadPixels(srcX, srcY, srcW, srcH, GL_DEPTH_COMPONENT,
+ GL_UNSIGNED_INT, tmp);
+ _mesa_meta_setup_drawpix_texture(ctx, depthTex, newTex,
+ srcW, srcH, GL_DEPTH_COMPONENT,
+ GL_UNSIGNED_INT, tmp);
+
+ /* texcoords (after texture allocation!) */
+ {
+ verts[0].tex[0] = 0.0F;
+ verts[0].tex[1] = 0.0F;
+ verts[1].tex[0] = depthTex->Sright;
+ verts[1].tex[1] = 0.0F;
+ verts[2].tex[0] = depthTex->Sright;
+ verts[2].tex[1] = depthTex->Ttop;
+ verts[3].tex[0] = 0.0F;
+ verts[3].tex[1] = depthTex->Ttop;
+
+ /* upload new vertex data */
+ _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
+ }
+
+ if (!blit->DepthFP)
+ init_blit_depth_pixels(ctx);
+
+ _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP);
+ _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE);
+ _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE);
+ _mesa_DepthFunc(GL_ALWAYS);
+ _mesa_DepthMask(GL_TRUE);
+
+ _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH);
+ _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
+ _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ mask &= ~GL_DEPTH_BUFFER_BIT;
+
+ free(tmp);
+ }
+ }
+
+ if (mask & GL_STENCIL_BUFFER_BIT) {
+ /* XXX can't easily do stencil */
+ }
+
+ if (!use_glsl_version)
+ _mesa_set_enable(ctx, tex->Target, GL_FALSE);
+
+ _mesa_meta_end(ctx);
+
+fallback:
+ if (mask) {
+ _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1, mask, filter);
+ }
+}
+
+void
+_mesa_meta_glsl_blit_cleanup(struct blit_state *blit)
+{
+ if (blit->VAO) {
+ _mesa_DeleteVertexArrays(1, &blit->VAO);
+ blit->VAO = 0;
+ _mesa_DeleteBuffers(1, &blit->VBO);
+ blit->VBO = 0;
+ }
+ if (blit->DepthFP) {
+ _mesa_DeleteProgramsARB(1, &blit->DepthFP);
+ blit->DepthFP = 0;
+ }
+
+ _mesa_meta_blit_shader_table_cleanup(&blit->shaders);
+
+ _mesa_DeleteTextures(1, &blit->depthTex.TexObj);
+ blit->depthTex.TexObj = 0;
+}