[Mesa-dev] [PATCH 5/9] st/mesa: fix SINT <-> UINT conversion during PBO upload / download
Nicolai Hähnle
nhaehnle at gmail.com
Wed Nov 9 15:01:53 UTC 2016
From: Nicolai Hähnle <nicolai.haehnle at amd.com>
This fixes use cases like glReadPixels from an RGBA8I framebuffer into
a PBO with type GL_INT by clamping values appropriately when they fall
outside the range of the destination format.
Fixes parts of GL45-CTS.gtf32.GL3Tests.packed_pixels.packed_pixels_pbo.
---
src/mesa/state_tracker/st_cb_readpixels.c | 2 +-
src/mesa/state_tracker/st_cb_texture.c | 2 +-
src/mesa/state_tracker/st_context.h | 4 +-
src/mesa/state_tracker/st_pbo.c | 95 +++++++++++++++++++++++++------
src/mesa/state_tracker/st_pbo.h | 8 ++-
5 files changed, 89 insertions(+), 22 deletions(-)
diff --git a/src/mesa/state_tracker/st_cb_readpixels.c b/src/mesa/state_tracker/st_cb_readpixels.c
index cab6abe..ea91bb9 100644
--- a/src/mesa/state_tracker/st_cb_readpixels.c
+++ b/src/mesa/state_tracker/st_cb_readpixels.c
@@ -212,21 +212,21 @@ try_pbo_readpixels(struct st_context *st, struct st_renderbuffer *strb,
st_pbo_addresses_invert_y(&addr, fb.height);
{
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, view_target);
+ void *fs = st_pbo_get_download_fs(st, view_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);
diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c
index ef59041..45f0448 100644
--- a/src/mesa/state_tracker/st_cb_texture.c
+++ b/src/mesa/state_tracker/st_cb_texture.c
@@ -1133,21 +1133,21 @@ try_pbo_upload_common(struct gl_context *ctx,
struct pipe_surface *surface,
const struct st_pbo_addresses *addr,
enum pipe_format src_format)
{
struct st_context *st = st_context(ctx);
struct cso_context *cso = st->cso_context;
struct pipe_context *pipe = st->pipe;
bool success = false;
void *fs;
- fs = st_pbo_get_upload_fs(st);
+ fs = st_pbo_get_upload_fs(st, src_format, surface->format);
if (!fs)
return false;
cso_save_state(cso, (CSO_BIT_FRAGMENT_SAMPLER_VIEWS |
CSO_BIT_FRAGMENT_SAMPLERS |
CSO_BIT_VERTEX_ELEMENTS |
CSO_BIT_AUX_VERTEX_BUFFER_SLOT |
CSO_BIT_FRAMEBUFFER |
CSO_BIT_VIEWPORT |
CSO_BIT_BLEND |
diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h
index 83d77fd..b3478ea 100644
--- a/src/mesa/state_tracker/st_context.h
+++ b/src/mesa/state_tracker/st_context.h
@@ -217,22 +217,22 @@ struct st_context
void *vs_layered;
void *gs_layered;
} clear;
/* For gl(Compressed)Tex(Sub)Image */
struct {
struct pipe_rasterizer_state raster;
struct pipe_blend_state upload_blend;
void *vs;
void *gs;
- void *upload_fs;
- void *download_fs[PIPE_MAX_TEXTURE_TYPES];
+ void *upload_fs[3];
+ void *download_fs[3][PIPE_MAX_TEXTURE_TYPES];
bool upload_enabled;
bool download_enabled;
bool rgba_only;
bool layers;
bool use_gs;
} pbo;
/** for drawing with st_util_vertex */
struct pipe_vertex_element util_velems[3];
diff --git a/src/mesa/state_tracker/st_pbo.c b/src/mesa/state_tracker/st_pbo.c
index 1e21554..a9ea6ea 100644
--- a/src/mesa/state_tracker/st_pbo.c
+++ b/src/mesa/state_tracker/st_pbo.c
@@ -30,23 +30,33 @@
#include "state_tracker/st_context.h"
#include "state_tracker/st_pbo.h"
#include "state_tracker/st_cb_bufferobjects.h"
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "pipe/p_screen.h"
#include "cso_cache/cso_context.h"
#include "tgsi/tgsi_ureg.h"
+#include "util/u_format.h"
#include "util/u_inlines.h"
#include "util/u_upload_mgr.h"
+/* Conversion to apply in the fragment shader. */
+enum st_pbo_conversion {
+ ST_PBO_CONVERT_NONE = 0,
+ ST_PBO_CONVERT_UINT_TO_SINT,
+ ST_PBO_CONVERT_SINT_TO_UINT,
+
+ ST_NUM_PBO_CONVERSIONS
+};
+
/* Final setup of buffer addressing information.
*
* buf_offset is in pixels.
*
* Returns false if something (e.g. alignment) prevents PBO upload/download.
*/
bool
st_pbo_addresses_setup(struct st_context *st,
struct pipe_resource *buf, intptr_t buf_offset,
struct st_pbo_addresses *addr)
@@ -369,22 +379,40 @@ st_pbo_create_gs(struct st_context *st)
ureg_scalar(in_pos_vertex, TGSI_SWIZZLE_Z));
ureg_EMIT(ureg, ureg_scalar(imm, TGSI_SWIZZLE_X));
}
ureg_END(ureg);
return ureg_create_shader_and_destroy(ureg, st->pipe);
}
+static void
+build_conversion(struct ureg_program *ureg, const struct ureg_dst *temp,
+ enum st_pbo_conversion conversion)
+{
+ switch (conversion) {
+ case ST_PBO_CONVERT_SINT_TO_UINT:
+ ureg_IMAX(ureg, *temp, ureg_src(*temp), ureg_imm1i(ureg, 0));
+ break;
+ case ST_PBO_CONVERT_UINT_TO_SINT:
+ ureg_UMIN(ureg, *temp, ureg_src(*temp), ureg_imm1u(ureg, (1u << 31) - 1));
+ break;
+ default:
+ /* no-op */
+ break;
+ }
+}
+
static void *
-create_fs(struct st_context *st, bool download, enum pipe_texture_target target)
+create_fs(struct st_context *st, bool download, enum pipe_texture_target target,
+ enum st_pbo_conversion conversion)
{
struct pipe_context *pipe = st->pipe;
struct pipe_screen *screen = pipe->screen;
struct ureg_program *ureg;
bool have_layer;
struct ureg_dst out;
struct ureg_src sampler;
struct ureg_src pos;
struct ureg_src layer;
struct ureg_src const0;
@@ -488,57 +516,88 @@ create_fs(struct st_context *st, bool download, enum pipe_texture_target target)
ureg_UADD(ureg, temp1_layer,
ureg_scalar(ureg_src(temp1), TGSI_SWIZZLE_Z),
ureg_scalar(const1, TGSI_SWIZZLE_X));
}
}
/* temp1 = txf(sampler, temp1) */
ureg_TXF(ureg, temp1, util_pipe_tex_to_tgsi_tex(target, 1),
ureg_src(temp1), sampler);
+ build_conversion(ureg, &temp1, conversion);
+
/* store(out, temp0, temp1) */
op[0] = ureg_src(temp0);
op[1] = ureg_src(temp1);
ureg_memory_insn(ureg, TGSI_OPCODE_STORE, &out, 1, op, 2, 0,
TGSI_TEXTURE_BUFFER, PIPE_FORMAT_NONE);
ureg_release_temporary(ureg, temp1);
} else {
/* out = txf(sampler, temp0.x) */
- ureg_TXF(ureg, out, TGSI_TEXTURE_BUFFER, ureg_src(temp0), sampler);
+ ureg_TXF(ureg, temp0, TGSI_TEXTURE_BUFFER, ureg_src(temp0), sampler);
+
+ build_conversion(ureg, &temp0, conversion);
+
+ ureg_MOV(ureg, out, ureg_src(temp0));
}
ureg_release_temporary(ureg, temp0);
ureg_END(ureg);
return ureg_create_shader_and_destroy(ureg, pipe);
}
+static enum st_pbo_conversion
+get_pbo_conversion(enum pipe_format src_format, enum pipe_format dst_format)
+{
+ if (util_format_is_pure_uint(src_format)) {
+ if (util_format_is_pure_sint(dst_format))
+ return ST_PBO_CONVERT_UINT_TO_SINT;
+ } else if (util_format_is_pure_sint(src_format)) {
+ if (util_format_is_pure_uint(dst_format))
+ return ST_PBO_CONVERT_SINT_TO_UINT;
+ }
+
+ return ST_PBO_CONVERT_NONE;
+}
+
void *
-st_pbo_get_upload_fs(struct st_context *st)
+st_pbo_get_upload_fs(struct st_context *st,
+ enum pipe_format src_format,
+ enum pipe_format dst_format)
{
- if (!st->pbo.upload_fs)
- st->pbo.upload_fs = create_fs(st, false, 0);
+ STATIC_ASSERT(ARRAY_SIZE(st->pbo.upload_fs) == ST_NUM_PBO_CONVERSIONS);
+
+ enum st_pbo_conversion conversion = get_pbo_conversion(src_format, dst_format);
- return st->pbo.upload_fs;
+ if (!st->pbo.upload_fs[conversion])
+ st->pbo.upload_fs[conversion] = create_fs(st, false, 0, conversion);
+
+ return st->pbo.upload_fs[conversion];
}
void *
-st_pbo_get_download_fs(struct st_context *st, enum pipe_texture_target target)
+st_pbo_get_download_fs(struct st_context *st, enum pipe_texture_target target,
+ enum pipe_format src_format,
+ enum pipe_format dst_format)
{
+ STATIC_ASSERT(ARRAY_SIZE(st->pbo.download_fs) == ST_NUM_PBO_CONVERSIONS);
assert(target < PIPE_MAX_TEXTURE_TYPES);
- if (!st->pbo.download_fs[target])
- st->pbo.download_fs[target] = create_fs(st, true, target);
+ enum st_pbo_conversion conversion = get_pbo_conversion(src_format, dst_format);
+
+ if (!st->pbo.download_fs[conversion][target])
+ st->pbo.download_fs[conversion][target] = create_fs(st, true, target, conversion);
- return st->pbo.download_fs[target];
+ return st->pbo.download_fs[conversion][target];
}
void
st_init_pbo_helpers(struct st_context *st)
{
struct pipe_context *pipe = st->pipe;
struct pipe_screen *screen = pipe->screen;
st->pbo.upload_enabled =
screen->get_param(screen, PIPE_CAP_TEXTURE_BUFFER_OBJECTS) &&
@@ -573,29 +632,33 @@ st_init_pbo_helpers(struct st_context *st)
/* Rasterizer state */
memset(&st->pbo.raster, 0, sizeof(struct pipe_rasterizer_state));
st->pbo.raster.half_pixel_center = 1;
}
void
st_destroy_pbo_helpers(struct st_context *st)
{
unsigned i;
- if (st->pbo.upload_fs) {
- cso_delete_fragment_shader(st->cso_context, st->pbo.upload_fs);
- st->pbo.upload_fs = NULL;
+ for (i = 0; i < ARRAY_SIZE(st->pbo.upload_fs); ++i) {
+ if (st->pbo.upload_fs[i]) {
+ cso_delete_fragment_shader(st->cso_context, st->pbo.upload_fs[i]);
+ st->pbo.upload_fs[i] = NULL;
+ }
}
for (i = 0; i < ARRAY_SIZE(st->pbo.download_fs); ++i) {
- if (st->pbo.download_fs[i]) {
- cso_delete_fragment_shader(st->cso_context, st->pbo.download_fs[i]);
- st->pbo.download_fs[i] = NULL;
+ for (unsigned j = 0; j < ARRAY_SIZE(st->pbo.download_fs[0]); ++j) {
+ if (st->pbo.download_fs[i][j]) {
+ cso_delete_fragment_shader(st->cso_context, st->pbo.download_fs[i][j]);
+ st->pbo.download_fs[i][j] = NULL;
+ }
}
}
if (st->pbo.gs) {
cso_delete_geometry_shader(st->cso_context, st->pbo.gs);
st->pbo.gs = NULL;
}
if (st->pbo.vs) {
cso_delete_vertex_shader(st->cso_context, st->pbo.vs);
diff --git a/src/mesa/state_tracker/st_pbo.h b/src/mesa/state_tracker/st_pbo.h
index 6513093..54ae776 100644
--- a/src/mesa/state_tracker/st_pbo.h
+++ b/src/mesa/state_tracker/st_pbo.h
@@ -78,22 +78,26 @@ bool
st_pbo_draw(struct st_context *st, const struct st_pbo_addresses *addr,
unsigned surface_width, unsigned surface_height);
void *
st_pbo_create_vs(struct st_context *st);
void *
st_pbo_create_gs(struct st_context *st);
void *
-st_pbo_get_upload_fs(struct st_context *st);
+st_pbo_get_upload_fs(struct st_context *st,
+ enum pipe_format src_format,
+ enum pipe_format dst_format);
void *
-st_pbo_get_download_fs(struct st_context *st, enum pipe_texture_target target);
+st_pbo_get_download_fs(struct st_context *st, enum pipe_texture_target target,
+ enum pipe_format src_format,
+ enum pipe_format dst_format);
extern void
st_init_pbo_helpers(struct st_context *st);
extern void
st_destroy_pbo_helpers(struct st_context *st);
#endif /* ST_PBO_H */
--
2.7.4
More information about the mesa-dev
mailing list