virgl: implement EXT_multisampled_render_to_texture
Signed-off-by: Italo Nicola <italonicola@collabora.com>
Reviewed-by: Gert Wollny <gert.wollny@collabora.com>
diff --git a/src/virgl_hw.h b/src/virgl_hw.h
index fc6f733..dce8cbc 100644
--- a/src/virgl_hw.h
+++ b/src/virgl_hw.h
@@ -441,6 +441,7 @@
#define VIRGL_CAP_V2_MEMINFO (1 << 3)
#define VIRGL_CAP_V2_STRING_MARKER (1 << 4)
#define VIRGL_CAP_V2_DIFFERENT_GPU (1 << 5)
+#define VIRGL_CAP_V2_IMPLICIT_MSAA (1 << 6)
/* virgl bind flags - these are compatible with mesa 10.5 gallium.
* but are fixed, no other should be passed to virgl either.
diff --git a/src/virgl_protocol.h b/src/virgl_protocol.h
index 19068ad..ec3c458 100644
--- a/src/virgl_protocol.h
+++ b/src/virgl_protocol.h
@@ -57,6 +57,7 @@
VIRGL_OBJECT_SURFACE,
VIRGL_OBJECT_QUERY,
VIRGL_OBJECT_STREAMOUT_TARGET,
+ VIRGL_OBJECT_MSAA_SURFACE,
VIRGL_MAX_OBJECTS,
};
@@ -345,6 +346,10 @@
#define VIRGL_OBJ_SURFACE_TEXTURE_LEVEL 4
#define VIRGL_OBJ_SURFACE_TEXTURE_LAYERS 5
+/* create surface with implicit MSAA support (for EXT_multisample_render_to_texture) */
+#define VIRGL_OBJ_MSAA_SURFACE_SIZE (VIRGL_OBJ_SURFACE_SIZE + 1)
+#define VIRGL_OBJ_SURFACE_SAMPLE_COUNT 6
+
/* create streamout target */
#define VIRGL_OBJ_STREAMOUT_SIZE 4
#define VIRGL_OBJ_STREAMOUT_HANDLE 1
diff --git a/src/vrend_blitter.c b/src/vrend_blitter.c
index a96b6bc..41bd90e 100644
--- a/src/vrend_blitter.c
+++ b/src/vrend_blitter.c
@@ -748,7 +748,7 @@
glUseProgram(prog_id);
glBindFramebuffer(GL_FRAMEBUFFER, blit_ctx->fb_id);
- vrend_fb_bind_texture_id(dst_res, blit_views[1], 0, info->dst.level, info->dst.box.z);
+ vrend_fb_bind_texture_id(dst_res, blit_views[1], 0, info->dst.level, info->dst.box.z, 0);
buffers = GL_COLOR_ATTACHMENT0;
glDrawBuffers(1, &buffers);
@@ -783,7 +783,7 @@
uint32_t layer = (dst_res->target == GL_TEXTURE_CUBE_MAP) ? info->dst.box.z : dst_z;
glBindFramebuffer(GL_FRAMEBUFFER, blit_ctx->fb_id);
- vrend_fb_bind_texture_id(dst_res, blit_views[1], 0, info->dst.level, layer);
+ vrend_fb_bind_texture_id(dst_res, blit_views[1], 0, info->dst.level, layer, 0);
buffers = GL_COLOR_ATTACHMENT0;
glDrawBuffers(1, &buffers);
diff --git a/src/vrend_debug.c b/src/vrend_debug.c
index b888ad2..a6e2896 100644
--- a/src/vrend_debug.c
+++ b/src/vrend_debug.c
@@ -94,7 +94,8 @@
"SAMPLER_STATE",
"SURFACE",
"QUERY",
- "STREAMOUT_TARGET"
+ "STREAMOUT_TARGET",
+ "MSAA_SURFACE"
};
const char *vrend_get_comand_name(enum virgl_context_cmd cmd)
diff --git a/src/vrend_decode.c b/src/vrend_decode.c
index 91f5f24..35ccc23 100644
--- a/src/vrend_decode.c
+++ b/src/vrend_decode.c
@@ -612,21 +612,34 @@
return 0;
}
-static int vrend_decode_create_surface(struct vrend_context *ctx, const uint32_t *buf, uint32_t handle, uint16_t length)
+static int vrend_decode_create_surface_common(struct vrend_context *ctx, const uint32_t *buf, uint32_t handle, uint32_t sample_count)
{
uint32_t res_handle, format, val0, val1;
- int ret;
-
- if (length != VIRGL_OBJ_SURFACE_SIZE)
- return EINVAL;
res_handle = get_buf_entry(buf, VIRGL_OBJ_SURFACE_RES_HANDLE);
format = get_buf_entry(buf, VIRGL_OBJ_SURFACE_FORMAT);
/* decide later if these are texture or buffer */
val0 = get_buf_entry(buf, VIRGL_OBJ_SURFACE_BUFFER_FIRST_ELEMENT);
val1 = get_buf_entry(buf, VIRGL_OBJ_SURFACE_BUFFER_LAST_ELEMENT);
- ret = vrend_create_surface(ctx, handle, res_handle, format, val0, val1);
- return ret;
+
+ return vrend_create_surface(ctx, handle, res_handle, format, val0, val1, sample_count);
+}
+
+static int vrend_decode_create_surface(struct vrend_context *ctx, const uint32_t *buf, uint32_t handle, uint16_t length)
+{
+ if (length != VIRGL_OBJ_SURFACE_SIZE)
+ return EINVAL;
+
+ return vrend_decode_create_surface_common(ctx, buf, handle, 0);
+}
+
+static int vrend_decode_create_msaa_surface(struct vrend_context *ctx, const uint32_t *buf, uint32_t handle, uint16_t length)
+{
+ if (length != VIRGL_OBJ_MSAA_SURFACE_SIZE)
+ return EINVAL;
+
+ uint32_t sample_count = get_buf_entry(buf, VIRGL_OBJ_SURFACE_SAMPLE_COUNT);
+ return vrend_decode_create_surface_common(ctx, buf, handle, sample_count);
}
static int vrend_decode_create_sampler_view(struct vrend_context *ctx, const uint32_t *buf, uint32_t handle, uint16_t length)
@@ -789,6 +802,9 @@
case VIRGL_OBJECT_STREAMOUT_TARGET:
ret = vrend_decode_create_stream_output_target(ctx, buf, handle, length);
break;
+ case VIRGL_OBJECT_MSAA_SURFACE:
+ ret = vrend_decode_create_msaa_surface(ctx, buf, handle, length);
+ break;
default:
return EINVAL;
}
diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
index 7d1d7e8..2d534ef 100644
--- a/src/vrend_renderer.c
+++ b/src/vrend_renderer.c
@@ -202,6 +202,7 @@
feat_txqs,
feat_ubo,
feat_viewport_array,
+ feat_implicit_msaa,
feat_last,
};
@@ -302,6 +303,7 @@
FEAT(txqs, 45, UNAVAIL, "GL_ARB_shader_texture_image_samples" ),
FEAT(ubo, 31, 30, "GL_ARB_uniform_buffer_object" ),
FEAT(viewport_array, 41, UNAVAIL, "GL_ARB_viewport_array", "GL_OES_viewport_array"),
+ FEAT(implicit_msaa, UNAVAIL, UNAVAIL, "GL_EXT_multisampled_render_to_texture"),
};
struct global_renderer_state {
@@ -451,6 +453,7 @@
GLuint res_handle;
GLuint format;
GLuint val0, val1;
+ GLuint nr_samples;
struct vrend_resource *texture;
};
@@ -959,25 +962,27 @@
#define GLES_WARN_DEPTH_CLEAR 14
#define GLES_WARN_LOGIC_OP 15
#define GLES_WARN_TIMESTAMP 16
+#define GLES_WARN_IMPLICIT_MSAA_SURFACE 17
MAYBE_UNUSED
static const char *vrend_gles_warn_strings[] = {
- [GLES_WARN_NONE] = "None",
- [GLES_WARN_STIPPLE] = "Stipple",
- [GLES_WARN_POLYGON_MODE] = "Polygon Mode",
- [GLES_WARN_DEPTH_RANGE] = "Depth Range",
- [GLES_WARN_POINT_SIZE] = "Point Size",
- [GLES_WARN_SEAMLESS_CUBE_MAP] = "Seamless Cube Map",
- [GLES_WARN_LOD_BIAS] = "Lod Bias",
- [GLES_WARN_TEXTURE_RECT] = "Texture Rect",
- [GLES_WARN_OFFSET_LINE] = "Offset Line",
- [GLES_WARN_OFFSET_POINT] = "Offset Point",
- [GLES_WARN_FLATSHADE_FIRST] = "Flatshade First",
- [GLES_WARN_LINE_SMOOTH] = "Line Smooth",
- [GLES_WARN_POLY_SMOOTH] = "Poly Smooth",
- [GLES_WARN_DEPTH_CLEAR] = "Depth Clear",
- [GLES_WARN_LOGIC_OP] = "LogicOp",
- [GLES_WARN_TIMESTAMP] = "GL_TIMESTAMP",
+ [GLES_WARN_NONE] = "None",
+ [GLES_WARN_STIPPLE] = "Stipple",
+ [GLES_WARN_POLYGON_MODE] = "Polygon Mode",
+ [GLES_WARN_DEPTH_RANGE] = "Depth Range",
+ [GLES_WARN_POINT_SIZE] = "Point Size",
+ [GLES_WARN_SEAMLESS_CUBE_MAP] = "Seamless Cube Map",
+ [GLES_WARN_LOD_BIAS] = "Lod Bias",
+ [GLES_WARN_TEXTURE_RECT] = "Texture Rect",
+ [GLES_WARN_OFFSET_LINE] = "Offset Line",
+ [GLES_WARN_OFFSET_POINT] = "Offset Point",
+ [GLES_WARN_FLATSHADE_FIRST] = "Flatshade First",
+ [GLES_WARN_LINE_SMOOTH] = "Line Smooth",
+ [GLES_WARN_POLY_SMOOTH] = "Poly Smooth",
+ [GLES_WARN_DEPTH_CLEAR] = "Depth Clear",
+ [GLES_WARN_LOGIC_OP] = "LogicOp",
+ [GLES_WARN_TIMESTAMP] = "GL_TIMESTAMP",
+ [GLES_WARN_IMPLICIT_MSAA_SURFACE] = "Implicit MSAA Surface",
};
static void __report_gles_warn(MAYBE_UNUSED const char *fname,
@@ -1849,7 +1854,8 @@
int vrend_create_surface(struct vrend_context *ctx,
uint32_t handle,
uint32_t res_handle, uint32_t format,
- uint32_t val0, uint32_t val1)
+ uint32_t val0, uint32_t val1,
+ uint32_t nr_samples)
{
struct vrend_surface *surf;
struct vrend_resource *res;
@@ -1876,6 +1882,7 @@
surf->val0 = val0;
surf->val1 = val1;
surf->id = res->id;
+ surf->nr_samples = nr_samples;
if (!has_bit(res->storage_bits, VREND_STORAGE_GL_BUFFER) &&
has_bit(res->storage_bits, VREND_STORAGE_GL_IMMUTABLE)) {
@@ -2305,6 +2312,41 @@
return 0;
}
+static void vrend_framebuffer_texture_2d(struct vrend_resource *res,
+ GLenum target, GLenum attachment,
+ GLenum textarget, uint32_t texture,
+ int32_t level, uint32_t samples)
+{
+ assert(textarget == GL_TEXTURE_2D);
+
+ if (samples == 0) {
+ glFramebufferTexture2D(target, attachment, textarget, texture, level);
+ } else if (!has_feature(feat_implicit_msaa)) {
+ /* fallback to non-msaa */
+ report_gles_warn(vrend_state.current_ctx, GLES_WARN_IMPLICIT_MSAA_SURFACE);
+ glFramebufferTexture2D(target, attachment, textarget, texture, level);
+ } else if (attachment == GL_COLOR_ATTACHMENT0){
+ glFramebufferTexture2DMultisampleEXT(target, attachment, textarget,
+ texture, level, samples);
+ } else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_DEPTH_ATTACHMENT) {
+ GLenum internalformat =
+ attachment == GL_STENCIL_ATTACHMENT ? GL_STENCIL_INDEX8 : GL_DEPTH_COMPONENT16;
+
+ glGenRenderbuffers(1, &res->rbo_id);
+ glBindRenderbuffer(GL_RENDERBUFFER, res->rbo_id);
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
+ internalformat, res->base.width0,
+ res->base.height0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
+ GL_RENDERBUFFER, res->rbo_id);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ } else {
+ /* unsupported attachment for EXT_multisampled_render_to_texture, fallback to non-msaa */
+ report_gles_warn(vrend_state.current_ctx, GLES_WARN_IMPLICIT_MSAA_SURFACE);
+ glFramebufferTexture2D(target, attachment, textarget, texture, level);
+ }
+}
+
static
void debug_texture(MAYBE_UNUSED const char *f, const struct vrend_resource *gt)
{
@@ -2333,9 +2375,8 @@
}
void vrend_fb_bind_texture_id(struct vrend_resource *res,
- int id,
- int idx,
- uint32_t level, uint32_t layer)
+ int id, int idx, uint32_t level,
+ uint32_t layer, uint32_t samples)
{
const struct util_format_description *desc = util_format_description(res->base.format);
GLenum attachment = GL_COLOR_ATTACHMENT0 + idx;
@@ -2380,8 +2421,9 @@
glFramebufferTexture(GL_FRAMEBUFFER, attachment,
id, level);
else
- glFramebufferTexture2D(GL_FRAMEBUFFER, attachment,
- GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, id, level);
+ vrend_framebuffer_texture_2d(res, GL_FRAMEBUFFER, attachment,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer,
+ id, level, samples);
break;
case GL_TEXTURE_1D:
glFramebufferTexture1D(GL_FRAMEBUFFER, attachment,
@@ -2389,8 +2431,8 @@
break;
case GL_TEXTURE_2D:
default:
- glFramebufferTexture2D(GL_FRAMEBUFFER, attachment,
- res->target, id, level);
+ vrend_framebuffer_texture_2d(res, GL_FRAMEBUFFER, attachment,
+ res->target, id, level, samples);
break;
}
@@ -2413,7 +2455,7 @@
int idx,
uint32_t level, uint32_t layer)
{
- vrend_fb_bind_texture_id(res, res->id, idx, level, layer);
+ vrend_fb_bind_texture_id(res, res->id, idx, level, layer, 0);
}
static void vrend_hw_set_zsurf_texture(struct vrend_context *ctx)
@@ -2431,7 +2473,8 @@
return;
vrend_fb_bind_texture_id(surf->texture, surf->id, 0, surf->val0,
- first_layer != last_layer ? 0xffffffff : first_layer);
+ first_layer != last_layer ? 0xffffffff : first_layer,
+ surf->nr_samples);
}
}
@@ -2449,7 +2492,8 @@
uint32_t last_layer = (sub_ctx->surf[index]->val1 >> 16) & 0xffff;
vrend_fb_bind_texture_id(surf->texture, surf->id, index, surf->val0,
- first_layer != last_layer ? 0xffffffff : first_layer);
+ first_layer != last_layer ? 0xffffffff : first_layer,
+ surf->nr_samples);
}
}
@@ -7193,6 +7237,10 @@
free(res->ptr);
}
+ if (res->rbo_id) {
+ glDeleteRenderbuffers(1, &res->rbo_id);
+ }
+
if (has_bit(res->storage_bits, VREND_STORAGE_GL_MEMOBJ)) {
glDeleteMemoryObjectsEXT(1, &res->memobj);
}
@@ -9057,7 +9105,7 @@
n_layers = info->dst.box.depth;
for (i = 0; i < n_layers; i++) {
glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
- vrend_fb_bind_texture_id(src_res, blitter_views[0], 0, info->src.level, info->src.box.z + i);
+ vrend_fb_bind_texture_id(src_res, blitter_views[0], 0, info->src.level, info->src.box.z + i, 0);
if (make_intermediate_copy) {
int level_width = u_minify(src_res->base.width0, info->src.level);
@@ -9075,7 +9123,7 @@
}
glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
- vrend_fb_bind_texture_id(dst_res, blitter_views[1], 0, info->dst.level, info->dst.box.z + i);
+ vrend_fb_bind_texture_id(dst_res, blitter_views[1], 0, info->dst.level, info->dst.box.z + i, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
if (has_feature(feat_srgb_write_control)) {
@@ -10483,6 +10531,9 @@
if (has_feature(feat_khr_debug))
caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_STRING_MARKER;
+ if (has_feature(feat_implicit_msaa))
+ caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_IMPLICIT_MSAA;
+
if (vrend_winsys_different_gpu())
caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_DIFFERENT_GPU;
}
diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h
index 55d6b94..b132384 100644
--- a/src/vrend_renderer.h
+++ b/src/vrend_renderer.h
@@ -74,6 +74,10 @@
GLuint tbo_tex_id;/* tbos have two ids to track */
bool y_0_top;
+ /* used for keeping track of multisampled renderbuffer for
+ * GL_EXT_multisampled_render_to_texture. */
+ GLuint rbo_id;
+
/* Pointer to system memory storage for this resource. Only valid for
* VREND_RESOURCE_STORAGE_GUEST_ELSE_SYSTEM buffer storage.
*/
@@ -204,7 +208,8 @@
int vrend_create_surface(struct vrend_context *ctx,
uint32_t handle,
uint32_t res_handle, uint32_t format,
- uint32_t val0, uint32_t val1);
+ uint32_t val0, uint32_t val1,
+ uint32_t nr_samples);
int vrend_create_sampler_view(struct vrend_context *ctx,
uint32_t handle,
uint32_t res_handle, uint32_t format,
@@ -347,9 +352,8 @@
uint32_t res_handle);
void vrend_fb_bind_texture_id(struct vrend_resource *res,
- int id,
- int idx,
- uint32_t level, uint32_t layer);
+ int id, int idx, uint32_t level,
+ uint32_t layer, uint32_t samples);
void vrend_set_tess_state(struct vrend_context *ctx, const float tess_factors[6]);