meta: Add an accelerated glCopyTexSubImage using glBlitFramebuffer.

You'll note from the previous commits that there's something of a loop
here: You call CTSI, which calls BlitFB, then if things go wrong that
falls back to CTSI.  As a result, meta CTSI reaches over into blitfb to
tell it "no, don't try that fallback".

v2: Drop the _mesa_update_state(), which was only necessary due to use of
    _mesa_clip_blit() in _mesa_meta_BlitFramebuffer() in another patch
    series.
v3: Drop an _EXT suffix I copy-and-pasted.

Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> (v2)
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:
Eric Anholt 2014-02-28 13:23:25 -08:00
parent 70961c032f
commit 234db60954
4 changed files with 94 additions and 12 deletions

View File

@ -37,6 +37,7 @@
#include "main/arbprogram.h"
#include "main/arrayobj.h"
#include "main/blend.h"
#include "main/blit.h"
#include "main/bufferobj.h"
#include "main/buffers.h"
#include "main/colortab.h"
@ -94,7 +95,8 @@ static void meta_decompress_cleanup(struct decompress_state *decompress);
static void meta_drawpix_cleanup(struct drawpix_state *drawpix);
void
_mesa_meta_bind_fbo_image(struct gl_texture_image *texImage, GLuint layer)
_mesa_meta_bind_fbo_image(GLenum attachment,
struct gl_texture_image *texImage, GLuint layer)
{
struct gl_texture_object *texObj = texImage->TexObject;
int level = texImage->Level;
@ -103,17 +105,18 @@ _mesa_meta_bind_fbo_image(struct gl_texture_image *texImage, GLuint layer)
switch (target) {
case GL_TEXTURE_1D:
_mesa_FramebufferTexture1D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
attachment,
target,
texObj->Name,
level);
break;
case GL_TEXTURE_1D_ARRAY:
case GL_TEXTURE_2D_ARRAY:
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
case GL_TEXTURE_CUBE_MAP_ARRAY:
case GL_TEXTURE_3D:
_mesa_FramebufferTextureLayer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
attachment,
texObj->Name,
level,
layer);
@ -123,7 +126,7 @@ _mesa_meta_bind_fbo_image(struct gl_texture_image *texImage, GLuint layer)
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face;
_mesa_FramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
attachment,
target,
texObj->Name,
level);
@ -2728,6 +2731,77 @@ get_temp_image_type(struct gl_context *ctx, mesa_format format)
}
}
/**
* Attempts to wrap the destination texture in an FBO and use
* glBlitFramebuffer() to implement glCopyTexSubImage().
*/
static bool
copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims,
struct gl_texture_image *texImage,
GLint xoffset,
GLint yoffset,
GLint zoffset,
struct gl_renderbuffer *rb,
GLint x, GLint y,
GLsizei width, GLsizei height)
{
struct gl_texture_object *texObj = texImage->TexObject;
GLuint fbo;
bool success = false;
GLbitfield mask;
GLenum status;
if (!ctx->Extensions.ARB_framebuffer_object)
return false;
_mesa_unlock_texture(ctx, texObj);
_mesa_meta_begin(ctx, MESA_META_ALL);
_mesa_GenFramebuffers(1, &fbo);
_mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
if (rb->_BaseFormat == GL_DEPTH_STENCIL ||
rb->_BaseFormat == GL_DEPTH_COMPONENT) {
_mesa_meta_bind_fbo_image(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);
mask |= GL_STENCIL_BUFFER_BIT;
}
_mesa_DrawBuffer(GL_NONE);
} else {
_mesa_meta_bind_fbo_image(GL_COLOR_ATTACHMENT0, texImage, zoffset);
mask = GL_COLOR_BUFFER_BIT;
_mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
}
status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
goto out;
ctx->Meta->Blit.no_ctsi_fallback = true;
/* We skip the core BlitFramebuffer checks for format consistency, which
* are too strict for CopyTexImage. We know meta will be fine with format
* changes.
*/
_mesa_meta_BlitFramebuffer(ctx, x, y,
x + width, y + height,
xoffset, yoffset,
xoffset + width, yoffset + height,
mask, GL_NEAREST);
ctx->Meta->Blit.no_ctsi_fallback = false;
success = true;
out:
_mesa_lock_texture(ctx, texObj);
_mesa_DeleteFramebuffers(1, &fbo);
_mesa_meta_end(ctx);
return success;
}
/**
* Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions.
* Have to be careful with locking and meta state for pixel transfer.
@ -2745,11 +2819,14 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
GLint bpp;
void *buf;
/* The gl_renderbuffer is part of the interface for
* dd_function_table::CopyTexSubImage, but this implementation does not use
* it.
*/
(void) rb;
if (copytexsubimage_using_blit_framebuffer(ctx, dims,
texImage,
xoffset, yoffset, zoffset,
rb,
x, y,
width, height)) {
return;
}
/* Choose format/type for temporary image buffer */
format = _mesa_get_format_base_format(texImage->TexFormat);

View File

@ -253,6 +253,7 @@ struct blit_state
struct blit_shader_table shaders;
GLuint msaa_shaders[BLIT_MSAA_SHADER_COUNT];
struct temp_texture depthTex;
bool no_ctsi_fallback;
};
@ -505,6 +506,7 @@ void
_mesa_meta_glsl_generate_mipmap_cleanup(struct gen_mipmap_state *mipmap);
void
_mesa_meta_bind_fbo_image(struct gl_texture_image *texImage, GLuint layer);
_mesa_meta_bind_fbo_image(GLenum attachment,
struct gl_texture_image *texImage, GLuint layer);
#endif /* META_H */

View File

@ -419,6 +419,9 @@ blitframebuffer_texture(struct gl_context *ctx,
/* Fall back to doing a CopyTexSubImage to get the destination
* renderbuffer into a texture.
*/
if (ctx->Meta->Blit.no_ctsi_fallback)
return false;
if (rb->NumSamples > 1)
return false;

View File

@ -103,7 +103,7 @@ fallback_required(struct gl_context *ctx, GLenum target,
_mesa_GenFramebuffers(1, &mipmap->FBO);
_mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO);
_mesa_meta_bind_fbo_image(baseImage, 0);
_mesa_meta_bind_fbo_image(GL_COLOR_ATTACHMENT0, baseImage, 0);
status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
@ -317,7 +317,7 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
_mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
verts, GL_DYNAMIC_DRAW_ARB);
_mesa_meta_bind_fbo_image(dstImage, layer);
_mesa_meta_bind_fbo_image(GL_COLOR_ATTACHMENT0, dstImage, layer);
/* sanity check */
if (_mesa_CheckFramebufferStatus(GL_FRAMEBUFFER) !=