From 65dceac12d7f3b941b3d4d96eb5dd1349dcc3540 Mon Sep 17 00:00:00 2001 From: Andrew Wesie Date: Sat, 6 Oct 2018 19:20:46 -0500 Subject: [PATCH] st/mesa: accelerate glGetTexImage PBO downloads --- src/mesa/state_tracker/st_cb_texture.c | 193 ++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 7 deletions(-) diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index e6e27a852..c9e182a91 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -1392,6 +1392,176 @@ try_pbo_upload(struct gl_context *ctx, GLuint dims, return success; } +static bool +try_pbo_download(struct st_context *st, + struct gl_texture_image *texImage, + enum pipe_format src_format, enum pipe_format dst_format, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint width, GLint height, GLint depth, + const struct gl_pixelstore_attrib *pack, void *pixels) +{ + struct st_texture_image *stImage = st_texture_image(texImage); + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_resource *texture = stImage->pt; + struct cso_context *cso = st->cso_context; + const struct util_format_description *desc; + struct st_pbo_addresses addr; + struct pipe_framebuffer_state fb; + enum pipe_texture_target pipe_target; + GLenum gl_target = texImage->TexObject->Target; + GLuint dims; + bool success = false; + + if (texture->nr_samples > 1) + return false; + + /* GetTexImage only returns a single face for cubemaps. */ + if (gl_target == GL_TEXTURE_CUBE_MAP) { + gl_target = GL_TEXTURE_2D; + } + if (gl_target == GL_TEXTURE_CUBE_MAP_ARRAY) { + gl_target = GL_TEXTURE_2D_ARRAY; + } + pipe_target = gl_target_to_pipe(gl_target); + dims = _mesa_get_texture_dimensions(gl_target); + + /* From now on, we need the gallium representation of dimensions. */ + if (gl_target == GL_TEXTURE_1D_ARRAY) { + depth = height; + height = 1; + zoffset = yoffset; + yoffset = 0; + } + + if (depth != 1 && !st->pbo.layers) + return false; + + if (!screen->is_format_supported(screen, dst_format, PIPE_BUFFER, 0, 0, + PIPE_BIND_SHADER_IMAGE)) + return false; + + desc = util_format_description(dst_format); + + /* Compute PBO addresses */ + addr.bytes_per_pixel = desc->block.bits / 8; + addr.xoffset = xoffset; + addr.yoffset = yoffset; + addr.width = width; + addr.height = height; + addr.depth = depth; + if (!st_pbo_addresses_pixelstore(st, gl_target, dims == 3, pack, pixels, &addr)) + return false; + + cso_save_state(cso, (CSO_BIT_FRAGMENT_SAMPLER_VIEWS | + CSO_BIT_FRAGMENT_SAMPLERS | + CSO_BIT_FRAGMENT_IMAGE0 | + CSO_BIT_BLEND | + CSO_BIT_VERTEX_ELEMENTS | + CSO_BIT_AUX_VERTEX_BUFFER_SLOT | + CSO_BIT_FRAMEBUFFER | + CSO_BIT_VIEWPORT | + CSO_BIT_RASTERIZER | + CSO_BIT_DEPTH_STENCIL_ALPHA | + CSO_BIT_STREAM_OUTPUTS | + CSO_BIT_PAUSE_QUERIES | + CSO_BIT_SAMPLE_MASK | + CSO_BIT_MIN_SAMPLES | + CSO_BIT_RENDER_CONDITION | + CSO_BITS_ALL_SHADERS)); + cso_save_constant_buffer_slot0(cso, PIPE_SHADER_FRAGMENT); + + cso_set_sample_mask(cso, ~0); + cso_set_min_samples(cso, 1); + cso_set_render_condition(cso, NULL, FALSE, 0); + + /* Set up the sampler_view */ + { + struct pipe_sampler_view templ; + struct pipe_sampler_view *sampler_view; + struct pipe_sampler_state sampler = {0}; + const struct pipe_sampler_state *samplers[1] = {&sampler}; + unsigned level = texImage->TexObject->MinLevel + texImage->Level; + unsigned max_layer = util_max_layer(texture, level); + + u_sampler_view_default_template(&templ, texture, src_format); + + templ.target = pipe_target; + templ.u.tex.first_level = level; + templ.u.tex.last_level = templ.u.tex.first_level; + + zoffset += texImage->Face + texImage->TexObject->MinLayer; + templ.u.tex.first_layer = MIN2(zoffset, max_layer); + templ.u.tex.last_layer = MIN2(zoffset + depth - 1, max_layer); + + sampler_view = pipe->create_sampler_view(pipe, texture, &templ); + if (sampler_view == NULL) + goto fail; + + cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, 1, &sampler_view); + + pipe_sampler_view_reference(&sampler_view, NULL); + + cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 1, samplers); + } + + /* Set up destination image */ + { + struct pipe_image_view image; + + memset(&image, 0, sizeof(image)); + image.resource = addr.buffer; + image.format = dst_format; + image.access = PIPE_IMAGE_ACCESS_WRITE; + image.u.buf.offset = addr.first_element * addr.bytes_per_pixel; + image.u.buf.size = (addr.last_element - addr.first_element + 1) * + addr.bytes_per_pixel; + + cso_set_shader_images(cso, PIPE_SHADER_FRAGMENT, 0, 1, &image); + } + + /* Set up no-attachment framebuffer */ + memset(&fb, 0, sizeof(fb)); + fb.width = width; + fb.height = height; + fb.layers = depth; + fb.samples = 1; + cso_set_framebuffer(cso, &fb); + + /* Any blend state would do. Set this just to prevent drivers having + * blend == NULL. + */ + cso_set_blend(cso, &st->pbo.upload_blend); + + cso_set_viewport_dims(cso, fb.width, fb.height, FALSE); + + { + struct pipe_depth_stencil_alpha_state dsa; + memset(&dsa, 0, sizeof(dsa)); + cso_set_depth_stencil_alpha(cso, &dsa); + } + + /* Set up the fragment shader */ + { + void *fs = st_pbo_get_download_fs(st, pipe_target, src_format, dst_format); + if (!fs) + goto fail; + + cso_set_fragment_shader_handle(cso, fs); + } + + success = st_pbo_draw(st, &addr, fb.width, fb.height); + + /* Buffer written via shader images needs explicit synchronization. */ + pipe->memory_barrier(pipe, PIPE_BARRIER_ALL); + +fail: + cso_restore_state(cso); + cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_FRAGMENT); + + return success; +} + static void st_TexSubImage(struct gl_context *ctx, GLuint dims, @@ -1933,13 +2103,6 @@ st_GetTexSubImage(struct gl_context * ctx, goto fallback; } - /* See if the texture format already matches the format and type, - * in which case the memcpy-based fast path will be used. */ - if (_mesa_format_matches_format_and_type(texImage->TexFormat, format, - type, ctx->Pack.SwapBytes, NULL)) { - goto fallback; - } - /* Convert the source format to what is expected by GetTexImage * and see if it's supported. * @@ -2067,6 +2230,22 @@ st_GetTexSubImage(struct gl_context * ctx, } } + if (st->pbo.download_enabled && _mesa_is_bufferobj(ctx->Pack.BufferObj)) { + if (try_pbo_download(st, texImage, + src_format, dst_format, + xoffset, yoffset, zoffset, + width, height, depth, + &ctx->Pack, pixels)) + return; + } + + /* See if the texture format already matches the format and type, + * in which case the memcpy-based fast path will be used. */ + if (_mesa_format_matches_format_and_type(texImage->TexFormat, format, + type, ctx->Pack.SwapBytes, NULL)) { + goto fallback; + } + /* create the destination texture of size (width X height X depth) */ memset(&dst_templ, 0, sizeof(dst_templ)); dst_templ.target = pipe_target; -- 2.17.1