diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index 1943f2b..4e057a7 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -2927,6 +2927,25 @@ static void vrend_destroy_shader_object(void *obj_ptr) 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, unsigned type, 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); if (util_format_is_pure_integer(ctx->sub->surf[i]->format)) 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) { 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->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->coord_replace = ctx->sub->rs_state.point_quad_rasterization ? ctx->sub->rs_state.sprite_coord_enable : 0; 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) { ctx->sub->hw_blend_state.logicop_enable = state->logicop_enable; 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); - } } else if (state->logicop_enable) { glEnable(GL_COLOR_LOGIC_OP); glLogicOp(translate_logicop(state->logicop_func)); diff --git a/src/vrend_shader.c b/src/vrend_shader.c index 23fda0c..8e2d174 100644 --- a/src/vrend_shader.c +++ b/src/vrend_shader.c @@ -810,6 +810,22 @@ iter_inputs(struct tgsi_iterate_context *iter, 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 iter_declaration(struct tgsi_iterate_context *iter, struct tgsi_full_declaration *decl ) @@ -1195,6 +1211,10 @@ iter_declaration(struct tgsi_iterate_context *iter, } else name_prefix = "ex"; break; + } else if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT && + ctx->key->fs_logicop_enabled) { + name_prefix = "fsout_tmp"; + break; } /* fallthrough */ case TGSI_SEMANTIC_BCOLOR: @@ -1877,6 +1897,81 @@ static void handle_vertex_proc_exit(struct dump_ctx *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) { 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) emit_alpha_test(ctx); + if (ctx->key->fs_logicop_enabled) + emit_fragment_logicop(ctx); + if (ctx->write_all_cbufs) emit_cbuf_writes(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"); } + 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) 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) { for (i = 0; i < (uint32_t)ctx->cfg->max_draw_buffers; i++) { - if (ctx->cfg->use_gles) - emit_hdrf(ctx, "layout (location=%d) out vec4 fsout_c%d;\n", i, i); - else + if (ctx->cfg->use_gles) { + if (ctx->key->fs_logicop_enabled) + 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); } } else { diff --git a/src/vrend_shader.h b/src/vrend_shader.h index 96f0c49..01b5646 100644 --- a/src/vrend_shader.h +++ b/src/vrend_shader.h @@ -107,6 +107,11 @@ struct vrend_shader_key { bool flatshade; bool prev_stage_pervertex_out; 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; struct vrend_layout_info prev_stage_generic_and_patch_outputs_layout[64];