diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index 80f3649..eecf186 100644 --- a/src/vrend_renderer.c +++ b/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);