vrend,shader: track logicop state and emulate it in GLES

This patch uses GL_EXT_framebuffer_fetch_non_coherent (preferred)
or GL_EXT_framebuffer_fetch to emulate the logiops in the fragement
shader. If neither of these extension are available then only
GL_COPY, GL_COPY_INVERTED, GL_CLEAR, and GL_SET are emulated.

Fixes piglit gl-1.0-logicop on GLES hosts.

v2: Use non_coherent access when possible

Signed-off-by: Gert Wollny <gert.wollny@collabora.com>
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
macos/master
Gert Wollny 6 years ago committed by Gert Wollny
parent c9c9c31b3b
commit 811d8ef201
  1. 32
      src/vrend_renderer.c
  2. 120
      src/vrend_shader.c
  3. 5
      src/vrend_shader.h

@ -2927,6 +2927,25 @@ static void vrend_destroy_shader_object(void *obj_ptr)
vrend_shader_state_reference(&state, NULL); vrend_shader_state_reference(&state, NULL);
} }
static inline bool can_emulate_logicop(enum pipe_logicop op)
{
if (has_feature(feat_framebuffer_fetch_non_coherent) ||
has_feature(feat_framebuffer_fetch))
return true;
/* These ops don't need to read back from the framebuffer */
switch (op) {
case PIPE_LOGICOP_CLEAR:
case PIPE_LOGICOP_COPY:
case PIPE_LOGICOP_SET:
case PIPE_LOGICOP_COPY_INVERTED:
return true;
default:
return false;
}
}
static inline void vrend_fill_shader_key(struct vrend_context *ctx, static inline void vrend_fill_shader_key(struct vrend_context *ctx,
unsigned type, unsigned type,
struct vrend_shader_key *key) struct vrend_shader_key *key)
@ -2942,6 +2961,7 @@ static inline void vrend_fill_shader_key(struct vrend_context *ctx,
key->cbufs_are_a8_bitmask |= (1 << i); key->cbufs_are_a8_bitmask |= (1 << i);
if (util_format_is_pure_integer(ctx->sub->surf[i]->format)) if (util_format_is_pure_integer(ctx->sub->surf[i]->format))
add_alpha_test = false; add_alpha_test = false;
key->surface_component_bits[i] = util_format_get_component_bits(ctx->sub->surf[i]->format, UTIL_FORMAT_COLORSPACE_RGB, 0);
} }
if (add_alpha_test) { if (add_alpha_test) {
key->add_alpha_test = ctx->sub->dsa_state.alpha.enabled; key->add_alpha_test = ctx->sub->dsa_state.alpha.enabled;
@ -2958,6 +2978,13 @@ static inline void vrend_fill_shader_key(struct vrend_context *ctx,
key->add_alpha_test = 0; key->add_alpha_test = 0;
key->pstipple_tex = 0; key->pstipple_tex = 0;
} }
if (type == PIPE_SHADER_FRAGMENT && vrend_state.use_gles && can_emulate_logicop(ctx->sub->blend_state.logicop_func)) {
key->fs_logicop_enabled = ctx->sub->blend_state.logicop_enable;
key->fs_logicop_func = ctx->sub->blend_state.logicop_func;
key->fs_logicop_emulate_coherent = !has_feature(feat_framebuffer_fetch_non_coherent);
}
key->invert_fs_origin = !ctx->sub->inverted_fbo_content; key->invert_fs_origin = !ctx->sub->inverted_fbo_content;
key->coord_replace = ctx->sub->rs_state.point_quad_rasterization ? ctx->sub->rs_state.sprite_coord_enable : 0; key->coord_replace = ctx->sub->rs_state.point_quad_rasterization ? ctx->sub->rs_state.sprite_coord_enable : 0;
key->winsys_adjust_y_emitted = false; key->winsys_adjust_y_emitted = false;
@ -4572,9 +4599,10 @@ static void vrend_hw_emit_blend(struct vrend_context *ctx, struct pipe_blend_sta
if (state->logicop_enable != ctx->sub->hw_blend_state.logicop_enable) { if (state->logicop_enable != ctx->sub->hw_blend_state.logicop_enable) {
ctx->sub->hw_blend_state.logicop_enable = state->logicop_enable; ctx->sub->hw_blend_state.logicop_enable = state->logicop_enable;
if (vrend_state.use_gles) { if (vrend_state.use_gles) {
if (state->logicop_enable) { if (can_emulate_logicop(state->logicop_func))
ctx->sub->shader_dirty = true;
else
report_gles_warn(ctx, GLES_WARN_LOGIC_OP); report_gles_warn(ctx, GLES_WARN_LOGIC_OP);
}
} else if (state->logicop_enable) { } else if (state->logicop_enable) {
glEnable(GL_COLOR_LOGIC_OP); glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(translate_logicop(state->logicop_func)); glLogicOp(translate_logicop(state->logicop_func));

@ -810,6 +810,22 @@ iter_inputs(struct tgsi_iterate_context *iter,
return true; return true;
} }
static bool logiop_require_inout(struct vrend_shader_key *key)
{
if (!key->fs_logicop_enabled)
return false;
switch (key->fs_logicop_func) {
case PIPE_LOGICOP_CLEAR:
case PIPE_LOGICOP_SET:
case PIPE_LOGICOP_COPY:
case PIPE_LOGICOP_COPY_INVERTED:
return false;
default:
return true;
}
}
static boolean static boolean
iter_declaration(struct tgsi_iterate_context *iter, iter_declaration(struct tgsi_iterate_context *iter,
struct tgsi_full_declaration *decl ) struct tgsi_full_declaration *decl )
@ -1195,6 +1211,10 @@ iter_declaration(struct tgsi_iterate_context *iter,
} else } else
name_prefix = "ex"; name_prefix = "ex";
break; break;
} else if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
ctx->key->fs_logicop_enabled) {
name_prefix = "fsout_tmp";
break;
} }
/* fallthrough */ /* fallthrough */
case TGSI_SEMANTIC_BCOLOR: case TGSI_SEMANTIC_BCOLOR:
@ -1877,6 +1897,81 @@ static void handle_vertex_proc_exit(struct dump_ctx *ctx)
emit_prescale(ctx); emit_prescale(ctx);
} }
static void emit_fragment_logicop(struct dump_ctx *ctx)
{
char src[PIPE_MAX_COLOR_BUFS][64];
char src_fb[PIPE_MAX_COLOR_BUFS][64];
double scale[PIPE_MAX_COLOR_BUFS];
int mask[PIPE_MAX_COLOR_BUFS];
char full_op[PIPE_MAX_COLOR_BUFS][128];
for (unsigned i = 0; i < ctx->num_outputs; i++) {
mask[i] = (1 << ctx->key->surface_component_bits[i]) - 1;
scale[i] = mask[i];
switch (ctx->key->fs_logicop_func) {
case PIPE_LOGICOP_INVERT:
snprintf(src_fb[i], 64, "ivec4(%f * fsout_c%d + 0.5)", scale[i], i);
break;
case PIPE_LOGICOP_NOR:
case PIPE_LOGICOP_AND_INVERTED:
case PIPE_LOGICOP_AND_REVERSE:
case PIPE_LOGICOP_XOR:
case PIPE_LOGICOP_NAND:
case PIPE_LOGICOP_AND:
case PIPE_LOGICOP_EQUIV:
case PIPE_LOGICOP_OR_INVERTED:
case PIPE_LOGICOP_OR_REVERSE:
case PIPE_LOGICOP_OR:
snprintf(src_fb[i], 64, "ivec4(%f * fsout_c%d + 0.5)", scale[i], i);
/* fallthrough */
case PIPE_LOGICOP_COPY_INVERTED:
snprintf(src[i], 64, "ivec4(%f * fsout_tmp_c%d + 0.5)", scale[i], i);
break;
case PIPE_LOGICOP_COPY:
case PIPE_LOGICOP_NOOP:
case PIPE_LOGICOP_CLEAR:
case PIPE_LOGICOP_SET:
break;
}
}
for (unsigned i = 0; i < ctx->num_outputs; i++) {
switch (ctx->key->fs_logicop_func) {
case PIPE_LOGICOP_CLEAR: snprintf(full_op[i], 128, "%s", "vec4(0)"); break;
case PIPE_LOGICOP_NOOP: full_op[i][0]= 0; break;
case PIPE_LOGICOP_SET: snprintf(full_op[i], 128, "%s", "vec4(1)"); break;
case PIPE_LOGICOP_COPY: snprintf(full_op[i], 128, "fsout_tmp_c%d", i); break;
case PIPE_LOGICOP_COPY_INVERTED: snprintf(full_op[i], 128, "~%s", src[i]); break;
case PIPE_LOGICOP_INVERT: snprintf(full_op[i], 128, "~%s", src_fb[i]); break;
case PIPE_LOGICOP_AND: snprintf(full_op[i], 128, "%s & %s", src[i], src_fb[i]); break;
case PIPE_LOGICOP_NAND: snprintf(full_op[i], 128, "~( %s & %s )", src[i], src_fb[i]); break;
case PIPE_LOGICOP_NOR: snprintf(full_op[i], 128, "~( %s | %s )", src[i], src_fb[i]); break;
case PIPE_LOGICOP_AND_INVERTED: snprintf(full_op[i], 128, "~%s & %s", src[i], src_fb[i]); break;
case PIPE_LOGICOP_AND_REVERSE: snprintf(full_op[i], 128, "%s & ~%s", src[i], src_fb[i]); break;
case PIPE_LOGICOP_XOR: snprintf(full_op[i], 128, "%s ^%s", src[i], src_fb[i]); break;
case PIPE_LOGICOP_EQUIV: snprintf(full_op[i], 128, "~( %s ^ %s )", src[i], src_fb[i]); break;
case PIPE_LOGICOP_OR_INVERTED: snprintf(full_op[i], 128, "~%s | %s", src[i], src_fb[i]); break;
case PIPE_LOGICOP_OR_REVERSE: snprintf(full_op[i], 128, "%s | ~%s", src[i], src_fb[i]); break;
case PIPE_LOGICOP_OR: snprintf(full_op[i], 128, "%s | %s", src[i], src_fb[i]); break;
}
}
for (unsigned i = 0; i < ctx->num_outputs; i++) {
switch (ctx->key->fs_logicop_func) {
case PIPE_LOGICOP_NOOP:
break;
case PIPE_LOGICOP_COPY:
case PIPE_LOGICOP_CLEAR:
case PIPE_LOGICOP_SET:
emit_buff(ctx, "fsout_c%d = %s;\n", i, full_op[i]);
break;
default:
emit_buff(ctx, "fsout_c%d = vec4((%s) & %d) / %f;\n", i, full_op[i], mask[i], scale[i]);
}
}
}
static void handle_fragment_proc_exit(struct dump_ctx *ctx) static void handle_fragment_proc_exit(struct dump_ctx *ctx)
{ {
if (ctx->key->pstipple_tex) if (ctx->key->pstipple_tex)
@ -1888,8 +1983,12 @@ static void handle_fragment_proc_exit(struct dump_ctx *ctx)
if (ctx->key->add_alpha_test) if (ctx->key->add_alpha_test)
emit_alpha_test(ctx); emit_alpha_test(ctx);
if (ctx->key->fs_logicop_enabled)
emit_fragment_logicop(ctx);
if (ctx->write_all_cbufs) if (ctx->write_all_cbufs)
emit_cbuf_writes(ctx); emit_cbuf_writes(ctx);
} }
static void set_texture_reqs(struct dump_ctx *ctx, static void set_texture_reqs(struct dump_ctx *ctx,
@ -5015,6 +5114,14 @@ static void emit_header(struct dump_ctx *ctx)
emit_ext(ctx, "OES_shader_image_atomic", "require"); emit_ext(ctx, "OES_shader_image_atomic", "require");
} }
if (logiop_require_inout(ctx->key)) {
if (ctx->key->fs_logicop_emulate_coherent)
emit_ext(ctx, "EXT_shader_framebuffer_fetch", "require");
else
emit_ext(ctx, "EXT_shader_framebuffer_fetch_non_coherent", "require");
}
if (ctx->shader_req_bits & SHADER_REQ_LODQ) if (ctx->shader_req_bits & SHADER_REQ_LODQ)
emit_ext(ctx, "EXT_texture_query_lod", "require"); emit_ext(ctx, "EXT_texture_query_lod", "require");
@ -5832,9 +5939,16 @@ static void emit_ios_fs(struct dump_ctx *ctx)
if (ctx->write_all_cbufs) { if (ctx->write_all_cbufs) {
for (i = 0; i < (uint32_t)ctx->cfg->max_draw_buffers; i++) { for (i = 0; i < (uint32_t)ctx->cfg->max_draw_buffers; i++) {
if (ctx->cfg->use_gles) if (ctx->cfg->use_gles) {
emit_hdrf(ctx, "layout (location=%d) out vec4 fsout_c%d;\n", i, i); if (ctx->key->fs_logicop_enabled)
else emit_hdrf(ctx, "vec4 fsout_tmp_c%d;\n", i);
if (logiop_require_inout(ctx->key)) {
const char *noncoherent = ctx->key->fs_logicop_emulate_coherent ? "" : ", noncoherent";
emit_hdrf(ctx, "layout (location=%d%s) inout highp vec4 fsout_c%d;\n", i, noncoherent, i);
} else
emit_hdrf(ctx, "layout (location=%d) out vec4 fsout_c%d;\n", i, i);
} else
emit_hdrf(ctx, "out vec4 fsout_c%d;\n", i); emit_hdrf(ctx, "out vec4 fsout_c%d;\n", i);
} }
} else { } else {

@ -107,6 +107,11 @@ struct vrend_shader_key {
bool flatshade; bool flatshade;
bool prev_stage_pervertex_out; bool prev_stage_pervertex_out;
bool guest_sent_io_arrays; bool guest_sent_io_arrays;
bool fs_logicop_enabled;
bool fs_logicop_emulate_coherent;
enum pipe_logicop fs_logicop_func;
uint8_t surface_component_bits[PIPE_MAX_COLOR_BUFS];
uint32_t num_prev_generic_and_patch_outputs; uint32_t num_prev_generic_and_patch_outputs;
struct vrend_layout_info prev_stage_generic_and_patch_outputs_layout[64]; struct vrend_layout_info prev_stage_generic_and_patch_outputs_layout[64];

Loading…
Cancel
Save