vrend: blit_int factor out test whether the fbo blit can be done

Related: https://gitlab.freedesktop.org/virgl/virglrenderer/-/issues/125

Signed-off-by: Gert Wollny <gert.wollny@collabora.com>
Reviewed-by: Corentin Noël <corentin.noel@collabora.com>.
macos/master
Gert Wollny 3 years ago
parent f50c878d61
commit 3b5eb5f9b5
  1. 222
      src/vrend_renderer.c

@ -46,6 +46,7 @@
#include "vrend_renderer.h"
#include "vrend_debug.h"
#include "vrend_winsys.h"
#include "vrend_blitter.h"
#include "virgl_util.h"
@ -9101,7 +9102,6 @@ static bool vrend_blit_needs_redblue_swizzle(struct vrend_resource *src_res,
return needs_redblue_swizzle;
}
static void vrend_renderer_prepare_blit_extra_info(struct vrend_context *ctx,
struct vrend_resource *src_res,
struct vrend_resource *dst_res,
@ -9155,46 +9155,23 @@ static void vrend_renderer_prepare_blit_extra_info(struct vrend_context *ctx,
}
}
static void vrend_renderer_blit_int(struct vrend_context *ctx,
struct vrend_resource *src_res,
struct vrend_resource *dst_res,
const struct pipe_blit_info *info)
/* Prepare the extra blit info and return true if a FBO blit can be used. */
static bool vrend_renderer_prepare_blit(struct vrend_context *ctx,
struct vrend_resource *src_res,
struct vrend_resource *dst_res,
const struct vrend_blit_info *info)
{
struct vrend_blit_info blit_info = {
.b = *info,
.src_view = src_res->id,
.dst_view = dst_res->id,
.needs_swizzle = false,
.can_fbo_blit = true,
.gl_filter = convert_mag_filter(info->filter),
.swizzle = {0, 1, 2, 3},
};
GLbitfield glmask = 0;
int n_layers = 1, i;
bool make_intermediate_copy = false;
GLuint intermediate_fbo = 0;
struct vrend_resource *intermediate_copy = 0;
/* We create the texture views in this function instead of doing it in
* vrend_renderer_prepare_blit_extra_info because we also delete them here */
if ((src_res->base.format != info->src.format) && has_feature(feat_texture_view))
blit_info.src_view = vrend_make_view(src_res, info->src.format);
if ((dst_res->base.format != info->dst.format) && has_feature(feat_texture_view))
blit_info.dst_view = vrend_make_view(dst_res, info->dst.format);
vrend_renderer_prepare_blit_extra_info(ctx, src_res, dst_res, &blit_info);
bool use_gl = !blit_info.can_fbo_blit;
if (!info->can_fbo_blit)
return false;
/* if we can't make FBO's use the fallback path */
if (!vrend_format_can_render(src_res->base.format) &&
!vrend_format_is_ds(src_res->base.format))
use_gl = true;
if (!vrend_format_can_render(dst_res->base.format) &&
!vrend_format_is_ds(dst_res->base.format))
use_gl = true;
return false;
if (!vrend_format_can_render(src_res->base.format) &&
!vrend_format_is_ds(src_res->base.format))
return false;
/* different depth formats */
if (vrend_format_is_ds(src_res->base.format) &&
@ -9202,76 +9179,74 @@ static void vrend_renderer_blit_int(struct vrend_context *ctx,
if (src_res->base.format != dst_res->base.format) {
if (!(src_res->base.format == PIPE_FORMAT_S8_UINT_Z24_UNORM &&
(dst_res->base.format == PIPE_FORMAT_Z24X8_UNORM))) {
use_gl = true;
return false;
}
}
}
/* glBlitFramebuffer - can support depth stencil with NEAREST
which we use for mipmaps */
if ((info->mask & (PIPE_MASK_Z | PIPE_MASK_S)) && info->filter == PIPE_TEX_FILTER_LINEAR)
use_gl = true;
if ((info->b.mask & (PIPE_MASK_Z | PIPE_MASK_S)) && info->gl_filter == PIPE_TEX_FILTER_LINEAR)
return false;
/* since upstream mesa change
* https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5034
* an imported RGBX texture uses GL_RGB8 as internal format while
* in virgl_formats, we use GL_RGBA8 internal format for RGBX texutre.
* on GLES host, glBlitFramebuffer doesn't work in such case. */
if (vrend_state.use_gles && !use_gl &&
info->mask & PIPE_MASK_RGBA &&
if (vrend_state.use_gles &&
info->b.mask & PIPE_MASK_RGBA &&
src_res->base.format == VIRGL_FORMAT_R8G8B8X8_UNORM &&
dst_res->base.format == VIRGL_FORMAT_R8G8B8X8_UNORM &&
has_bit(src_res->storage_bits, VREND_STORAGE_EGL_IMAGE) !=
has_bit(dst_res->storage_bits, VREND_STORAGE_EGL_IMAGE) &&
(src_res->base.nr_samples || dst_res->base.nr_samples)) {
use_gl = true;
return false;
}
if (use_gl) {;}
/* GLES generally doesn't support blitting to a multi-sample FB, and also not
* from a multi-sample FB where the regions are not exatly the same or the
* source and target format are different. For
* downsampling DS blits to zero samples we solve this by doing two blits */
else if (vrend_state.use_gles &&
((dst_res->base.nr_samples > 0) ||
((info->mask & PIPE_MASK_RGBA) &&
(src_res->base.nr_samples > 0) &&
(info->src.box.x != info->dst.box.x ||
info->src.box.width != info->dst.box.width ||
blit_info.dst_y1 != blit_info.src_y1 ||
blit_info.dst_y2 != blit_info.src_y2 ||
info->src.format != info->dst.format))
)
) {
if (vrend_state.use_gles &&
((dst_res->base.nr_samples > 0) ||
((info->b.mask & PIPE_MASK_RGBA) &&
(src_res->base.nr_samples > 0) &&
(info->b.src.box.x != info->b.dst.box.x ||
info->b.src.box.width != info->b.dst.box.width ||
info->dst_y1 != info->src_y1 || info->dst_y2 != info->src_y2 ||
info->b.src.format != info->b.dst.format))
)) {
VREND_DEBUG(dbg_blit, ctx, "Use GL fallback because dst:ms:%d src:ms:%d (%d %d %d %d) -> (%d %d %d %d)\n",
dst_res->base.nr_samples, src_res->base.nr_samples, info->src.box.x, info->src.box.x + info->src.box.width,
blit_info.src_y1, blit_info.src_y2, info->dst.box.x, info->dst.box.x + info->dst.box.width,
blit_info.dst_y1, blit_info.dst_y2);
use_gl = true;
dst_res->base.nr_samples, src_res->base.nr_samples, info->b.src.box.x, info->b.src.box.x + info->b.src.box.width,
info->src_y1, info->src_y2, info->b.dst.box.x, info->b.dst.box.x + info->b.dst.box.width, info->dst_y1, info->dst_y2);
return false;
}
/* for 3D mipmapped blits - hand roll time */
else if (info->src.box.depth != info->dst.box.depth)
use_gl = true;
if (use_gl) {
blit_info.has_texture_srgb_decode = has_feature(feat_texture_srgb_decode);
blit_info.has_srgb_write_control = has_feature(feat_srgb_write_control);
/* for 3D mipmapped blits - hand roll time */
if (info->b.src.box.depth != info->b.dst.box.depth)
return false;
VREND_DEBUG(dbg_blit, ctx, "BLIT_INT: use GL fallback\n");
vrend_renderer_blit_gl(ctx, src_res, dst_res, &blit_info);
vrend_sync_make_current(ctx->sub->gl_context);
goto cleanup;
}
return true;
}
if (info->mask & PIPE_MASK_Z)
static void vrend_renderer_blit_fbo(struct vrend_context *ctx,
struct vrend_resource *src_res,
struct vrend_resource *dst_res,
const struct vrend_blit_info *info)
{
GLbitfield glmask = 0;
if (info->b.mask & PIPE_MASK_Z)
glmask |= GL_DEPTH_BUFFER_BIT;
if (info->mask & PIPE_MASK_S)
if (info->b.mask & PIPE_MASK_S)
glmask |= GL_STENCIL_BUFFER_BIT;
if (info->mask & PIPE_MASK_RGBA)
if (info->b.mask & PIPE_MASK_RGBA)
glmask |= GL_COLOR_BUFFER_BIT;
if (info->scissor_enable) {
glScissor(info->scissor.minx, info->scissor.miny, info->scissor.maxx - info->scissor.minx, info->scissor.maxy - info->scissor.miny);
if (info->b.scissor_enable) {
glScissor(info->b.scissor.minx, info->b.scissor.miny,
info->b.scissor.maxx - info->b.scissor.minx,
info->b.scissor.maxy - info->b.scissor.miny);
ctx->sub->scissor_state_dirty = (1 << 0);
glEnable(GL_SCISSOR_TEST);
} else
@ -9287,14 +9262,18 @@ static void vrend_renderer_blit_int(struct vrend_context *ctx,
* limitations on GLES first copy the full frame to a non-multisample
* surface and then copy the according area to the final target surface.
*/
bool make_intermediate_copy = false;
GLuint intermediate_fbo = 0;
struct vrend_resource *intermediate_copy = 0;
if (vrend_state.use_gles &&
(info->mask & PIPE_MASK_ZS) &&
(info->b.mask & PIPE_MASK_ZS) &&
((src_res->base.nr_samples > 0) &&
(src_res->base.nr_samples != dst_res->base.nr_samples)) &&
((info->src.box.x != info->dst.box.x) ||
(blit_info.src_y1 != blit_info.dst_y1) ||
(info->src.box.width != info->dst.box.width) ||
(blit_info.src_y2 != blit_info.dst_y2))) {
((info->b.src.box.x != info->b.dst.box.x) ||
(info->src_y1 != info->dst_y1) ||
(info->b.src.box.width != info->b.dst.box.width) ||
(info->src_y2 != info->dst_y2))) {
make_intermediate_copy = true;
@ -9305,7 +9284,7 @@ static void vrend_renderer_blit_int(struct vrend_context *ctx,
args.width = src_res->base.width0;
args.height = src_res->base.height0;
args.depth = src_res->base.depth0;
args.format = info->src.format;
args.format = info->b.src.format;
args.target = src_res->base.target;
args.last_level = src_res->base.last_level;
args.array_size = src_res->base.array_size;
@ -9325,47 +9304,47 @@ static void vrend_renderer_blit_int(struct vrend_context *ctx,
}
glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
if (info->mask & PIPE_MASK_RGBA)
if (info->b.mask & PIPE_MASK_RGBA)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D, 0, 0);
else
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
if (info->mask & PIPE_MASK_RGBA)
if (info->b.mask & PIPE_MASK_RGBA)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D, 0, 0);
else if (info->mask & (PIPE_MASK_Z | PIPE_MASK_S))
else if (info->b.mask & (PIPE_MASK_Z | PIPE_MASK_S))
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, 0, 0);
if (info->src.box.depth == info->dst.box.depth)
n_layers = info->dst.box.depth;
for (i = 0; i < n_layers; i++) {
int n_layers = info->b.src.box.depth == info->b.dst.box.depth ? info->b.dst.box.depth : 1;
for (int i = 0; i < n_layers; i++) {
glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
vrend_fb_bind_texture_id(src_res, blit_info.src_view, 0, info->src.level, info->src.box.z + i, 0);
vrend_fb_bind_texture_id(src_res, info->src_view, 0, info->b.src.level, info->b.src.box.z + i, 0);
if (make_intermediate_copy) {
int level_width = u_minify(src_res->base.width0, info->src.level);
int level_height = u_minify(src_res->base.width0, info->src.level);
int level_width = u_minify(src_res->base.width0, info->b.src.level);
int level_height = u_minify(src_res->base.width0, info->b.src.level);
glBindFramebuffer(GL_FRAMEBUFFER, intermediate_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, 0, 0);
vrend_fb_bind_texture(intermediate_copy, 0, info->src.level, info->src.box.z + i);
vrend_fb_bind_texture(intermediate_copy, 0, info->b.src.level, info->b.src.box.z + i);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediate_fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
glBlitFramebuffer(0, 0, level_width, level_height,
0, 0, level_width, level_height,
glmask, blit_info.gl_filter);
glmask, info->gl_filter);
}
glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
vrend_fb_bind_texture_id(dst_res, blit_info.dst_view, 0, info->dst.level, info->dst.box.z + i, 0);
vrend_fb_bind_texture_id(dst_res, info->dst_view, 0, info->b.dst.level, info->b.dst.box.z + i, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
if (has_feature(feat_srgb_write_control)) {
if (util_format_is_srgb(info->dst.format) ||
util_format_is_srgb(info->src.format))
if (util_format_is_srgb(info->b.dst.format) ||
util_format_is_srgb(info->b.src.format))
glEnable(GL_FRAMEBUFFER_SRGB);
else
glDisable(GL_FRAMEBUFFER_SRGB);
@ -9373,15 +9352,15 @@ static void vrend_renderer_blit_int(struct vrend_context *ctx,
glBindFramebuffer(GL_READ_FRAMEBUFFER, intermediate_fbo);
glBlitFramebuffer(info->src.box.x,
blit_info.src_y1,
info->src.box.x + info->src.box.width,
blit_info.src_y2,
info->dst.box.x,
blit_info.dst_y1,
info->dst.box.x + info->dst.box.width,
blit_info.dst_y2,
glmask, blit_info.gl_filter);
glBlitFramebuffer(info->b.src.box.x,
info->src_y1,
info->b.src.box.x + info->b.src.box.width,
info->src_y2,
info->b.dst.box.x,
info->dst_y1,
info->b.dst.box.x + info->b.dst.box.width,
info->dst_y2,
glmask, info->gl_filter);
}
glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
@ -9415,7 +9394,42 @@ static void vrend_renderer_blit_int(struct vrend_context *ctx,
else
glDisable(GL_SCISSOR_TEST);
cleanup:
}
static void vrend_renderer_blit_int(struct vrend_context *ctx,
struct vrend_resource *src_res,
struct vrend_resource *dst_res,
const struct pipe_blit_info *info)
{
struct vrend_blit_info blit_info = {
.b = *info,
.src_view = src_res->id,
.dst_view = dst_res->id,
.swizzle = {0, 1, 2, 3}
};
/* We create the texture views in this function instead of doing it in
* vrend_renderer_prepare_blit_extra_info because we also delete them here */
if ((src_res->base.format != info->src.format) && has_feature(feat_texture_view))
blit_info.src_view = vrend_make_view(src_res, info->src.format);
if ((dst_res->base.format != info->dst.format) && has_feature(feat_texture_view))
blit_info.dst_view = vrend_make_view(dst_res, info->dst.format);
vrend_renderer_prepare_blit_extra_info(ctx, src_res, dst_res, &blit_info);
if (vrend_renderer_prepare_blit(ctx, src_res, dst_res, &blit_info)) {
VREND_DEBUG(dbg_blit, ctx, "BLIT_INT: use FBO blit\n");
vrend_renderer_blit_fbo(ctx, src_res, dst_res, &blit_info);
} else {
blit_info.has_srgb_write_control = has_feature(feat_texture_srgb_decode);
blit_info.has_texture_srgb_decode = has_feature(feat_srgb_write_control);
VREND_DEBUG(dbg_blit, ctx, "BLIT_INT: use GL fallback\n");
vrend_renderer_blit_gl(ctx, src_res, dst_res, &blit_info);
vrend_sync_make_current(ctx->sub->gl_context);
}
if (blit_info.src_view != src_res->id)
glDeleteTextures(1, &blit_info.src_view);

Loading…
Cancel
Save