diff options
Diffstat (limited to 'src/gallium')
115 files changed, 3527 insertions, 1760 deletions
diff --git a/src/gallium/auxiliary/nir/tgsi_to_nir.c b/src/gallium/auxiliary/nir/tgsi_to_nir.c index 93dfb803389..278d5e9bf5b 100644 --- a/src/gallium/auxiliary/nir/tgsi_to_nir.c +++ b/src/gallium/auxiliary/nir/tgsi_to_nir.c @@ -24,6 +24,7 @@ #include "util/ralloc.h" #include "glsl/nir/nir.h" +#include "glsl/nir/nir_control_flow.h" #include "glsl/nir/nir_builder.h" #include "glsl/list.h" #include "glsl/shader_enums.h" @@ -307,7 +308,7 @@ ttn_emit_immediate(struct ttn_compile *c) for (i = 0; i < 4; i++) load_const->value.u[i] = tgsi_imm->u[i].Uint; - nir_instr_insert_after_cf_list(b->cf_node_list, &load_const->instr); + nir_builder_instr_insert(b, &load_const->instr); } static nir_src @@ -363,7 +364,7 @@ ttn_src_for_file_and_index(struct ttn_compile *c, unsigned file, unsigned index, load->variables[0] = ttn_array_deref(c, load, var, offset, indirect); nir_ssa_dest_init(&load->instr, &load->dest, 4, NULL); - nir_instr_insert_after_cf_list(b->cf_node_list, &load->instr); + nir_builder_instr_insert(b, &load->instr); src = nir_src_for_ssa(&load->dest.ssa); @@ -414,7 +415,7 @@ ttn_src_for_file_and_index(struct ttn_compile *c, unsigned file, unsigned index, load->num_components = ncomp; nir_ssa_dest_init(&load->instr, &load->dest, ncomp, NULL); - nir_instr_insert_after_cf_list(b->cf_node_list, &load->instr); + nir_builder_instr_insert(b, &load->instr); src = nir_src_for_ssa(&load->dest.ssa); break; @@ -476,7 +477,7 @@ ttn_src_for_file_and_index(struct ttn_compile *c, unsigned file, unsigned index, srcn++; } nir_ssa_dest_init(&load->instr, &load->dest, 4, NULL); - nir_instr_insert_after_cf_list(b->cf_node_list, &load->instr); + nir_builder_instr_insert(b, &load->instr); src = nir_src_for_ssa(&load->dest.ssa); break; @@ -552,7 +553,7 @@ ttn_get_dest(struct ttn_compile *c, struct tgsi_full_dst_register *tgsi_fdst) load->dest = nir_dest_for_reg(reg); - nir_instr_insert_after_cf_list(b->cf_node_list, &load->instr); + nir_builder_instr_insert(b, &load->instr); } else { assert(!tgsi_dst->Indirect); dest.dest.reg.reg = c->temp_regs[index].reg; @@ -667,7 +668,7 @@ ttn_alu(nir_builder *b, nir_op op, nir_alu_dest dest, nir_ssa_def **src) instr->src[i].src = nir_src_for_ssa(src[i]); instr->dest = dest; - nir_instr_insert_after_cf_list(b->cf_node_list, &instr->instr); + nir_builder_instr_insert(b, &instr->instr); } static void @@ -683,7 +684,7 @@ ttn_move_dest_masked(nir_builder *b, nir_alu_dest dest, mov->src[0].src = nir_src_for_ssa(def); for (unsigned i = def->num_components; i < 4; i++) mov->src[0].swizzle[i] = def->num_components - 1; - nir_instr_insert_after_cf_list(b->cf_node_list, &mov->instr); + nir_builder_instr_insert(b, &mov->instr); } static void @@ -902,7 +903,7 @@ ttn_kill(nir_builder *b, nir_op op, nir_alu_dest dest, nir_ssa_def **src) { nir_intrinsic_instr *discard = nir_intrinsic_instr_create(b->shader, nir_intrinsic_discard); - nir_instr_insert_after_cf_list(b->cf_node_list, &discard->instr); + nir_builder_instr_insert(b, &discard->instr); } static void @@ -912,7 +913,7 @@ ttn_kill_if(nir_builder *b, nir_op op, nir_alu_dest dest, nir_ssa_def **src) nir_intrinsic_instr *discard = nir_intrinsic_instr_create(b->shader, nir_intrinsic_discard_if); discard->src[0] = nir_src_for_ssa(cmp); - nir_instr_insert_after_cf_list(b->cf_node_list, &discard->instr); + nir_builder_instr_insert(b, &discard->instr); } static void @@ -976,14 +977,14 @@ static void ttn_cont(nir_builder *b) { nir_jump_instr *instr = nir_jump_instr_create(b->shader, nir_jump_continue); - nir_instr_insert_after_cf_list(b->cf_node_list, &instr->instr); + nir_builder_instr_insert(b, &instr->instr); } static void ttn_brk(nir_builder *b) { nir_jump_instr *instr = nir_jump_instr_create(b->shader, nir_jump_break); - nir_instr_insert_after_cf_list(b->cf_node_list, &instr->instr); + nir_builder_instr_insert(b, &instr->instr); } static void @@ -1279,7 +1280,7 @@ ttn_tex(struct ttn_compile *c, nir_alu_dest dest, nir_ssa_def **src) assert(src_number == num_srcs); nir_ssa_dest_init(&instr->instr, &instr->dest, 4, NULL); - nir_instr_insert_after_cf_list(b->cf_node_list, &instr->instr); + nir_builder_instr_insert(b, &instr->instr); /* Resolve the writemask on the texture op. */ ttn_move_dest(b, dest, &instr->dest.ssa); @@ -1318,10 +1319,10 @@ ttn_txq(struct ttn_compile *c, nir_alu_dest dest, nir_ssa_def **src) txs->src[0].src_type = nir_tex_src_lod; nir_ssa_dest_init(&txs->instr, &txs->dest, 3, NULL); - nir_instr_insert_after_cf_list(b->cf_node_list, &txs->instr); + nir_builder_instr_insert(b, &txs->instr); nir_ssa_dest_init(&qlv->instr, &qlv->dest, 1, NULL); - nir_instr_insert_after_cf_list(b->cf_node_list, &qlv->instr); + nir_builder_instr_insert(b, &qlv->instr); ttn_move_dest_masked(b, dest, &txs->dest.ssa, TGSI_WRITEMASK_XYZ); ttn_move_dest_masked(b, dest, &qlv->dest.ssa, TGSI_WRITEMASK_W); @@ -1730,7 +1731,7 @@ ttn_emit_instruction(struct ttn_compile *c) store->variables[0] = ttn_array_deref(c, store, var, offset, indirect); store->src[0] = nir_src_for_reg(dest.dest.reg.reg); - nir_instr_insert_after_cf_list(b->cf_node_list, &store->instr); + nir_builder_instr_insert(b, &store->instr); } } @@ -1759,11 +1760,26 @@ ttn_add_output_stores(struct ttn_compile *c) store->const_index[0] = loc; store->src[0].reg.reg = c->output_regs[loc].reg; store->src[0].reg.base_offset = c->output_regs[loc].offset; - nir_instr_insert_after_cf_list(b->cf_node_list, &store->instr); + nir_builder_instr_insert(b, &store->instr); } } } +static gl_shader_stage +tgsi_processor_to_shader_stage(unsigned processor) +{ + switch (processor) { + case TGSI_PROCESSOR_FRAGMENT: return MESA_SHADER_FRAGMENT; + case TGSI_PROCESSOR_VERTEX: return MESA_SHADER_VERTEX; + case TGSI_PROCESSOR_GEOMETRY: return MESA_SHADER_GEOMETRY; + case TGSI_PROCESSOR_TESS_CTRL: return MESA_SHADER_TESS_CTRL; + case TGSI_PROCESSOR_TESS_EVAL: return MESA_SHADER_TESS_EVAL; + case TGSI_PROCESSOR_COMPUTE: return MESA_SHADER_COMPUTE; + default: + unreachable("invalid TGSI processor"); + }; +} + struct nir_shader * tgsi_to_nir(const void *tgsi_tokens, const nir_shader_compiler_options *options) @@ -1775,7 +1791,12 @@ tgsi_to_nir(const void *tgsi_tokens, int ret; c = rzalloc(NULL, struct ttn_compile); - s = nir_shader_create(NULL, options); + + tgsi_scan_shader(tgsi_tokens, &scan); + c->scan = &scan; + + s = nir_shader_create(NULL, tgsi_processor_to_shader_stage(scan.processor), + options); nir_function *func = nir_function_create(s, "main"); nir_function_overload *overload = nir_function_overload_create(func); @@ -1784,9 +1805,6 @@ tgsi_to_nir(const void *tgsi_tokens, nir_builder_init(&c->build, impl); nir_builder_insert_after_cf_list(&c->build, &impl->body); - tgsi_scan_shader(tgsi_tokens, &scan); - c->scan = &scan; - s->num_inputs = scan.file_max[TGSI_FILE_INPUT] + 1; s->num_uniforms = scan.const_file_max[0] + 1; s->num_outputs = scan.file_max[TGSI_FILE_OUTPUT] + 1; diff --git a/src/gallium/auxiliary/tgsi/tgsi_text.c b/src/gallium/auxiliary/tgsi/tgsi_text.c index a6675c5168d..3e3ed5b19d1 100644 --- a/src/gallium/auxiliary/tgsi/tgsi_text.c +++ b/src/gallium/auxiliary/tgsi/tgsi_text.c @@ -259,7 +259,7 @@ struct translate_ctx struct tgsi_token *tokens_end; struct tgsi_header *header; unsigned processor : 4; - int implied_array_size : 5; + unsigned implied_array_size : 6; unsigned num_immediates; }; @@ -675,6 +675,9 @@ parse_register_dcl( eat_opt_white( &cur ); if (cur[0] == '[') { + bool is_in = *file == TGSI_FILE_INPUT; + bool is_out = *file == TGSI_FILE_OUTPUT; + ++cur; ctx->cur = cur; if (!parse_register_dcl_bracket( ctx, &brackets[1] )) @@ -684,7 +687,11 @@ parse_register_dcl( * input primitive. so we want to declare just * the index relevant to the semantics which is in * the second bracket */ - if (ctx->processor == TGSI_PROCESSOR_GEOMETRY && *file == TGSI_FILE_INPUT) { + + /* tessellation has similar constraints to geometry shader */ + if ((ctx->processor == TGSI_PROCESSOR_GEOMETRY && is_in) || + (ctx->processor == TGSI_PROCESSOR_TESS_EVAL && is_in) || + (ctx->processor == TGSI_PROCESSOR_TESS_CTRL && (is_in || is_out))) { brackets[0] = brackets[1]; *num_brackets = 1; } else { @@ -740,6 +747,14 @@ parse_dst_operand( dst->Dimension.Indirect = 0; dst->Dimension.Dimension = 0; dst->Dimension.Index = bracket[0].index; + + if (bracket[0].ind_file != TGSI_FILE_NULL) { + dst->Dimension.Indirect = 1; + dst->DimIndirect.File = bracket[0].ind_file; + dst->DimIndirect.Index = bracket[0].ind_index; + dst->DimIndirect.Swizzle = bracket[0].ind_comp; + dst->DimIndirect.ArrayID = bracket[0].ind_array; + } bracket[0] = bracket[1]; } dst->Register.Index = bracket[0].index; @@ -1623,6 +1638,10 @@ static boolean translate( struct translate_ctx *ctx ) if (!parse_header( ctx )) return FALSE; + if (ctx->processor == TGSI_PROCESSOR_TESS_CTRL || + ctx->processor == TGSI_PROCESSOR_TESS_EVAL) + ctx->implied_array_size = 32; + while (*ctx->cur != '\0') { uint label_val = 0; if (!eat_white( &ctx->cur )) { diff --git a/src/gallium/auxiliary/util/u_blitter.c b/src/gallium/auxiliary/util/u_blitter.c index 85206eab1a7..9bba07aa18e 100644 --- a/src/gallium/auxiliary/util/u_blitter.c +++ b/src/gallium/auxiliary/util/u_blitter.c @@ -104,7 +104,7 @@ struct blitter_context_priv void *fs_resolve_uint[PIPE_MAX_TEXTURE_TYPES][NUM_RESOLVE_FRAG_SHADERS][2]; /* Blend state. */ - void *blend[PIPE_MASK_RGBA+1]; /**< blend state with writemask */ + void *blend[PIPE_MASK_RGBA+1][2]; /**< blend state with writemask */ void *blend_clear[GET_CLEAR_BLEND_STATE_IDX(PIPE_CLEAR_COLOR)+1]; /* Depth stencil alpha state. */ @@ -159,7 +159,7 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe) struct pipe_rasterizer_state rs_state; struct pipe_sampler_state sampler_state; struct pipe_vertex_element velem[2]; - unsigned i; + unsigned i, j; ctx = CALLOC_STRUCT(blitter_context_priv); if (!ctx) @@ -208,8 +208,20 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe) memset(&blend, 0, sizeof(blend)); for (i = 0; i <= PIPE_MASK_RGBA; i++) { - blend.rt[0].colormask = i; - ctx->blend[i] = pipe->create_blend_state(pipe, &blend); + for (j = 0; j < 2; j++) { + memset(&blend.rt[0], 0, sizeof(blend.rt[0])); + blend.rt[0].colormask = i; + if (j) { + blend.rt[0].blend_enable = 1; + blend.rt[0].rgb_func = PIPE_BLEND_ADD; + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; + blend.rt[0].alpha_func = PIPE_BLEND_ADD; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA; + } + ctx->blend[i][j] = pipe->create_blend_state(pipe, &blend); + } } /* depth stencil alpha state objects */ @@ -409,9 +421,10 @@ void util_blitter_destroy(struct blitter_context *blitter) struct pipe_context *pipe = blitter->pipe; int i, j, f; - for (i = 0; i <= PIPE_MASK_RGBA; i++) { - pipe->delete_blend_state(pipe, ctx->blend[i]); - } + for (i = 0; i <= PIPE_MASK_RGBA; i++) + for (j = 0; j < 2; j++) + pipe->delete_blend_state(pipe, ctx->blend[i][j]); + for (i = 0; i < Elements(ctx->blend_clear); i++) { if (ctx->blend_clear[i]) pipe->delete_blend_state(pipe, ctx->blend_clear[i]); @@ -1217,7 +1230,7 @@ static void *get_clear_blend_state(struct blitter_context_priv *ctx, /* Return an existing blend state. */ if (!clear_buffers) - return ctx->blend[0]; + return ctx->blend[0][0]; index = GET_CLEAR_BLEND_STATE_IDX(clear_buffers); @@ -1483,7 +1496,8 @@ void util_blitter_copy_texture(struct blitter_context *blitter, /* Copy. */ util_blitter_blit_generic(blitter, dst_view, &dstbox, src_view, srcbox, src->width0, src->height0, - PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL); + PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL, + FALSE); pipe_surface_reference(&dst_view, NULL); pipe_sampler_view_reference(&src_view, NULL); @@ -1496,7 +1510,8 @@ void util_blitter_blit_generic(struct blitter_context *blitter, const struct pipe_box *srcbox, unsigned src_width0, unsigned src_height0, unsigned mask, unsigned filter, - const struct pipe_scissor_state *scissor) + const struct pipe_scissor_state *scissor, + boolean alpha_blend) { struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter; struct pipe_context *pipe = ctx->base.pipe; @@ -1550,7 +1565,7 @@ void util_blitter_blit_generic(struct blitter_context *blitter, fb_state.zsbuf = NULL; if (blit_depth || blit_stencil) { - pipe->bind_blend_state(pipe, ctx->blend[0]); + pipe->bind_blend_state(pipe, ctx->blend[0][0]); if (blit_depth && blit_stencil) { pipe->bind_depth_stencil_alpha_state(pipe, @@ -1573,7 +1588,9 @@ void util_blitter_blit_generic(struct blitter_context *blitter, } } else { - pipe->bind_blend_state(pipe, ctx->blend[mask & PIPE_MASK_RGBA]); + unsigned colormask = mask & PIPE_MASK_RGBA; + + pipe->bind_blend_state(pipe, ctx->blend[colormask][alpha_blend]); pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil); ctx->bind_fs_state(pipe, blitter_get_fs_texfetch_col(ctx, src->format, src_target, @@ -1786,7 +1803,8 @@ util_blitter_blit(struct blitter_context *blitter, util_blitter_blit_generic(blitter, dst_view, &info->dst.box, src_view, &info->src.box, src->width0, src->height0, info->mask, info->filter, - info->scissor_enable ? &info->scissor : NULL); + info->scissor_enable ? &info->scissor : NULL, + info->alpha_blend); pipe_surface_reference(&dst_view, NULL); pipe_sampler_view_reference(&src_view, NULL); @@ -1815,7 +1833,7 @@ void util_blitter_clear_render_target(struct blitter_context *blitter, blitter_disable_render_cond(ctx); /* bind states */ - pipe->bind_blend_state(pipe, ctx->blend[PIPE_MASK_RGBA]); + pipe->bind_blend_state(pipe, ctx->blend[PIPE_MASK_RGBA][0]); pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil); bind_fs_write_one_cbuf(ctx); pipe->bind_vertex_elements_state(pipe, ctx->velem_state); @@ -1867,7 +1885,7 @@ void util_blitter_clear_depth_stencil(struct blitter_context *blitter, blitter_disable_render_cond(ctx); /* bind states */ - pipe->bind_blend_state(pipe, ctx->blend[0]); + pipe->bind_blend_state(pipe, ctx->blend[0][0]); if ((clear_flags & PIPE_CLEAR_DEPTHSTENCIL) == PIPE_CLEAR_DEPTHSTENCIL) { sr.ref_value[0] = stencil & 0xff; pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_write_depth_stencil); @@ -1933,8 +1951,8 @@ void util_blitter_custom_depth_stencil(struct blitter_context *blitter, blitter_disable_render_cond(ctx); /* bind states */ - pipe->bind_blend_state(pipe, cbsurf ? ctx->blend[PIPE_MASK_RGBA] : - ctx->blend[0]); + pipe->bind_blend_state(pipe, cbsurf ? ctx->blend[PIPE_MASK_RGBA][0] : + ctx->blend[0][0]); pipe->bind_depth_stencil_alpha_state(pipe, dsa_stage); if (cbsurf) bind_fs_write_one_cbuf(ctx); @@ -2187,7 +2205,7 @@ void util_blitter_custom_color(struct blitter_context *blitter, /* bind states */ pipe->bind_blend_state(pipe, custom_blend ? custom_blend - : ctx->blend[PIPE_MASK_RGBA]); + : ctx->blend[PIPE_MASK_RGBA][0]); pipe->bind_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_stencil); bind_fs_write_one_cbuf(ctx); pipe->bind_vertex_elements_state(pipe, ctx->velem_state); diff --git a/src/gallium/auxiliary/util/u_blitter.h b/src/gallium/auxiliary/util/u_blitter.h index 0cd173d6284..becdb029f13 100644 --- a/src/gallium/auxiliary/util/u_blitter.h +++ b/src/gallium/auxiliary/util/u_blitter.h @@ -246,7 +246,8 @@ void util_blitter_blit_generic(struct blitter_context *blitter, const struct pipe_box *srcbox, unsigned src_width0, unsigned src_height0, unsigned mask, unsigned filter, - const struct pipe_scissor_state *scissor); + const struct pipe_scissor_state *scissor, + boolean alpha_blend); void util_blitter_blit(struct blitter_context *blitter, const struct pipe_blit_info *info); diff --git a/src/gallium/auxiliary/util/u_surface.c b/src/gallium/auxiliary/util/u_surface.c index 654b5bbc552..70ed911b7f1 100644 --- a/src/gallium/auxiliary/util/u_surface.c +++ b/src/gallium/auxiliary/util/u_surface.c @@ -676,6 +676,9 @@ util_try_blit_via_copy_region(struct pipe_context *ctx, return FALSE; } + if (blit->alpha_blend) + return FALSE; + ctx->resource_copy_region(ctx, blit->dst.resource, blit->dst.level, blit->dst.box.x, blit->dst.box.y, blit->dst.box.z, blit->src.resource, blit->src.level, diff --git a/src/gallium/drivers/freedreno/a2xx/a2xx.xml.h b/src/gallium/drivers/freedreno/a2xx/a2xx.xml.h index c4516baf2ec..dd489568a77 100644 --- a/src/gallium/drivers/freedreno/a2xx/a2xx.xml.h +++ b/src/gallium/drivers/freedreno/a2xx/a2xx.xml.h @@ -13,8 +13,8 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63728 bytes, from 2015-08-05 18:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63915 bytes, from 2015-08-24 16:56:28) Copyright (C) 2013-2015 by the following authors: - Rob Clark <[email protected]> (robclark) diff --git a/src/gallium/drivers/freedreno/a3xx/a3xx.xml.h b/src/gallium/drivers/freedreno/a3xx/a3xx.xml.h index 8e8cf6a03f2..441bfec5756 100644 --- a/src/gallium/drivers/freedreno/a3xx/a3xx.xml.h +++ b/src/gallium/drivers/freedreno/a3xx/a3xx.xml.h @@ -13,8 +13,8 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63728 bytes, from 2015-08-05 18:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63915 bytes, from 2015-08-24 16:56:28) Copyright (C) 2013-2015 by the following authors: - Rob Clark <[email protected]> (robclark) @@ -326,6 +326,13 @@ enum a3xx_tex_type { A3XX_TEX_3D = 3, }; +enum a3xx_tex_msaa { + A3XX_TPL1_MSAA1X = 0, + A3XX_TPL1_MSAA2X = 1, + A3XX_TPL1_MSAA4X = 2, + A3XX_TPL1_MSAA8X = 3, +}; + #define A3XX_INT0_RBBM_GPU_IDLE 0x00000001 #define A3XX_INT0_RBBM_AHB_ERROR 0x00000002 #define A3XX_INT0_RBBM_REG_TIMEOUT 0x00000004 @@ -2652,6 +2659,7 @@ static inline uint32_t A3XX_VGT_DRAW_INITIATOR_NUM_INSTANCES(uint32_t val) #define REG_A3XX_VGT_IMMED_DATA 0x000021fd #define REG_A3XX_TEX_SAMP_0 0x00000000 +#define A3XX_TEX_SAMP_0_CLAMPENABLE 0x00000001 #define A3XX_TEX_SAMP_0_MIPFILTER_LINEAR 0x00000002 #define A3XX_TEX_SAMP_0_XY_MAG__MASK 0x0000000c #define A3XX_TEX_SAMP_0_XY_MAG__SHIFT 2 @@ -2695,6 +2703,7 @@ static inline uint32_t A3XX_TEX_SAMP_0_COMPARE_FUNC(enum adreno_compare_func val { return ((val) << A3XX_TEX_SAMP_0_COMPARE_FUNC__SHIFT) & A3XX_TEX_SAMP_0_COMPARE_FUNC__MASK; } +#define A3XX_TEX_SAMP_0_CUBEMAPSEAMLESSFILTOFF 0x01000000 #define A3XX_TEX_SAMP_0_UNNORM_COORDS 0x80000000 #define REG_A3XX_TEX_SAMP_1 0x00000001 @@ -2750,6 +2759,12 @@ static inline uint32_t A3XX_TEX_CONST_0_MIPLVLS(uint32_t val) { return ((val) << A3XX_TEX_CONST_0_MIPLVLS__SHIFT) & A3XX_TEX_CONST_0_MIPLVLS__MASK; } +#define A3XX_TEX_CONST_0_MSAATEX__MASK 0x00300000 +#define A3XX_TEX_CONST_0_MSAATEX__SHIFT 20 +static inline uint32_t A3XX_TEX_CONST_0_MSAATEX(enum a3xx_tex_msaa val) +{ + return ((val) << A3XX_TEX_CONST_0_MSAATEX__SHIFT) & A3XX_TEX_CONST_0_MSAATEX__MASK; +} #define A3XX_TEX_CONST_0_FMT__MASK 0x1fc00000 #define A3XX_TEX_CONST_0_FMT__SHIFT 22 static inline uint32_t A3XX_TEX_CONST_0_FMT(enum a3xx_tex_fmt val) @@ -2785,7 +2800,7 @@ static inline uint32_t A3XX_TEX_CONST_1_FETCHSIZE(enum a3xx_tex_fetchsize val) } #define REG_A3XX_TEX_CONST_2 0x00000002 -#define A3XX_TEX_CONST_2_INDX__MASK 0x000000ff +#define A3XX_TEX_CONST_2_INDX__MASK 0x000001ff #define A3XX_TEX_CONST_2_INDX__SHIFT 0 static inline uint32_t A3XX_TEX_CONST_2_INDX(uint32_t val) { @@ -2805,7 +2820,7 @@ static inline uint32_t A3XX_TEX_CONST_2_SWAP(enum a3xx_color_swap val) } #define REG_A3XX_TEX_CONST_3 0x00000003 -#define A3XX_TEX_CONST_3_LAYERSZ1__MASK 0x00007fff +#define A3XX_TEX_CONST_3_LAYERSZ1__MASK 0x0001ffff #define A3XX_TEX_CONST_3_LAYERSZ1__SHIFT 0 static inline uint32_t A3XX_TEX_CONST_3_LAYERSZ1(uint32_t val) { diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_format.c b/src/gallium/drivers/freedreno/a3xx/fd3_format.c index ec87aa979e3..04cb9b98fb7 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_format.c +++ b/src/gallium/drivers/freedreno/a3xx/fd3_format.c @@ -262,6 +262,15 @@ static struct fd3_format formats[PIPE_FORMAT_COUNT] = { _T(ETC2_R11_SNORM, ETC2_R11_SNORM, NONE, WZYX), _T(ETC2_RG11_UNORM, ETC2_RG11_UNORM, NONE, WZYX), _T(ETC2_RG11_SNORM, ETC2_RG11_SNORM, NONE, WZYX), + + _T(DXT1_RGB, DXT1, NONE, WZYX), + _T(DXT1_SRGB, DXT1, NONE, WZYX), + _T(DXT1_RGBA, DXT1, NONE, WZYX), + _T(DXT1_SRGBA, DXT1, NONE, WZYX), + _T(DXT3_RGBA, DXT3, NONE, WZYX), + _T(DXT3_SRGBA, DXT3, NONE, WZYX), + _T(DXT5_RGBA, DXT5, NONE, WZYX), + _T(DXT5_SRGBA, DXT5, NONE, WZYX), }; enum a3xx_vtx_fmt @@ -301,7 +310,7 @@ fd3_pipe2fetchsize(enum pipe_format format) { if (format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) format = PIPE_FORMAT_Z32_FLOAT; - switch (util_format_get_blocksizebits(format)) { + switch (util_format_get_blocksizebits(format) / util_format_get_blockwidth(format)) { case 8: return TFETCH_1_BYTE; case 16: return TFETCH_2_BYTE; case 32: return TFETCH_4_BYTE; diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_rasterizer.c b/src/gallium/drivers/freedreno/a3xx/fd3_rasterizer.c index 9c16804fff5..583caaa806f 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_rasterizer.c +++ b/src/gallium/drivers/freedreno/a3xx/fd3_rasterizer.c @@ -73,7 +73,7 @@ fd3_rasterizer_state_create(struct pipe_context *pctx, so->gras_su_poly_offset_scale = A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL(cso->offset_scale); so->gras_su_poly_offset_offset = - A3XX_GRAS_SU_POLY_OFFSET_OFFSET(cso->offset_units); + A3XX_GRAS_SU_POLY_OFFSET_OFFSET(cso->offset_units * 2.0f); so->gras_su_mode_control = A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(cso->line_width/2.0); diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_texture.c b/src/gallium/drivers/freedreno/a3xx/fd3_texture.c index c30658d0e7b..2d6ecb2c050 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_texture.c +++ b/src/gallium/drivers/freedreno/a3xx/fd3_texture.c @@ -115,6 +115,7 @@ fd3_sampler_state_create(struct pipe_context *pctx, so->texsamp0 = COND(!cso->normalized_coords, A3XX_TEX_SAMP_0_UNNORM_COORDS) | + COND(!cso->seamless_cube_map, A3XX_TEX_SAMP_0_CUBEMAPSEAMLESSFILTOFF) | COND(miplinear, A3XX_TEX_SAMP_0_MIPFILTER_LINEAR) | A3XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter, aniso)) | A3XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter, aniso)) | @@ -239,7 +240,7 @@ fd3_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, A3XX_TEX_CONST_1_HEIGHT(u_minify(prsc->height0, lvl)); /* when emitted, A3XX_TEX_CONST_2_INDX() must be OR'd in: */ so->texconst2 = - A3XX_TEX_CONST_2_PITCH(rsc->slices[lvl].pitch * rsc->cpp); + A3XX_TEX_CONST_2_PITCH(util_format_get_nblocksx(cso->format, rsc->slices[lvl].pitch) * rsc->cpp); switch (prsc->target) { case PIPE_TEXTURE_1D_ARRAY: case PIPE_TEXTURE_2D_ARRAY: diff --git a/src/gallium/drivers/freedreno/a4xx/a4xx.xml.h b/src/gallium/drivers/freedreno/a4xx/a4xx.xml.h index 563f70ac5eb..2e1d712a28c 100644 --- a/src/gallium/drivers/freedreno/a4xx/a4xx.xml.h +++ b/src/gallium/drivers/freedreno/a4xx/a4xx.xml.h @@ -13,8 +13,8 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63728 bytes, from 2015-08-05 18:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63915 bytes, from 2015-08-24 16:56:28) Copyright (C) 2013-2015 by the following authors: - Rob Clark <[email protected]> (robclark) @@ -162,10 +162,13 @@ enum a4xx_tex_fmt { TFMT4_8_UNORM = 4, TFMT4_8_8_UNORM = 14, TFMT4_8_8_8_8_UNORM = 28, + TFMT4_8_SNORM = 5, TFMT4_8_8_SNORM = 15, TFMT4_8_8_8_8_SNORM = 29, + TFMT4_8_UINT = 6, TFMT4_8_8_UINT = 16, TFMT4_8_8_8_8_UINT = 30, + TFMT4_8_SINT = 7, TFMT4_8_8_SINT = 17, TFMT4_8_8_8_8_SINT = 31, TFMT4_16_UINT = 21, @@ -430,7 +433,7 @@ static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_SWAP(enum a3xx_color_swap val) return ((val) << A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT) & A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK; } #define A4XX_RB_MRT_BUF_INFO_COLOR_SRGB 0x00002000 -#define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK 0x007fc000 +#define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK 0xffffc000 #define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__SHIFT 14 static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(uint32_t val) { @@ -440,7 +443,7 @@ static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(uint32_t val) static inline uint32_t REG_A4XX_RB_MRT_BASE(uint32_t i0) { return 0x000020a6 + 0x5*i0; } static inline uint32_t REG_A4XX_RB_MRT_CONTROL3(uint32_t i0) { return 0x000020a7 + 0x5*i0; } -#define A4XX_RB_MRT_CONTROL3_STRIDE__MASK 0x0001fff8 +#define A4XX_RB_MRT_CONTROL3_STRIDE__MASK 0x03fffff8 #define A4XX_RB_MRT_CONTROL3_STRIDE__SHIFT 3 static inline uint32_t A4XX_RB_MRT_CONTROL3_STRIDE(uint32_t val) { @@ -1460,6 +1463,7 @@ static inline uint32_t A4XX_SP_FS_MRT_REG_MRTFORMAT(enum a4xx_color_fmt val) { return ((val) << A4XX_SP_FS_MRT_REG_MRTFORMAT__SHIFT) & A4XX_SP_FS_MRT_REG_MRTFORMAT__MASK; } +#define A4XX_SP_FS_MRT_REG_COLOR_SRGB 0x00040000 #define REG_A4XX_SP_CS_CTRL_REG0 0x00002300 diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_emit.h b/src/gallium/drivers/freedreno/a4xx/fd4_emit.h index ab7850e50b0..3a1d4b617d3 100644 --- a/src/gallium/drivers/freedreno/a4xx/fd4_emit.h +++ b/src/gallium/drivers/freedreno/a4xx/fd4_emit.h @@ -56,6 +56,7 @@ struct fd4_emit { uint32_t sprite_coord_enable; /* bitmask */ bool sprite_coord_mode; bool rasterflat; + bool no_decode_srgb; /* cached to avoid repeated lookups of same variants: */ struct ir3_shader_variant *vp, *fp; diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_format.c b/src/gallium/drivers/freedreno/a4xx/fd4_format.c index 3e0045449eb..6c9e217d5ad 100644 --- a/src/gallium/drivers/freedreno/a4xx/fd4_format.c +++ b/src/gallium/drivers/freedreno/a4xx/fd4_format.c @@ -79,9 +79,9 @@ struct fd4_format { static struct fd4_format formats[PIPE_FORMAT_COUNT] = { /* 8-bit */ VT(R8_UNORM, 8_UNORM, R8_UNORM, WZYX), - V_(R8_SNORM, 8_SNORM, NONE, WZYX), - V_(R8_UINT, 8_UINT, NONE, WZYX), - V_(R8_SINT, 8_SINT, NONE, WZYX), + VT(R8_SNORM, 8_SNORM, NONE, WZYX), + VT(R8_UINT, 8_UINT, NONE, WZYX), + VT(R8_SINT, 8_SINT, NONE, WZYX), V_(R8_USCALED, 8_UINT, NONE, WZYX), V_(R8_SSCALED, 8_UINT, NONE, WZYX), @@ -115,8 +115,8 @@ static struct fd4_format formats[PIPE_FORMAT_COUNT] = { VT(R8G8_UNORM, 8_8_UNORM, R8G8_UNORM, WZYX), VT(R8G8_SNORM, 8_8_SNORM, R8G8_SNORM, WZYX), - VT(R8G8_UINT, 8_8_UINT, NONE, WZYX), - VT(R8G8_SINT, 8_8_SINT, NONE, WZYX), + VT(R8G8_UINT, 8_8_UINT, R8G8_UINT, WZYX), + VT(R8G8_SINT, 8_8_SINT, R8G8_SINT, WZYX), V_(R8G8_USCALED, 8_8_UINT, NONE, WZYX), V_(R8G8_SSCALED, 8_8_SINT, NONE, WZYX), diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_gmem.c b/src/gallium/drivers/freedreno/a4xx/fd4_gmem.c index 81c37f72565..3f8bbf3a124 100644 --- a/src/gallium/drivers/freedreno/a4xx/fd4_gmem.c +++ b/src/gallium/drivers/freedreno/a4xx/fd4_gmem.c @@ -46,7 +46,8 @@ static void emit_mrt(struct fd_ringbuffer *ring, unsigned nr_bufs, - struct pipe_surface **bufs, uint32_t *bases, uint32_t bin_w) + struct pipe_surface **bufs, uint32_t *bases, + uint32_t bin_w, bool decode_srgb) { enum a4xx_tile_mode tile_mode; unsigned i; @@ -60,6 +61,7 @@ emit_mrt(struct fd_ringbuffer *ring, unsigned nr_bufs, for (i = 0; i < A4XX_MAX_RENDER_TARGETS; i++) { enum a4xx_color_fmt format = 0; enum a3xx_color_swap swap = WZYX; + bool srgb = false; struct fd_resource *rsc = NULL; struct fd_resource_slice *slice = NULL; uint32_t stride = 0; @@ -68,10 +70,9 @@ emit_mrt(struct fd_ringbuffer *ring, unsigned nr_bufs, if ((i < nr_bufs) && bufs[i]) { struct pipe_surface *psurf = bufs[i]; - enum pipe_format pformat = 0; + enum pipe_format pformat = psurf->format; rsc = fd_resource(psurf->texture); - pformat = psurf->format; /* In case we're drawing to Z32F_S8, the "color" actually goes to * the stencil @@ -86,6 +87,11 @@ emit_mrt(struct fd_ringbuffer *ring, unsigned nr_bufs, format = fd4_pipe2color(pformat); swap = fd4_pipe2swap(pformat); + if (decode_srgb) + srgb = util_format_is_srgb(pformat); + else + pformat = util_format_linear(pformat); + debug_assert(psurf->u.tex.first_layer == psurf->u.tex.last_layer); offset = fd_resource_offset(rsc, psurf->u.tex.level, @@ -108,7 +114,8 @@ emit_mrt(struct fd_ringbuffer *ring, unsigned nr_bufs, OUT_RING(ring, A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT(format) | A4XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE(tile_mode) | A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(stride) | - A4XX_RB_MRT_BUF_INFO_COLOR_SWAP(swap)); + A4XX_RB_MRT_BUF_INFO_COLOR_SWAP(swap) | + COND(srgb, A4XX_RB_MRT_BUF_INFO_COLOR_SRGB)); if (bin_w || (i >= nr_bufs) || !bufs[i]) { OUT_RING(ring, base); OUT_RING(ring, A4XX_RB_MRT_CONTROL3_STRIDE(stride)); @@ -282,7 +289,7 @@ emit_mem2gmem_surf(struct fd_context *ctx, uint32_t *bases, struct fd_ringbuffer *ring = ctx->ring; struct pipe_surface *zsbufs[2]; - emit_mrt(ring, nr_bufs, bufs, bases, bin_w); + emit_mrt(ring, nr_bufs, bufs, bases, bin_w, false); if (bufs[0] && (bufs[0]->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)) { /* The gmem_restore_tex logic will put the first buffer's stencil @@ -315,6 +322,7 @@ fd4_emit_tile_mem2gmem(struct fd_context *ctx, struct fd_tile *tile) .key = { .half_precision = fd_half_precision(pfb), }, + .no_decode_srgb = true, }; unsigned char mrt_comp[A4XX_MAX_RENDER_TARGETS] = {0}; float x0, y0, x1, y1; @@ -520,7 +528,7 @@ fd4_emit_sysmem_prep(struct fd_context *ctx) OUT_RING(ring, A4XX_RB_FRAME_BUFFER_DIMENSION_WIDTH(pfb->width) | A4XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT(pfb->height)); - emit_mrt(ring, pfb->nr_cbufs, pfb->cbufs, NULL, 0); + emit_mrt(ring, pfb->nr_cbufs, pfb->cbufs, NULL, 0, true); /* setup scissor/offset for current tile: */ OUT_PKT0(ring, REG_A4XX_RB_BIN_OFFSET, 1); @@ -677,7 +685,7 @@ fd4_emit_tile_renderprep(struct fd_context *ctx, struct fd_tile *tile) OUT_RING(ring, CP_SET_BIN_1_X1(x1) | CP_SET_BIN_1_Y1(y1)); OUT_RING(ring, CP_SET_BIN_2_X2(x2) | CP_SET_BIN_2_Y2(y2)); - emit_mrt(ring, pfb->nr_cbufs, pfb->cbufs, gmem->cbuf_base, gmem->bin_w); + emit_mrt(ring, pfb->nr_cbufs, pfb->cbufs, gmem->cbuf_base, gmem->bin_w, true); /* setup scissor/offset for current tile: */ OUT_PKT0(ring, REG_A4XX_RB_BIN_OFFSET, 1); diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_program.c b/src/gallium/drivers/freedreno/a4xx/fd4_program.c index 1a6d0142132..a3d7123ccee 100644 --- a/src/gallium/drivers/freedreno/a4xx/fd4_program.c +++ b/src/gallium/drivers/freedreno/a4xx/fd4_program.c @@ -450,10 +450,15 @@ fd4_program_emit(struct fd_ringbuffer *ring, struct fd4_emit *emit, OUT_PKT0(ring, REG_A4XX_SP_FS_MRT_REG(0), 8); for (i = 0; i < 8; i++) { enum a4xx_color_fmt format = 0; - if (i < nr) + bool srgb = false; + if (i < nr) { format = fd4_emit_format(bufs[i]); + if (bufs[i] && !emit->no_decode_srgb) + srgb = util_format_is_srgb(bufs[i]->format); + } OUT_RING(ring, A4XX_SP_FS_MRT_REG_REGID(color_regid[i]) | A4XX_SP_FS_MRT_REG_MRTFORMAT(format) | + COND(srgb, A4XX_SP_FS_MRT_REG_COLOR_SRGB) | COND(emit->key.half_precision, A4XX_SP_FS_MRT_REG_HALF_PRECISION)); } diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_texture.c b/src/gallium/drivers/freedreno/a4xx/fd4_texture.c index d2bc5fee6c0..213b29c9181 100644 --- a/src/gallium/drivers/freedreno/a4xx/fd4_texture.c +++ b/src/gallium/drivers/freedreno/a4xx/fd4_texture.c @@ -187,9 +187,9 @@ fd4_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, A4XX_TEX_CONST_3_LAYERSZ(rsc->layer_size); break; case PIPE_TEXTURE_CUBE: - case PIPE_TEXTURE_CUBE_ARRAY: /* ?? not sure about _CUBE_ARRAY */ + case PIPE_TEXTURE_CUBE_ARRAY: so->texconst3 = - A4XX_TEX_CONST_3_DEPTH(1) | + A4XX_TEX_CONST_3_DEPTH(prsc->array_size / 6) | A4XX_TEX_CONST_3_LAYERSZ(rsc->layer_size); break; case PIPE_TEXTURE_3D: diff --git a/src/gallium/drivers/freedreno/adreno_common.xml.h b/src/gallium/drivers/freedreno/adreno_common.xml.h index 00b6acba065..29944b7ac08 100644 --- a/src/gallium/drivers/freedreno/adreno_common.xml.h +++ b/src/gallium/drivers/freedreno/adreno_common.xml.h @@ -13,8 +13,8 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63728 bytes, from 2015-08-05 18:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63915 bytes, from 2015-08-24 16:56:28) Copyright (C) 2013-2015 by the following authors: - Rob Clark <[email protected]> (robclark) diff --git a/src/gallium/drivers/freedreno/adreno_pm4.xml.h b/src/gallium/drivers/freedreno/adreno_pm4.xml.h index 98a90e26679..432dce3dfb3 100644 --- a/src/gallium/drivers/freedreno/adreno_pm4.xml.h +++ b/src/gallium/drivers/freedreno/adreno_pm4.xml.h @@ -13,8 +13,8 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2015-05-20 20:03:14) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14968 bytes, from 2015-05-20 20:12:27) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-05-20 20:03:14) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63728 bytes, from 2015-08-05 18:07:28) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 67120 bytes, from 2015-08-14 23:22:03) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 63915 bytes, from 2015-08-24 16:56:28) Copyright (C) 2013-2015 by the following authors: - Rob Clark <[email protected]> (robclark) diff --git a/src/gallium/drivers/freedreno/freedreno_context.c b/src/gallium/drivers/freedreno/freedreno_context.c index 8e6d43150ce..0b6b9fbbe7a 100644 --- a/src/gallium/drivers/freedreno/freedreno_context.c +++ b/src/gallium/drivers/freedreno/freedreno_context.c @@ -131,11 +131,13 @@ static void fd_context_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence, unsigned flags) { + struct fd_ringbuffer *ring = fd_context(pctx)->ring; + fd_context_render(pctx); if (fence) { fd_screen_fence_ref(pctx->screen, fence, NULL); - *fence = fd_fence_create(pctx); + *fence = fd_fence_create(pctx, fd_ringbuffer_timestamp(ring)); } } diff --git a/src/gallium/drivers/freedreno/freedreno_fence.c b/src/gallium/drivers/freedreno/freedreno_fence.c index 04a9feacd58..5125f091860 100644 --- a/src/gallium/drivers/freedreno/freedreno_fence.c +++ b/src/gallium/drivers/freedreno/freedreno_fence.c @@ -50,35 +50,18 @@ fd_screen_fence_ref(struct pipe_screen *pscreen, *ptr = pfence; } -/* TODO we need to spiff out libdrm_freedreno a bit to allow passing - * the timeout.. and maybe a better way to check if fence has been - * signaled. The current implementation is a bit lame for now to - * avoid bumping libdrm version requirement. - */ - -boolean fd_screen_fence_signalled(struct pipe_screen *screen, - struct pipe_fence_handle *fence) -{ - uint32_t timestamp = fd_ringbuffer_timestamp(fence->ctx->ring); - - /* TODO util helper for compare w/ rollover? */ - return timestamp >= fence->timestamp; -} - boolean fd_screen_fence_finish(struct pipe_screen *screen, struct pipe_fence_handle *fence, uint64_t timeout) { - if (!timeout) - return fd_screen_fence_signalled(screen, fence); - - if (fd_pipe_wait(fence->screen->pipe, fence->timestamp)) + if (fd_pipe_wait_timeout(fence->screen->pipe, fence->timestamp, timeout)) return false; return true; } -struct pipe_fence_handle * fd_fence_create(struct pipe_context *pctx) +struct pipe_fence_handle * fd_fence_create(struct pipe_context *pctx, + uint32_t timestamp) { struct pipe_fence_handle *fence; struct fd_context *ctx = fd_context(pctx); @@ -91,7 +74,7 @@ struct pipe_fence_handle * fd_fence_create(struct pipe_context *pctx) fence->ctx = ctx; fence->screen = ctx->screen; - fence->timestamp = fd_ringbuffer_timestamp(ctx->ring); + fence->timestamp = timestamp; return fence; } diff --git a/src/gallium/drivers/freedreno/freedreno_fence.h b/src/gallium/drivers/freedreno/freedreno_fence.h index e36bcc4d1f2..06c314a6116 100644 --- a/src/gallium/drivers/freedreno/freedreno_fence.h +++ b/src/gallium/drivers/freedreno/freedreno_fence.h @@ -34,11 +34,10 @@ void fd_screen_fence_ref(struct pipe_screen *pscreen, struct pipe_fence_handle **ptr, struct pipe_fence_handle *pfence); -boolean fd_screen_fence_signalled(struct pipe_screen *screen, - struct pipe_fence_handle *pfence); boolean fd_screen_fence_finish(struct pipe_screen *screen, struct pipe_fence_handle *pfence, uint64_t timeout); -struct pipe_fence_handle * fd_fence_create(struct pipe_context *pctx); +struct pipe_fence_handle * fd_fence_create(struct pipe_context *pctx, + uint32_t timestamp); #endif /* FREEDRENO_FENCE_H_ */ diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c index 709ad4eb55b..98de0969cab 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.c +++ b/src/gallium/drivers/freedreno/freedreno_resource.c @@ -222,7 +222,7 @@ fd_resource_transfer_map(struct pipe_context *pctx, ptrans->level = level; ptrans->usage = usage; ptrans->box = *box; - ptrans->stride = slice->pitch * rsc->cpp; + ptrans->stride = util_format_get_nblocksx(format, slice->pitch) * rsc->cpp; ptrans->layer_stride = slice->size0; if (usage & PIPE_TRANSFER_READ) @@ -375,9 +375,11 @@ setup_slices(struct fd_resource *rsc, uint32_t alignment) for (level = 0; level <= prsc->last_level; level++) { struct fd_resource_slice *slice = fd_resource_slice(rsc, level); + uint32_t blocks; slice->pitch = width = align(width, 32); slice->offset = size; + blocks = util_format_get_nblocks(prsc->format, width, height); /* 1d array and 2d array textures must all have the same layer size * for each miplevel on a3xx. 3d textures can have different layer * sizes for high levels, but the hw auto-sizer is buggy (or at least @@ -387,9 +389,9 @@ setup_slices(struct fd_resource *rsc, uint32_t alignment) if (prsc->target == PIPE_TEXTURE_3D && ( level == 1 || (level > 1 && rsc->slices[level - 1].size0 > 0xf000))) - slice->size0 = align(slice->pitch * height * rsc->cpp, alignment); + slice->size0 = align(blocks * rsc->cpp, alignment); else if (level == 0 || rsc->layer_first || alignment == 1) - slice->size0 = align(slice->pitch * height * rsc->cpp, alignment); + slice->size0 = align(blocks * rsc->cpp, alignment); else slice->size0 = rsc->slices[level - 1].size0; @@ -459,7 +461,6 @@ fd_resource_create(struct pipe_screen *pscreen, if (is_a4xx(fd_screen(pscreen))) { switch (tmpl->target) { case PIPE_TEXTURE_3D: - /* TODO 3D_ARRAY? */ rsc->layer_first = false; break; default: diff --git a/src/gallium/drivers/freedreno/freedreno_screen.c b/src/gallium/drivers/freedreno/freedreno_screen.c index b55f5b36ca9..86e9a21da2f 100644 --- a/src/gallium/drivers/freedreno/freedreno_screen.c +++ b/src/gallium/drivers/freedreno/freedreno_screen.c @@ -163,7 +163,6 @@ fd_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_TEXTURE_MULTISAMPLE: case PIPE_CAP_TEXTURE_BARRIER: case PIPE_CAP_TEXTURE_MIRROR_CLAMP: - case PIPE_CAP_CUBE_MAP_ARRAY: case PIPE_CAP_MAX_DUAL_SOURCE_RENDER_TARGETS: case PIPE_CAP_START_INSTANCE: case PIPE_CAP_COMPUTE: @@ -176,6 +175,7 @@ fd_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_INDEP_BLEND_ENABLE: case PIPE_CAP_INDEP_BLEND_FUNC: case PIPE_CAP_TEXTURE_BUFFER_OBJECTS: + case PIPE_CAP_TEXTURE_HALF_FLOAT_LINEAR: return is_a3xx(screen) || is_a4xx(screen); case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT: @@ -191,8 +191,13 @@ fd_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) return 16383; case PIPE_CAP_DEPTH_CLIP_DISABLE: + case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE: return is_a3xx(screen); + case PIPE_CAP_TEXTURE_FLOAT_LINEAR: + case PIPE_CAP_CUBE_MAP_ARRAY: + return is_a4xx(screen); + case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT: return 256; @@ -202,7 +207,6 @@ fd_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) return is_ir3(screen) ? 130 : 120; /* Unsupported features. */ - case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE: case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER: case PIPE_CAP_TGSI_CAN_COMPACT_CONSTANTS: @@ -230,8 +234,6 @@ fd_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_RESOURCE_FROM_USER_MEMORY: case PIPE_CAP_DEVICE_RESET_STATUS_QUERY: case PIPE_CAP_MAX_SHADER_PATCH_VARYINGS: - case PIPE_CAP_TEXTURE_FLOAT_LINEAR: - case PIPE_CAP_TEXTURE_HALF_FLOAT_LINEAR: case PIPE_CAP_DEPTH_BOUNDS_TEST: return 0; diff --git a/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c b/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c index 0ab33455ed1..071901a3cc7 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_compiler_nir.c @@ -1636,6 +1636,11 @@ emit_tex(struct ir3_compile *ctx, nir_tex_instr *tex) coord[i] = ir3_SHL_B(b, coord[i], 0, lod, 0); } + /* the array coord for cube arrays needs 0.5 added to it */ + if (tex->sampler_dim == GLSL_SAMPLER_DIM_CUBE && tex->is_array && + opc != OPC_ISAML) + coord[3] = ir3_ADD_F(b, coord[3], 0, create_immed(b, fui(0.5)), 0); + /* * lay out the first argument in the proper order: * - actual coordinates first @@ -1759,6 +1764,12 @@ emit_tex_txs(struct ir3_compile *ctx, nir_tex_instr *tex) tex_info(tex, &flags, &coords); + /* Actually we want the number of dimensions, not coordinates. This + * distinction only matters for cubes. + */ + if (tex->sampler_dim == GLSL_SAMPLER_DIM_CUBE) + coords = 2; + dst = get_dst(ctx, &tex->dest, 4); compile_assert(ctx, tex->num_srcs == 1); @@ -2301,7 +2312,7 @@ emit_instructions(struct ir3_compile *ctx) ctx->ir = ir3_create(ctx->compiler, ninputs, noutputs); /* Create inputs in first block: */ - ctx->block = get_block(ctx, fxn->start_block); + ctx->block = get_block(ctx, nir_start_block(fxn)); ctx->in_block = ctx->block; list_addtail(&ctx->block->node, &ctx->ir->block_list); diff --git a/src/gallium/drivers/freedreno/ir3/ir3_nir_lower_if_else.c b/src/gallium/drivers/freedreno/ir3/ir3_nir_lower_if_else.c index dc9e4626f27..bed7b7b826a 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_nir_lower_if_else.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_nir_lower_if_else.c @@ -29,6 +29,7 @@ #include "ir3_nir.h" #include "glsl/nir/nir_builder.h" +#include "glsl/nir/nir_control_flow.h" /* Based on nir_opt_peephole_select, and hacked up to more aggressively * flatten anything that can be flattened diff --git a/src/gallium/drivers/freedreno/ir3/ir3_ra.c b/src/gallium/drivers/freedreno/ir3/ir3_ra.c index eaf3b3c35e8..88018398e96 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_ra.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_ra.c @@ -189,7 +189,7 @@ ir3_ra_alloc_reg_set(void *memctx) } /* allocate the reg-set.. */ - set->regs = ra_alloc_reg_set(set, ra_reg_count); + set->regs = ra_alloc_reg_set(set, ra_reg_count, true); set->ra_reg_to_gpr = ralloc_array(set, uint16_t, ra_reg_count); set->gpr_to_ra_reg = ralloc_array(set, uint16_t *, total_class_count); diff --git a/src/gallium/drivers/i915/i915_surface.c b/src/gallium/drivers/i915/i915_surface.c index 24e01560110..b2a639cb0f1 100644 --- a/src/gallium/drivers/i915/i915_surface.c +++ b/src/gallium/drivers/i915/i915_surface.c @@ -120,7 +120,8 @@ i915_surface_copy_render(struct pipe_context *pipe, util_blitter_blit_generic(i915->blitter, dst_view, &dstbox, src_view, src_box, src_width0, src_height0, - PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL); + PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL, + FALSE); return; fallback: diff --git a/src/gallium/drivers/nouveau/Makefile.sources b/src/gallium/drivers/nouveau/Makefile.sources index 3fae3bc9cba..9346ea3204d 100644 --- a/src/gallium/drivers/nouveau/Makefile.sources +++ b/src/gallium/drivers/nouveau/Makefile.sources @@ -121,7 +121,8 @@ NV50_CODEGEN_SOURCES := \ codegen/nv50_ir_target_nv50.cpp \ codegen/nv50_ir_target_nv50.h \ codegen/nv50_ir_util.cpp \ - codegen/nv50_ir_util.h + codegen/nv50_ir_util.h \ + codegen/unordered_set.h NVC0_CODEGEN_SOURCES := \ codegen/nv50_ir_emit_gk110.cpp \ diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir.h b/src/gallium/drivers/nouveau/codegen/nv50_ir.h index 3ddaeafebbd..ba1b0851927 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir.h +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir.h @@ -29,8 +29,8 @@ #include <deque> #include <list> #include <vector> -#include <tr1/unordered_set> +#include "codegen/unordered_set.h" #include "codegen/nv50_ir_util.h" #include "codegen/nv50_ir_graph.h" @@ -585,10 +585,10 @@ public: static inline Value *get(Iterator&); - std::tr1::unordered_set<ValueRef *> uses; + unordered_set<ValueRef *> uses; std::list<ValueDef *> defs; - typedef std::tr1::unordered_set<ValueRef *>::iterator UseIterator; - typedef std::tr1::unordered_set<ValueRef *>::const_iterator UseCIterator; + typedef unordered_set<ValueRef *>::iterator UseIterator; + typedef unordered_set<ValueRef *>::const_iterator UseCIterator; typedef std::list<ValueDef *>::iterator DefIterator; typedef std::list<ValueDef *>::const_iterator DefCIterator; diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gk110.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gk110.cpp index f06056f8f17..8f1542959c9 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gk110.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gk110.cpp @@ -933,6 +933,7 @@ CodeEmitterGK110::emitCVT(const Instruction *i) code[0] |= typeSizeofLog2(dType) << 10; code[0] |= typeSizeofLog2(i->sType) << 12; + code[1] |= i->subOp << 12; if (isSignedIntType(dType)) code[0] |= 0x4000; diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp index ef5c87d0437..6e22788341f 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp @@ -818,6 +818,7 @@ CodeEmitterGM107::emitI2F() emitField(0x31, 1, (insn->op == OP_ABS) || insn->src(0).mod.abs()); emitCC (0x2f); emitField(0x2d, 1, (insn->op == OP_NEG) || insn->src(0).mod.neg()); + emitField(0x29, 2, insn->subOp); emitRND (0x27, rnd, -1); emitField(0x0d, 1, isSignedType(insn->sType)); emitField(0x0a, 2, util_logbase2(typeSizeof(insn->sType))); @@ -850,6 +851,7 @@ CodeEmitterGM107::emitI2I() emitField(0x31, 1, (insn->op == OP_ABS) || insn->src(0).mod.abs()); emitCC (0x2f); emitField(0x2d, 1, (insn->op == OP_NEG) || insn->src(0).mod.neg()); + emitField(0x29, 2, insn->subOp); emitField(0x0d, 1, isSignedType(insn->sType)); emitField(0x0c, 1, isSignedType(insn->dType)); emitField(0x0a, 2, util_logbase2(typeSizeof(insn->sType))); diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp index f607f3ba3ec..6bf5219d346 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp @@ -1020,6 +1020,10 @@ CodeEmitterNVC0::emitCVT(Instruction *i) code[0] |= util_logbase2(typeSizeof(dType)) << 20; code[0] |= util_logbase2(typeSizeof(i->sType)) << 23; + // for 8/16 source types, the byte/word is in subOp. word 1 is + // represented as 2. + code[1] |= i->subOp << 0x17; + if (sat) code[0] |= 0x20; if (abs) @@ -2614,11 +2618,12 @@ private: int imul; // integer MUL to MUL delay 3 } res; struct ScoreData { - int r[64]; + int r[256]; int p[8]; int c; } rd, wr; int base; + int regs; void rebase(const int base) { @@ -2627,7 +2632,7 @@ private: return; this->base = 0; - for (int i = 0; i < 64; ++i) { + for (int i = 0; i < regs; ++i) { rd.r[i] += delta; wr.r[i] += delta; } @@ -2646,16 +2651,17 @@ private: res.imul += delta; res.tex += delta; } - void wipe() + void wipe(int regs) { memset(&rd, 0, sizeof(rd)); memset(&wr, 0, sizeof(wr)); memset(&res, 0, sizeof(res)); + this->regs = regs; } int getLatest(const ScoreData& d) const { int max = 0; - for (int i = 0; i < 64; ++i) + for (int i = 0; i < regs; ++i) if (d.r[i] > max) max = d.r[i]; for (int i = 0; i < 8; ++i) @@ -2690,7 +2696,7 @@ private: } void setMax(const RegScores *that) { - for (int i = 0; i < 64; ++i) { + for (int i = 0; i < regs; ++i) { rd.r[i] = MAX2(rd.r[i], that->rd.r[i]); wr.r[i] = MAX2(wr.r[i], that->wr.r[i]); } @@ -2711,7 +2717,7 @@ private: } void print(int cycle) { - for (int i = 0; i < 64; ++i) { + for (int i = 0; i < regs; ++i) { if (rd.r[i] > cycle) INFO("rd $r%i @ %i\n", i, rd.r[i]); if (wr.r[i] > cycle) @@ -2806,9 +2812,10 @@ SchedDataCalculator::getCycles(const Instruction *insn, int origDelay) const bool SchedDataCalculator::visit(Function *func) { + int regs = targ->getFileSize(FILE_GPR) + 1; scoreBoards.resize(func->cfg.getSize()); for (size_t i = 0; i < scoreBoards.size(); ++i) - scoreBoards[i].wipe(); + scoreBoards[i].wipe(regs); return true; } diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp index 4847a0f3355..f153674e9ce 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp @@ -2990,9 +2990,15 @@ Converter::handleInstruction(const struct tgsi_full_instruction *insn) case TGSI_OPCODE_UBFE: FOR_EACH_DST_ENABLED_CHANNEL(0, c, tgsi) { src0 = fetchSrc(0, c); - src1 = fetchSrc(1, c); - src2 = fetchSrc(2, c); - mkOp3(OP_INSBF, TYPE_U32, src1, src2, mkImm(0x808), src1); + if (tgsi.getSrc(1).getFile() == TGSI_FILE_IMMEDIATE && + tgsi.getSrc(2).getFile() == TGSI_FILE_IMMEDIATE) { + src1 = loadImm(NULL, tgsi.getSrc(2).getValueU32(c, info) << 8 | + tgsi.getSrc(1).getValueU32(c, info)); + } else { + src1 = fetchSrc(1, c); + src2 = fetchSrc(2, c); + mkOp3(OP_INSBF, TYPE_U32, src1, src2, mkImm(0x808), src1); + } mkOp2(OP_EXTBF, dstTy, dst0[c], src0, src1); } break; diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_gm107.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_gm107.cpp index 1f3fce2bb9a..420cc4ef7c0 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_gm107.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_gm107.cpp @@ -193,100 +193,16 @@ GM107LoweringPass::visit(Instruction *i) checkPredicate(i); switch (i->op) { - case OP_TEX: - case OP_TXB: - case OP_TXL: - case OP_TXF: - case OP_TXG: - return handleTEX(i->asTex()); - case OP_TXD: - return handleTXD(i->asTex()); - case OP_TXLQ: - return handleTXLQ(i->asTex()); - case OP_TXQ: - return handleTXQ(i->asTex()); - case OP_EX2: - bld.mkOp1(OP_PREEX2, TYPE_F32, i->getDef(0), i->getSrc(0)); - i->setSrc(0, i->getDef(0)); - break; - case OP_POW: - return handlePOW(i); - case OP_DIV: - return handleDIV(i); - case OP_MOD: - return handleMOD(i); - case OP_SQRT: - return handleSQRT(i); - case OP_EXPORT: - return handleEXPORT(i); case OP_PFETCH: return handlePFETCH(i); - case OP_EMIT: - case OP_RESTART: - return handleOUT(i); - case OP_RDSV: - return handleRDSV(i); - case OP_WRSV: - return handleWRSV(i); - case OP_LOAD: - if (i->src(0).getFile() == FILE_SHADER_INPUT) { - if (prog->getType() == Program::TYPE_COMPUTE) { - i->getSrc(0)->reg.file = FILE_MEMORY_CONST; - i->getSrc(0)->reg.fileIndex = 0; - } else - if (prog->getType() == Program::TYPE_GEOMETRY && - i->src(0).isIndirect(0)) { - // XXX: this assumes vec4 units - Value *ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(), - i->getIndirect(0, 0), bld.mkImm(4)); - i->setIndirect(0, 0, ptr); - i->op = OP_VFETCH; - } else { - i->op = OP_VFETCH; - assert(prog->getType() != Program::TYPE_FRAGMENT); // INTERP - } - } else if (i->src(0).getFile() == FILE_MEMORY_CONST) { - if (i->src(0).isIndirect(1)) { - Value *ptr; - if (i->src(0).isIndirect(0)) - ptr = bld.mkOp3v(OP_INSBF, TYPE_U32, bld.getSSA(), - i->getIndirect(0, 1), bld.mkImm(0x1010), - i->getIndirect(0, 0)); - else - ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(), - i->getIndirect(0, 1), bld.mkImm(16)); - i->setIndirect(0, 1, NULL); - i->setIndirect(0, 0, ptr); - i->subOp = NV50_IR_SUBOP_LDC_IS; - } - } - break; - case OP_ATOM: - { - const bool cctl = i->src(0).getFile() == FILE_MEMORY_GLOBAL; - handleATOM(i); - handleCasExch(i, cctl); - } - break; - case OP_SULDB: - case OP_SULDP: - case OP_SUSTB: - case OP_SUSTP: - case OP_SUREDB: - case OP_SUREDP: - handleSurfaceOpNVE4(i->asTex()); - break; case OP_DFDX: case OP_DFDY: - handleDFDX(i); - break; + return handleDFDX(i); case OP_POPCNT: - handlePOPCNT(i); - break; + return handlePOPCNT(i); default: - break; + return NVC0LoweringPass::visit(i); } - return true; } } // namespace nv50_ir diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp index c3c302da5c8..b1f406585a9 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp @@ -224,7 +224,7 @@ NVC0LegalizePostRA::findFirstUses( const Instruction *texi, const Instruction *insn, std::list<TexUse> &uses, - std::tr1::unordered_set<const Instruction *>& visited) + unordered_set<const Instruction *>& visited) { for (int d = 0; insn->defExists(d); ++d) { Value *v = insn->getDef(d); @@ -323,7 +323,7 @@ NVC0LegalizePostRA::insertTextureBarriers(Function *fn) if (!uses) return false; for (size_t i = 0; i < texes.size(); ++i) { - std::tr1::unordered_set<const Instruction *> visited; + unordered_set<const Instruction *> visited; findFirstUses(texes[i], texes[i], uses[i], visited); } diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.h b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.h index 260e101a1fb..2ce52e5c4f7 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.h +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.h @@ -20,8 +20,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include <tr1/unordered_set> - #include "codegen/nv50_ir.h" #include "codegen/nv50_ir_build_util.h" @@ -73,7 +71,7 @@ private: inline bool insnDominatedBy(const Instruction *, const Instruction *) const; void findFirstUses(const Instruction *tex, const Instruction *def, std::list<TexUse>&, - std::tr1::unordered_set<const Instruction *>&); + unordered_set<const Instruction *>&); void findOverwritingDefs(const Instruction *tex, Instruction *insn, const BasicBlock *term, std::list<TexUse>&); @@ -111,10 +109,11 @@ protected: void checkPredicate(Instruction *); + virtual bool visit(Instruction *); + private: virtual bool visit(Function *); virtual bool visit(BasicBlock *); - virtual bool visit(Instruction *); void readTessCoord(LValue *dst, int c); diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_peephole.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_peephole.cpp index cea96dcdfc5..b01ef4128cd 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_peephole.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_peephole.cpp @@ -1023,27 +1023,53 @@ ConstantFolding::opnd(Instruction *i, ImmediateValue &imm0, int s) case OP_AND: { - CmpInstruction *cmp = i->getSrc(t)->getInsn()->asCmp(); - if (!cmp || cmp->op == OP_SLCT || cmp->getDef(0)->refCount() > 1) - return; - if (!prog->getTarget()->isOpSupported(cmp->op, TYPE_F32)) - return; - if (imm0.reg.data.f32 != 1.0) - return; - if (i->getSrc(t)->getInsn()->dType != TYPE_U32) - return; + Instruction *src = i->getSrc(t)->getInsn(); + ImmediateValue imm1; + if (imm0.reg.data.u32 == 0) { + i->op = OP_MOV; + i->setSrc(0, new_ImmediateValue(prog, 0u)); + i->src(0).mod = Modifier(0); + i->setSrc(1, NULL); + } else if (imm0.reg.data.u32 == ~0U) { + i->op = i->src(t).mod.getOp(); + if (t) { + i->setSrc(0, i->getSrc(t)); + i->src(0).mod = i->src(t).mod; + } + i->setSrc(1, NULL); + } else if (src->asCmp()) { + CmpInstruction *cmp = src->asCmp(); + if (!cmp || cmp->op == OP_SLCT || cmp->getDef(0)->refCount() > 1) + return; + if (!prog->getTarget()->isOpSupported(cmp->op, TYPE_F32)) + return; + if (imm0.reg.data.f32 != 1.0) + return; + if (cmp->dType != TYPE_U32) + return; - i->getSrc(t)->getInsn()->dType = TYPE_F32; - if (i->src(t).mod != Modifier(0)) { - assert(i->src(t).mod == Modifier(NV50_IR_MOD_NOT)); - i->src(t).mod = Modifier(0); - cmp->setCond = inverseCondCode(cmp->setCond); - } - i->op = OP_MOV; - i->setSrc(s, NULL); - if (t) { - i->setSrc(0, i->getSrc(t)); - i->setSrc(t, NULL); + cmp->dType = TYPE_F32; + if (i->src(t).mod != Modifier(0)) { + assert(i->src(t).mod == Modifier(NV50_IR_MOD_NOT)); + i->src(t).mod = Modifier(0); + cmp->setCond = inverseCondCode(cmp->setCond); + } + i->op = OP_MOV; + i->setSrc(s, NULL); + if (t) { + i->setSrc(0, i->getSrc(t)); + i->setSrc(t, NULL); + } + } else if (prog->getTarget()->isOpSupported(OP_EXTBF, TYPE_U32) && + src->op == OP_SHR && + src->src(1).getImmediate(imm1) && + i->src(t).mod == Modifier(0) && + util_is_power_of_two(imm0.reg.data.u32 + 1)) { + // low byte = offset, high byte = width + uint32_t ext = (util_last_bit(imm0.reg.data.u32) << 8) | imm1.reg.data.u32; + i->op = OP_EXTBF; + i->setSrc(0, src->getSrc(0)); + i->setSrc(1, new_ImmediateValue(prog, ext)); } } break; @@ -1106,6 +1132,84 @@ ConstantFolding::opnd(Instruction *i, ImmediateValue &imm0, int s) i->op = OP_MOV; break; } + case OP_CVT: { + Storage res; + + // TODO: handle 64-bit values properly + if (typeSizeof(i->dType) == 8 || typeSizeof(i->sType) == 8) + return; + + // TODO: handle single byte/word extractions + if (i->subOp) + return; + + bld.setPosition(i, true); /* make sure bld is init'ed */ + +#define CASE(type, dst, fmin, fmax, imin, imax, umin, umax) \ + case type: \ + switch (i->sType) { \ + case TYPE_F32: \ + res.data.dst = util_iround(i->saturate ? \ + CLAMP(imm0.reg.data.f32, fmin, fmax) : \ + imm0.reg.data.f32); \ + break; \ + case TYPE_S32: \ + res.data.dst = i->saturate ? \ + CLAMP(imm0.reg.data.s32, imin, imax) : \ + imm0.reg.data.s32; \ + break; \ + case TYPE_U32: \ + res.data.dst = i->saturate ? \ + CLAMP(imm0.reg.data.u32, umin, umax) : \ + imm0.reg.data.u32; \ + break; \ + case TYPE_S16: \ + res.data.dst = i->saturate ? \ + CLAMP(imm0.reg.data.s16, imin, imax) : \ + imm0.reg.data.s16; \ + break; \ + case TYPE_U16: \ + res.data.dst = i->saturate ? \ + CLAMP(imm0.reg.data.u16, umin, umax) : \ + imm0.reg.data.u16; \ + break; \ + default: return; \ + } \ + i->setSrc(0, bld.mkImm(res.data.dst)); \ + break + + switch(i->dType) { + CASE(TYPE_U16, u16, 0, UINT16_MAX, 0, UINT16_MAX, 0, UINT16_MAX); + CASE(TYPE_S16, s16, INT16_MIN, INT16_MAX, INT16_MIN, INT16_MAX, 0, INT16_MAX); + CASE(TYPE_U32, u32, 0, UINT32_MAX, 0, INT32_MAX, 0, UINT32_MAX); + CASE(TYPE_S32, s32, INT32_MIN, INT32_MAX, INT32_MIN, INT32_MAX, 0, INT32_MAX); + case TYPE_F32: + switch (i->sType) { + case TYPE_F32: + res.data.f32 = i->saturate ? + CLAMP(imm0.reg.data.f32, 0.0f, 1.0f) : + imm0.reg.data.f32; + break; + case TYPE_U16: res.data.f32 = (float) imm0.reg.data.u16; break; + case TYPE_U32: res.data.f32 = (float) imm0.reg.data.u32; break; + case TYPE_S16: res.data.f32 = (float) imm0.reg.data.s16; break; + case TYPE_S32: res.data.f32 = (float) imm0.reg.data.s32; break; + default: + return; + } + i->setSrc(0, bld.mkImm(res.data.f32)); + break; + default: + return; + } +#undef CASE + + i->setType(i->dType); /* Remove i->sType, which we don't need anymore */ + i->op = OP_MOV; + i->saturate = 0; + i->src(0).mod = Modifier(0); /* Clear the already applied modifier */ + break; + } default: return; } @@ -1212,7 +1316,8 @@ private: void handleRCP(Instruction *); void handleSLCT(Instruction *); void handleLOGOP(Instruction *); - void handleCVT(Instruction *); + void handleCVT_NEG(Instruction *); + void handleCVT_EXTBF(Instruction *); void handleSUCLAMP(Instruction *); BuildUtil bld; @@ -1463,12 +1568,12 @@ AlgebraicOpt::handleLOGOP(Instruction *logop) // nv50: // F2I(NEG(I2F(ABS(SET)))) void -AlgebraicOpt::handleCVT(Instruction *cvt) +AlgebraicOpt::handleCVT_NEG(Instruction *cvt) { + Instruction *insn = cvt->getSrc(0)->getInsn(); if (cvt->sType != TYPE_F32 || cvt->dType != TYPE_S32 || cvt->src(0).mod != Modifier(0)) return; - Instruction *insn = cvt->getSrc(0)->getInsn(); if (!insn || insn->op != OP_NEG || insn->dType != TYPE_F32) return; if (insn->src(0).mod != Modifier(0)) @@ -1498,6 +1603,104 @@ AlgebraicOpt::handleCVT(Instruction *cvt) delete_Instruction(prog, cvt); } +// Some shaders extract packed bytes out of words and convert them to +// e.g. float. The Fermi+ CVT instruction can extract those directly, as can +// nv50 for word sizes. +// +// CVT(EXTBF(x, byte/word)) +// CVT(AND(bytemask, x)) +// CVT(AND(bytemask, SHR(x, 8/16/24))) +// CVT(SHR(x, 16/24)) +void +AlgebraicOpt::handleCVT_EXTBF(Instruction *cvt) +{ + Instruction *insn = cvt->getSrc(0)->getInsn(); + ImmediateValue imm; + Value *arg = NULL; + unsigned width, offset; + if ((cvt->sType != TYPE_U32 && cvt->sType != TYPE_S32) || !insn) + return; + if (insn->op == OP_EXTBF && insn->src(1).getImmediate(imm)) { + width = (imm.reg.data.u32 >> 8) & 0xff; + offset = imm.reg.data.u32 & 0xff; + arg = insn->getSrc(0); + + if (width != 8 && width != 16) + return; + if (width == 8 && offset & 0x7) + return; + if (width == 16 && offset & 0xf) + return; + } else if (insn->op == OP_AND) { + int s; + if (insn->src(0).getImmediate(imm)) + s = 0; + else if (insn->src(1).getImmediate(imm)) + s = 1; + else + return; + + if (imm.reg.data.u32 == 0xff) + width = 8; + else if (imm.reg.data.u32 == 0xffff) + width = 16; + else + return; + + arg = insn->getSrc(!s); + Instruction *shift = arg->getInsn(); + offset = 0; + if (shift && shift->op == OP_SHR && + shift->sType == cvt->sType && + shift->src(1).getImmediate(imm) && + ((width == 8 && (imm.reg.data.u32 & 0x7) == 0) || + (width == 16 && (imm.reg.data.u32 & 0xf) == 0))) { + arg = shift->getSrc(0); + offset = imm.reg.data.u32; + } + } else if (insn->op == OP_SHR && + insn->sType == cvt->sType && + insn->src(1).getImmediate(imm)) { + arg = insn->getSrc(0); + if (imm.reg.data.u32 == 24) { + width = 8; + offset = 24; + } else if (imm.reg.data.u32 == 16) { + width = 16; + offset = 16; + } else { + return; + } + } + + if (!arg) + return; + + // Irrespective of what came earlier, we can undo a shift on the argument + // by adjusting the offset. + Instruction *shift = arg->getInsn(); + if (shift && shift->op == OP_SHL && + shift->src(1).getImmediate(imm) && + ((width == 8 && (imm.reg.data.u32 & 0x7) == 0) || + (width == 16 && (imm.reg.data.u32 & 0xf) == 0)) && + imm.reg.data.u32 <= offset) { + arg = shift->getSrc(0); + offset -= imm.reg.data.u32; + } + + // The unpackSnorm lowering still leaves a few shifts behind, but it's too + // annoying to detect them. + + if (width == 8) { + cvt->sType = cvt->sType == TYPE_U32 ? TYPE_U8 : TYPE_S8; + } else { + assert(width == 16); + cvt->sType = cvt->sType == TYPE_U32 ? TYPE_U16 : TYPE_S16; + } + cvt->setSrc(0, arg); + cvt->subOp = offset >> 3; +} + // SUCLAMP dst, (ADD b imm), k, 0 -> SUCLAMP dst, b, k, imm (if imm fits s6) void AlgebraicOpt::handleSUCLAMP(Instruction *insn) @@ -1568,7 +1771,9 @@ AlgebraicOpt::visit(BasicBlock *bb) handleLOGOP(i); break; case OP_CVT: - handleCVT(i); + handleCVT_NEG(i); + if (prog->getTarget()->isOpSupported(OP_EXTBF, TYPE_U32)) + handleCVT_EXTBF(i); break; case OP_SUCLAMP: handleSUCLAMP(i); diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp index 78bc97f4397..0cd21cf47f5 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp @@ -25,7 +25,6 @@ #include <stack> #include <limits> -#include <tr1/unordered_set> namespace nv50_ir { @@ -1551,7 +1550,7 @@ SpillCodeInserter::run(const std::list<ValuePair>& lst) // Keep track of which instructions to delete later. Deleting them // inside the loop is unsafe since a single instruction may have // multiple destinations that all need to be spilled (like OP_SPLIT). - std::tr1::unordered_set<Instruction *> to_del; + unordered_set<Instruction *> to_del; for (Value::DefIterator d = lval->defs.begin(); d != lval->defs.end(); ++d) { @@ -1593,7 +1592,7 @@ SpillCodeInserter::run(const std::list<ValuePair>& lst) } } - for (std::tr1::unordered_set<Instruction *>::const_iterator it = to_del.begin(); + for (unordered_set<Instruction *>::const_iterator it = to_del.begin(); it != to_del.end(); ++it) delete_Instruction(func->getProgram(), *it); } diff --git a/src/gallium/drivers/nouveau/codegen/unordered_set.h b/src/gallium/drivers/nouveau/codegen/unordered_set.h new file mode 100644 index 00000000000..8ef6d462ffd --- /dev/null +++ b/src/gallium/drivers/nouveau/codegen/unordered_set.h @@ -0,0 +1,48 @@ +#ifndef __NV50_UNORDERED_SET_H__ +#define __NV50_UNORDERED_SET_H__ + +#if (__cplusplus >= 201103L) || defined(ANDROID) +#include <unordered_set> +#else +#include <tr1/unordered_set> +#endif + +namespace nv50_ir { + +#if __cplusplus >= 201103L +using std::unordered_set; +#elif !defined(ANDROID) +using std::tr1::unordered_set; +#else // Android release before lollipop +using std::isfinite; +typedef std::tr1::unordered_set<void *> voidptr_unordered_set; + +template <typename V> +class unordered_set : public voidptr_unordered_set { + public: + typedef voidptr_unordered_set _base; + typedef _base::iterator _biterator; + typedef _base::const_iterator const_biterator; + + class iterator : public _biterator { + public: + iterator(const _biterator & i) : _biterator(i) {} + V operator*() const { return reinterpret_cast<V>(*_biterator(*this)); } + }; + class const_iterator : public const_biterator { + public: + const_iterator(const iterator & i) : const_biterator(i) {} + const_iterator(const const_biterator & i) : const_biterator(i) {} + const V operator*() const { return reinterpret_cast<const V>(*const_biterator(*this)); } + }; + + iterator begin() { return _base::begin(); } + iterator end() { return _base::end(); } + const_iterator begin() const { return _base::begin(); } + const_iterator end() const { return _base::end(); } +}; +#endif + +} // namespace nv50_ir + +#endif // __NV50_UNORDERED_SET_H__ diff --git a/src/gallium/drivers/nouveau/nouveau_compiler.c b/src/gallium/drivers/nouveau/nouveau_compiler.c index 86604984220..495450b317a 100644 --- a/src/gallium/drivers/nouveau/nouveau_compiler.c +++ b/src/gallium/drivers/nouveau/nouveau_compiler.c @@ -190,6 +190,10 @@ main(int argc, char *argv[]) type = PIPE_SHADER_GEOMETRY; else if (!strncmp(text, "COMP", 4)) type = PIPE_SHADER_COMPUTE; + else if (!strncmp(text, "TESS_CTRL", 9)) + type = PIPE_SHADER_TESS_CTRL; + else if (!strncmp(text, "TESS_EVAL", 9)) + type = PIPE_SHADER_TESS_EVAL; else { _debug_printf("Unrecognized TGSI header\n"); return 1; diff --git a/src/gallium/drivers/nouveau/nv50/nv50_state.c b/src/gallium/drivers/nouveau/nv50/nv50_state.c index 9505a0b4085..410e6311e60 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_state.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_state.c @@ -117,7 +117,6 @@ nv50_blend_state_create(struct pipe_context *pipe, struct nv50_blend_stateobj *so = CALLOC_STRUCT(nv50_blend_stateobj); int i; bool emit_common_func = cso->rt[0].blend_enable; - uint32_t ms; if (nv50_context(pipe)->screen->tesla->oclass >= NVA3_3D_CLASS) { SB_BEGIN_3D(so, BLEND_INDEPENDENT, 1); @@ -189,15 +188,6 @@ nv50_blend_state_create(struct pipe_context *pipe, SB_DATA (so, nv50_colormask(cso->rt[0].colormask)); } - ms = 0; - if (cso->alpha_to_coverage) - ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_COVERAGE; - if (cso->alpha_to_one) - ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_ONE; - - SB_BEGIN_3D(so, MULTISAMPLE_CTRL, 1); - SB_DATA (so, ms); - assert(so->size <= (sizeof(so->state) / sizeof(so->state[0]))); return so; } diff --git a/src/gallium/drivers/nouveau/nv50/nv50_state_validate.c b/src/gallium/drivers/nouveau/nv50/nv50_state_validate.c index 985603df5fa..b304a177b50 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_state_validate.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_state_validate.c @@ -1,4 +1,6 @@ +#include "util/u_format.h" + #include "nv50/nv50_context.h" #include "nv50/nv50_defs.xml.h" @@ -314,6 +316,25 @@ nv50_validate_derived_2(struct nv50_context *nv50) } static void +nv50_validate_derived_3(struct nv50_context *nv50) +{ + struct nouveau_pushbuf *push = nv50->base.pushbuf; + struct pipe_framebuffer_state *fb = &nv50->framebuffer; + uint32_t ms = 0; + + if ((!fb->nr_cbufs || !fb->cbufs[0] || + !util_format_is_pure_integer(fb->cbufs[0]->format)) && nv50->blend) { + if (nv50->blend->pipe.alpha_to_coverage) + ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_COVERAGE; + if (nv50->blend->pipe.alpha_to_one) + ms |= NV50_3D_MULTISAMPLE_CTRL_ALPHA_TO_ONE; + } + + BEGIN_NV04(push, NV50_3D(MULTISAMPLE_CTRL), 1); + PUSH_DATA (push, ms); +} + +static void nv50_validate_clip(struct nv50_context *nv50) { struct nouveau_pushbuf *push = nv50->base.pushbuf; @@ -474,6 +495,7 @@ static struct state_validate { { nv50_validate_derived_rs, NV50_NEW_FRAGPROG | NV50_NEW_RASTERIZER | NV50_NEW_VERTPROG | NV50_NEW_GMTYPROG }, { nv50_validate_derived_2, NV50_NEW_ZSA | NV50_NEW_FRAMEBUFFER }, + { nv50_validate_derived_3, NV50_NEW_BLEND | NV50_NEW_FRAMEBUFFER }, { nv50_validate_clip, NV50_NEW_CLIP | NV50_NEW_RASTERIZER | NV50_NEW_VERTPROG | NV50_NEW_GMTYPROG }, { nv50_constbufs_validate, NV50_NEW_CONSTBUF }, diff --git a/src/gallium/drivers/nouveau/nv50/nv50_stateobj.h b/src/gallium/drivers/nouveau/nv50/nv50_stateobj.h index cf75d1eb11b..4b1d00c7155 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_stateobj.h +++ b/src/gallium/drivers/nouveau/nv50/nv50_stateobj.h @@ -19,7 +19,7 @@ struct nv50_blend_stateobj { struct pipe_blend_state pipe; int size; - uint32_t state[84]; // TODO: allocate less if !independent_blend_enable + uint32_t state[82]; // TODO: allocate less if !independent_blend_enable }; struct nv50_rasterizer_stateobj { diff --git a/src/gallium/drivers/nouveau/nv50/nv50_surface.c b/src/gallium/drivers/nouveau/nv50/nv50_surface.c index b1ae01692cb..64348b3c378 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_surface.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_surface.c @@ -68,6 +68,10 @@ nv50_2d_format(enum pipe_format format, bool dst, bool dst_src_equal) return NV50_SURFACE_FORMAT_R16_UNORM; case 4: return NV50_SURFACE_FORMAT_BGRA8_UNORM; + case 8: + return NV50_SURFACE_FORMAT_RGBA16_FLOAT; + case 16: + return NV50_SURFACE_FORMAT_RGBA32_FLOAT; default: return 0; } @@ -1003,6 +1007,8 @@ nv50_blitctx_prepare_state(struct nv50_blitctx *blit) /* zsa state */ BEGIN_NV04(push, NV50_3D(DEPTH_TEST_ENABLE), 1); PUSH_DATA (push, 0); + BEGIN_NV04(push, NV50_3D(DEPTH_BOUNDS_EN), 1); + PUSH_DATA (push, 0); BEGIN_NV04(push, NV50_3D(STENCIL_ENABLE), 1); PUSH_DATA (push, 0); BEGIN_NV04(push, NV50_3D(ALPHA_TEST_ENABLE), 1); @@ -1387,18 +1393,24 @@ nv50_blit_eng2d(struct nv50_context *nv50, const struct pipe_blit_info *info) PUSH_DATA (push, info->dst.box.z + i); } else { const unsigned z = info->dst.box.z + i; + const uint64_t address = dst->base.address + + dst->level[info->dst.level].offset + + z * dst->layer_stride; BEGIN_NV04(push, NV50_2D(DST_ADDRESS_HIGH), 2); - PUSH_DATAh(push, dst->base.address + z * dst->layer_stride); - PUSH_DATA (push, dst->base.address + z * dst->layer_stride); + PUSH_DATAh(push, address); + PUSH_DATA (push, address); } if (src->layout_3d) { /* not possible because of depth tiling */ assert(0); } else { const unsigned z = info->src.box.z + i; + const uint64_t address = src->base.address + + src->level[info->src.level].offset + + z * src->layer_stride; BEGIN_NV04(push, NV50_2D(SRC_ADDRESS_HIGH), 2); - PUSH_DATAh(push, src->base.address + z * src->layer_stride); - PUSH_DATA (push, src->base.address + z * src->layer_stride); + PUSH_DATAh(push, address); + PUSH_DATA (push, address); } BEGIN_NV04(push, NV50_2D(BLIT_SRC_Y_INT), 1); /* trigger */ PUSH_DATA (push, srcy >> 32); diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_context.c b/src/gallium/drivers/nouveau/nvc0/nvc0_context.c index 84f8db6a8ac..7a15a11f560 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_context.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_context.c @@ -132,6 +132,9 @@ nvc0_context_unreference_resources(struct nvc0_context *nvc0) pipe_resource_reference(res, NULL); } util_dynarray_fini(&nvc0->global_residents); + + if (nvc0->tcp_empty) + nvc0->base.pipe.delete_tcs_state(&nvc0->base.pipe, nvc0->tcp_empty); } static void @@ -306,13 +309,6 @@ nvc0_create(struct pipe_screen *pscreen, void *priv) pipe->memory_barrier = nvc0_memory_barrier; pipe->get_sample_position = nvc0_context_get_sample_position; - if (!screen->cur_ctx) { - nvc0->state = screen->save_state; - screen->cur_ctx = nvc0; - nouveau_pushbuf_bufctx(screen->base.pushbuf, nvc0->bufctx); - } - screen->base.pushbuf->kick_notify = nvc0_default_kick_notify; - nvc0_init_query_functions(nvc0); nvc0_init_surface_functions(nvc0); nvc0_init_state_functions(nvc0); @@ -326,6 +322,21 @@ nvc0_create(struct pipe_screen *pscreen, void *priv) /* shader builtin library is per-screen, but we need a context for m2mf */ nvc0_program_library_upload(nvc0); + nvc0_program_init_tcp_empty(nvc0); + if (!nvc0->tcp_empty) + goto out_err; + /* set the empty tctl prog on next draw in case one is never set */ + nvc0->dirty |= NVC0_NEW_TCTLPROG; + + /* now that there are no more opportunities for errors, set the current + * context if there isn't already one. + */ + if (!screen->cur_ctx) { + nvc0->state = screen->save_state; + screen->cur_ctx = nvc0; + nouveau_pushbuf_bufctx(screen->base.pushbuf, nvc0->bufctx); + } + screen->base.pushbuf->kick_notify = nvc0_default_kick_notify; /* add permanently resident buffers to bufctxts */ diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_context.h b/src/gallium/drivers/nouveau/nvc0/nvc0_context.h index f4499423a10..df1a891a43e 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_context.h +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_context.h @@ -128,6 +128,8 @@ struct nvc0_context { struct nvc0_program *fragprog; struct nvc0_program *compprog; + struct nvc0_program *tcp_empty; + struct nvc0_constbuf constbuf[6][NVC0_MAX_PIPE_CONSTBUFS]; uint16_t constbuf_dirty[6]; uint16_t constbuf_valid[6]; @@ -227,6 +229,7 @@ void nvc0_program_destroy(struct nvc0_context *, struct nvc0_program *); void nvc0_program_library_upload(struct nvc0_context *); uint32_t nvc0_program_symbol_offset(const struct nvc0_program *, uint32_t label); +void nvc0_program_init_tcp_empty(struct nvc0_context *); /* nvc0_query.c */ void nvc0_init_query_functions(struct nvc0_context *); diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_program.c b/src/gallium/drivers/nouveau/nvc0/nvc0_program.c index 507a2507fe3..12f1bb728d7 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_program.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_program.c @@ -22,6 +22,8 @@ #include "pipe/p_defines.h" +#include "tgsi/tgsi_ureg.h" + #include "nvc0/nvc0_context.h" #include "codegen/nv50_ir_driver.h" @@ -799,3 +801,18 @@ nvc0_program_symbol_offset(const struct nvc0_program *prog, uint32_t label) return prog->code_base + base + syms[i].offset; return prog->code_base; /* no symbols or symbol not found */ } + +void +nvc0_program_init_tcp_empty(struct nvc0_context *nvc0) +{ + struct ureg_program *ureg; + + ureg = ureg_create(TGSI_PROCESSOR_TESS_CTRL); + if (!ureg) + return; + + ureg_property(ureg, TGSI_PROPERTY_TCS_VERTICES_OUT, 1); + ureg_END(ureg); + + nvc0->tcp_empty = ureg_create_shader_and_destroy(ureg, &nvc0->base.pipe); +} diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_shader_state.c b/src/gallium/drivers/nouveau/nvc0/nvc0_shader_state.c index 8aa127adc0a..8f8ac2d34b9 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_shader_state.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_shader_state.c @@ -148,8 +148,13 @@ nvc0_tctlprog_validate(struct nvc0_context *nvc0) BEGIN_NVC0(push, NVC0_3D(SP_GPR_ALLOC(2)), 1); PUSH_DATA (push, tp->num_gprs); } else { - BEGIN_NVC0(push, NVC0_3D(SP_SELECT(2)), 1); + tp = nvc0->tcp_empty; + /* not a whole lot we can do to handle this failure */ + if (!nvc0_program_validate(nvc0, tp)) + assert(!"unable to validate empty tcp"); + BEGIN_NVC0(push, NVC0_3D(SP_SELECT(2)), 2); PUSH_DATA (push, 0x20); + PUSH_DATA (push, tp->code_base); } nvc0_program_update_context_state(nvc0, tp, 1); } diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_state.c b/src/gallium/drivers/nouveau/nvc0/nvc0_state.c index 2a33857d9df..ee29912eb40 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_state.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_state.c @@ -90,7 +90,6 @@ nvc0_blend_state_create(struct pipe_context *pipe, struct nvc0_blend_stateobj *so = CALLOC_STRUCT(nvc0_blend_stateobj); int i; int r; /* reference */ - uint32_t ms; uint8_t blend_en = 0; bool indep_masks = false; bool indep_funcs = false; @@ -176,15 +175,6 @@ nvc0_blend_state_create(struct pipe_context *pipe, } } - ms = 0; - if (cso->alpha_to_coverage) - ms |= NVC0_3D_MULTISAMPLE_CTRL_ALPHA_TO_COVERAGE; - if (cso->alpha_to_one) - ms |= NVC0_3D_MULTISAMPLE_CTRL_ALPHA_TO_ONE; - - SB_BEGIN_3D(so, MULTISAMPLE_CTRL, 1); - SB_DATA (so, ms); - assert(so->size <= (sizeof(so->state) / sizeof(so->state[0]))); return so; } @@ -234,7 +224,7 @@ nvc0_rasterizer_state_create(struct pipe_context *pipe, SB_IMMED_3D(so, MULTISAMPLE_ENABLE, cso->multisample); SB_IMMED_3D(so, LINE_SMOOTH_ENABLE, cso->line_smooth); - if (cso->line_smooth) + if (cso->line_smooth || cso->multisample) SB_BEGIN_3D(so, LINE_WIDTH_SMOOTH, 1); else SB_BEGIN_3D(so, LINE_WIDTH_ALIASED, 1); diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_state_validate.c b/src/gallium/drivers/nouveau/nvc0/nvc0_state_validate.c index ce1119c284d..47bd66d1e35 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_state_validate.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_state_validate.c @@ -1,4 +1,5 @@ +#include "util/u_format.h" #include "util/u_math.h" #include "nvc0/nvc0_context.h" @@ -555,6 +556,25 @@ nvc0_validate_derived_2(struct nvc0_context *nvc0) } static void +nvc0_validate_derived_3(struct nvc0_context *nvc0) +{ + struct nouveau_pushbuf *push = nvc0->base.pushbuf; + struct pipe_framebuffer_state *fb = &nvc0->framebuffer; + uint32_t ms = 0; + + if ((!fb->nr_cbufs || !fb->cbufs[0] || + !util_format_is_pure_integer(fb->cbufs[0]->format)) && nvc0->blend) { + if (nvc0->blend->pipe.alpha_to_coverage) + ms |= NVC0_3D_MULTISAMPLE_CTRL_ALPHA_TO_COVERAGE; + if (nvc0->blend->pipe.alpha_to_one) + ms |= NVC0_3D_MULTISAMPLE_CTRL_ALPHA_TO_ONE; + } + + BEGIN_NVC0(push, NVC0_3D(MULTISAMPLE_CTRL), 1); + PUSH_DATA (push, ms); +} + +static void nvc0_validate_tess_state(struct nvc0_context *nvc0) { struct nouveau_pushbuf *push = nvc0->base.pushbuf; @@ -628,6 +648,7 @@ static struct state_validate { { nvc0_validate_derived_1, NVC0_NEW_FRAGPROG | NVC0_NEW_ZSA | NVC0_NEW_RASTERIZER }, { nvc0_validate_derived_2, NVC0_NEW_ZSA | NVC0_NEW_FRAMEBUFFER }, + { nvc0_validate_derived_3, NVC0_NEW_BLEND | NVC0_NEW_FRAMEBUFFER }, { nvc0_validate_clip, NVC0_NEW_CLIP | NVC0_NEW_RASTERIZER | NVC0_NEW_VERTPROG | NVC0_NEW_TEVLPROG | diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_stateobj.h b/src/gallium/drivers/nouveau/nvc0/nvc0_stateobj.h index 18fcc12dea3..8bc33c6a0e0 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_stateobj.h +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_stateobj.h @@ -17,7 +17,7 @@ struct nvc0_blend_stateobj { struct pipe_blend_state pipe; int size; - uint32_t state[72]; + uint32_t state[70]; }; struct nvc0_rasterizer_stateobj { diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c b/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c index 51a6f93f891..dbdf292c862 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_surface.c @@ -887,6 +887,7 @@ nvc0_blitctx_prepare_state(struct nvc0_blitctx *blit) /* zsa state */ IMMED_NVC0(push, NVC0_3D(DEPTH_TEST_ENABLE), 0); + IMMED_NVC0(push, NVC0_3D(DEPTH_BOUNDS_EN), 0); IMMED_NVC0(push, NVC0_3D(STENCIL_ENABLE), 0); IMMED_NVC0(push, NVC0_3D(ALPHA_TEST_ENABLE), 0); @@ -1336,18 +1337,24 @@ nvc0_blit_eng2d(struct nvc0_context *nvc0, const struct pipe_blit_info *info) PUSH_DATA (push, info->dst.box.z + i); } else { const unsigned z = info->dst.box.z + i; + const uint64_t address = dst->base.address + + dst->level[info->dst.level].offset + + z * dst->layer_stride; BEGIN_NVC0(push, NVC0_2D(DST_ADDRESS_HIGH), 2); - PUSH_DATAh(push, dst->base.address + z * dst->layer_stride); - PUSH_DATA (push, dst->base.address + z * dst->layer_stride); + PUSH_DATAh(push, address); + PUSH_DATA (push, address); } if (src->layout_3d) { /* not possible because of depth tiling */ assert(0); } else { const unsigned z = info->src.box.z + i; + const uint64_t address = src->base.address + + src->level[info->src.level].offset + + z * src->layer_stride; BEGIN_NVC0(push, NVC0_2D(SRC_ADDRESS_HIGH), 2); - PUSH_DATAh(push, src->base.address + z * src->layer_stride); - PUSH_DATA (push, src->base.address + z * src->layer_stride); + PUSH_DATAh(push, address); + PUSH_DATA (push, address); } BEGIN_NVC0(push, NVC0_2D(BLIT_SRC_Y_INT), 1); /* trigger */ PUSH_DATA (push, srcy >> 32); diff --git a/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c b/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c index 14f93fba986..e8f4087cbc4 100644 --- a/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c +++ b/src/gallium/drivers/r300/compiler/radeon_pair_regalloc.c @@ -693,7 +693,8 @@ void rc_init_regalloc_state(struct rc_regalloc_state *s) }; /* Allocate the main ra data structure */ - s->regs = ra_alloc_reg_set(NULL, R500_PFS_NUM_TEMP_REGS * RC_MASK_XYZW); + s->regs = ra_alloc_reg_set(NULL, R500_PFS_NUM_TEMP_REGS * RC_MASK_XYZW, + true); /* Create the register classes */ for (i = 0; i < RC_REG_CLASS_COUNT; i++) { diff --git a/src/gallium/drivers/r300/r300_blit.c b/src/gallium/drivers/r300/r300_blit.c index 6ea8f24cc14..b8cc316c2ac 100644 --- a/src/gallium/drivers/r300/r300_blit.c +++ b/src/gallium/drivers/r300/r300_blit.c @@ -667,7 +667,8 @@ static void r300_resource_copy_region(struct pipe_context *pipe, r300_blitter_begin(r300, R300_COPY); util_blitter_blit_generic(r300->blitter, dst_view, &dstbox, src_view, src_box, src_width0, src_height0, - PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL); + PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL, + FALSE); r300_blitter_end(r300); pipe_surface_reference(&dst_view, NULL); diff --git a/src/gallium/drivers/r600/r600_blit.c b/src/gallium/drivers/r600/r600_blit.c index b0002c3b50f..22a0950a491 100644 --- a/src/gallium/drivers/r600/r600_blit.c +++ b/src/gallium/drivers/r600/r600_blit.c @@ -732,7 +732,8 @@ void r600_resource_copy_region(struct pipe_context *ctx, r600_blitter_begin(ctx, R600_COPY_TEXTURE); util_blitter_blit_generic(rctx->blitter, dst_view, &dstbox, src_view, src_box, src_width0, src_height0, - PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL); + PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL, + FALSE); r600_blitter_end(ctx); pipe_surface_reference(&dst_view, NULL); diff --git a/src/gallium/drivers/r600/r600_isa.h b/src/gallium/drivers/r600/r600_isa.h index 381f06d5924..fdbe1c00d20 100644 --- a/src/gallium/drivers/r600/r600_isa.h +++ b/src/gallium/drivers/r600/r600_isa.h @@ -262,7 +262,7 @@ static const struct alu_op_info alu_op_table[] = { {"PRED_SETNE_PUSH_INT", 2, { 0x4D, 0x4D },{ AF_VS, AF_VS, AF_VS, AF_VS}, AF_PRED_PUSH | AF_CC_NE | AF_INT_CMP }, {"PRED_SETLT_PUSH_INT", 2, { 0x4E, 0x4E },{ AF_VS, AF_VS, AF_VS, AF_VS}, AF_PRED_PUSH | AF_CC_LT | AF_INT_CMP }, {"PRED_SETLE_PUSH_INT", 2, { 0x4F, 0x4F },{ AF_VS, AF_VS, AF_VS, AF_VS}, AF_PRED_PUSH | AF_CC_LE | AF_INT_CMP }, - {"FLT_TO_INT", 1, { 0x6B, 0x50 },{ AF_S, AF_S, AF_VS, AF_VS}, AF_INT_DST | AF_CVT }, + {"FLT_TO_INT", 1, { 0x6B, 0x50 },{ AF_S, AF_S, AF_V, AF_V}, AF_INT_DST | AF_CVT }, {"BFREV_INT", 1, { -1, 0x51 },{ 0, 0, AF_VS, AF_VS}, AF_INT_DST }, {"ADDC_UINT", 2, { -1, 0x52 },{ 0, 0, AF_VS, AF_VS}, AF_UINT_DST }, {"SUBB_UINT", 2, { -1, 0x53 },{ 0, 0, AF_VS, AF_VS}, AF_UINT_DST }, diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h index 9b66105641a..384ba800a79 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -90,7 +90,7 @@ struct r600_context; struct r600_bytecode; -struct r600_shader_key; +union r600_shader_key; /* This is an atom containing GPU commands that never change. * This is supposed to be copied directly into the CS. */ @@ -643,7 +643,7 @@ void r600_resource_copy_region(struct pipe_context *ctx, /* r600_shader.c */ int r600_pipe_shader_create(struct pipe_context *ctx, struct r600_pipe_shader *shader, - struct r600_shader_key key); + union r600_shader_key key); void r600_pipe_shader_destroy(struct pipe_context *ctx, struct r600_pipe_shader *shader); diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c index 8d1f95abddc..4c4b6005981 100644 --- a/src/gallium/drivers/r600/r600_shader.c +++ b/src/gallium/drivers/r600/r600_shader.c @@ -62,7 +62,7 @@ The compiler must issue the source argument to slots z, y, and x static int r600_shader_from_tgsi(struct r600_context *rctx, struct r600_pipe_shader *pipeshader, - struct r600_shader_key key); + union r600_shader_key key); static void r600_add_gpr_array(struct r600_shader *ps, int start_gpr, @@ -133,7 +133,7 @@ static int store_shader(struct pipe_context *ctx, int r600_pipe_shader_create(struct pipe_context *ctx, struct r600_pipe_shader *shader, - struct r600_shader_key key) + union r600_shader_key key) { struct r600_context *rctx = (struct r600_context *)ctx; struct r600_pipe_shader_selector *sel = shader->selector; @@ -141,7 +141,7 @@ int r600_pipe_shader_create(struct pipe_context *ctx, bool dump = r600_can_dump_shader(&rctx->screen->b, sel->tokens); unsigned use_sb = !(rctx->screen->b.debug_flags & DBG_NO_SB); unsigned sb_disasm = use_sb || (rctx->screen->b.debug_flags & DBG_SB_DISASM); - unsigned export_shader = key.vs_as_es; + unsigned export_shader = key.vs.as_es; shader->shader.bc.isa = rctx->isa; @@ -1802,7 +1802,7 @@ static int emit_gs_ring_writes(struct r600_shader_ctx *ctx, bool ind) static int r600_shader_from_tgsi(struct r600_context *rctx, struct r600_pipe_shader *pipeshader, - struct r600_shader_key key) + union r600_shader_key key) { struct r600_screen *rscreen = rctx->screen; struct r600_shader *shader = &pipeshader->shader; @@ -1816,7 +1816,7 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, unsigned opcode; int i, j, k, r = 0; int next_param_base = 0, next_clip_base; - int max_color_exports = MAX2(key.nr_cbufs, 1); + int max_color_exports = MAX2(key.ps.nr_cbufs, 1); /* Declarations used by llvm code */ bool use_llvm = false; bool indirect_gprs; @@ -1830,8 +1830,8 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, ctx.shader = shader; ctx.native_integers = true; - shader->vs_as_gs_a = key.vs_as_gs_a; - shader->vs_as_es = key.vs_as_es; + shader->vs_as_gs_a = key.vs.as_gs_a; + shader->vs_as_es = key.vs.as_es; r600_bytecode_init(ctx.bc, rscreen->b.chip_class, rscreen->b.family, rscreen->has_compressed_msaa_texturing); @@ -1844,9 +1844,9 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, shader->processor_type = ctx.type; ctx.bc->type = shader->processor_type; - ring_outputs = key.vs_as_es || (ctx.type == TGSI_PROCESSOR_GEOMETRY); + ring_outputs = key.vs.as_es || (ctx.type == TGSI_PROCESSOR_GEOMETRY); - if (key.vs_as_es) { + if (key.vs.as_es) { ctx.gs_for_vs = &rctx->gs_shader->current->shader; } else { ctx.gs_for_vs = NULL; @@ -1866,7 +1866,7 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, shader->nr_ps_color_exports = 0; shader->nr_ps_max_color_exports = 0; - shader->two_side = key.color_two_side; + shader->two_side = key.ps.color_two_side; /* register allocations */ /* Values [0,127] correspond to GPR[0..127]. @@ -1970,7 +1970,7 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, shader->fs_write_all = FALSE; if (shader->vs_as_gs_a) - vs_add_primid_output(&ctx, key.vs_prim_id_out); + vs_add_primid_output(&ctx, key.vs.prim_id_out); while (!tgsi_parse_end_of_tokens(&ctx.parse)) { tgsi_parse_token(&ctx.parse); @@ -2091,7 +2091,7 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, radeon_llvm_ctx.chip_class = ctx.bc->chip_class; radeon_llvm_ctx.fs_color_all = shader->fs_write_all && (rscreen->b.chip_class >= EVERGREEN); radeon_llvm_ctx.stream_outputs = &so; - radeon_llvm_ctx.alpha_to_one = key.alpha_to_one; + radeon_llvm_ctx.alpha_to_one = key.ps.alpha_to_one; radeon_llvm_ctx.has_compressed_msaa_texturing = ctx.bc->has_compressed_msaa_texturing; mod = r600_tgsi_llvm(&radeon_llvm_ctx, tokens); @@ -2270,7 +2270,7 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, convert_edgeflag_to_int(&ctx); if (ring_outputs) { - if (key.vs_as_es) + if (key.vs.as_es) emit_gs_ring_writes(&ctx, FALSE); } else { /* Export output */ @@ -2386,7 +2386,7 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, j--; continue; } - output[j].swizzle_w = key.alpha_to_one ? 5 : 3; + output[j].swizzle_w = key.ps.alpha_to_one ? 5 : 3; output[j].array_base = shader->output[i].sid; output[j].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; shader->nr_ps_color_exports++; @@ -2399,7 +2399,7 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, output[j].swizzle_x = 0; output[j].swizzle_y = 1; output[j].swizzle_z = 2; - output[j].swizzle_w = key.alpha_to_one ? 5 : 3; + output[j].swizzle_w = key.ps.alpha_to_one ? 5 : 3; output[j].burst_count = 1; output[j].array_base = k; output[j].op = CF_OP_EXPORT; @@ -6151,10 +6151,10 @@ static int tgsi_cmp(struct r600_shader_ctx *ctx) r = tgsi_make_src_for_op3(ctx, temp_regs[0], i, &alu.src[0], &ctx->src[0]); if (r) return r; - r = tgsi_make_src_for_op3(ctx, temp_regs[1], i, &alu.src[1], &ctx->src[2]); + r = tgsi_make_src_for_op3(ctx, temp_regs[2], i, &alu.src[1], &ctx->src[2]); if (r) return r; - r = tgsi_make_src_for_op3(ctx, temp_regs[2], i, &alu.src[2], &ctx->src[1]); + r = tgsi_make_src_for_op3(ctx, temp_regs[1], i, &alu.src[2], &ctx->src[1]); if (r) return r; tgsi_dst(ctx, &inst->Dst[0], i, &alu.dst); diff --git a/src/gallium/drivers/r600/r600_shader.h b/src/gallium/drivers/r600/r600_shader.h index 5d05c8153d7..927bac57673 100644 --- a/src/gallium/drivers/r600/r600_shader.h +++ b/src/gallium/drivers/r600/r600_shader.h @@ -95,13 +95,17 @@ struct r600_shader { struct r600_shader_array * arrays; }; -struct r600_shader_key { - unsigned color_two_side:1; - unsigned alpha_to_one:1; - unsigned nr_cbufs:4; - unsigned vs_as_es:1; - unsigned vs_as_gs_a:1; - unsigned vs_prim_id_out:8; +union r600_shader_key { + struct { + unsigned nr_cbufs:4; + unsigned color_two_side:1; + unsigned alpha_to_one:1; + } ps; + struct { + unsigned prim_id_out:8; + unsigned as_es:1; /* export shader */ + unsigned as_gs_a:1; + } vs; }; struct r600_shader_array { @@ -122,7 +126,7 @@ struct r600_pipe_shader { unsigned flatshade; unsigned pa_cl_vs_out_cntl; unsigned nr_ps_color_outputs; - struct r600_shader_key key; + union r600_shader_key key; unsigned db_shader_control; unsigned ps_depth_export; unsigned enabled_stream_buffers_mask; diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index aa4a8d0240f..a05dd8352c7 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -702,29 +702,39 @@ void r600_emit_viewport_state(struct r600_context *rctx, struct r600_atom *atom) } /* Compute the key for the hw shader variant */ -static inline struct r600_shader_key r600_shader_selector_key(struct pipe_context * ctx, +static inline union r600_shader_key r600_shader_selector_key(struct pipe_context * ctx, struct r600_pipe_shader_selector * sel) { struct r600_context *rctx = (struct r600_context *)ctx; - struct r600_shader_key key; + union r600_shader_key key; memset(&key, 0, sizeof(key)); - if (sel->type == PIPE_SHADER_FRAGMENT) { - key.color_two_side = rctx->rasterizer && rctx->rasterizer->two_side; - key.alpha_to_one = rctx->alpha_to_one && - rctx->rasterizer && rctx->rasterizer->multisample_enable && - !rctx->framebuffer.cb0_is_integer; - key.nr_cbufs = rctx->framebuffer.state.nr_cbufs; - /* Dual-source blending only makes sense with nr_cbufs == 1. */ - if (key.nr_cbufs == 1 && rctx->dual_src_blend) - key.nr_cbufs = 2; - } else if (sel->type == PIPE_SHADER_VERTEX) { - key.vs_as_es = (rctx->gs_shader != NULL); + switch (sel->type) { + case PIPE_SHADER_VERTEX: { + key.vs.as_es = (rctx->gs_shader != NULL); if (rctx->ps_shader->current->shader.gs_prim_id_input && !rctx->gs_shader) { - key.vs_as_gs_a = true; - key.vs_prim_id_out = rctx->ps_shader->current->shader.input[rctx->ps_shader->current->shader.ps_prim_id_input].spi_sid; + key.vs.as_gs_a = true; + key.vs.prim_id_out = rctx->ps_shader->current->shader.input[rctx->ps_shader->current->shader.ps_prim_id_input].spi_sid; } + break; + } + case PIPE_SHADER_GEOMETRY: + break; + case PIPE_SHADER_FRAGMENT: { + key.ps.color_two_side = rctx->rasterizer && rctx->rasterizer->two_side; + key.ps.alpha_to_one = rctx->alpha_to_one && + rctx->rasterizer && rctx->rasterizer->multisample_enable && + !rctx->framebuffer.cb0_is_integer; + key.ps.nr_cbufs = rctx->framebuffer.state.nr_cbufs; + /* Dual-source blending only makes sense with nr_cbufs == 1. */ + if (key.ps.nr_cbufs == 1 && rctx->dual_src_blend) + key.ps.nr_cbufs = 2; + break; } + default: + assert(0); + } + return key; } @@ -734,7 +744,7 @@ static int r600_shader_select(struct pipe_context *ctx, struct r600_pipe_shader_selector* sel, bool *dirty) { - struct r600_shader_key key; + union r600_shader_key key; struct r600_pipe_shader * shader = NULL; int r; diff --git a/src/gallium/drivers/radeon/radeon_uvd.c b/src/gallium/drivers/radeon/radeon_uvd.c index 16ee5410273..81f3f45db9f 100644 --- a/src/gallium/drivers/radeon/radeon_uvd.c +++ b/src/gallium/drivers/radeon/radeon_uvd.c @@ -209,8 +209,6 @@ static uint32_t profile2stream_type(struct ruvd_decoder *dec, unsigned family) static unsigned calc_ctx_size(struct ruvd_decoder *dec) { - unsigned width_in_mb, height_in_mb, ctx_size; - unsigned width = align(dec->base.width, VL_MACROBLOCK_WIDTH); unsigned height = align(dec->base.height, VL_MACROBLOCK_HEIGHT); @@ -223,8 +221,7 @@ static unsigned calc_ctx_size(struct ruvd_decoder *dec) width = align (width, 16); height = align (height, 16); - ctx_size = ((width + 255) / 16)*((height + 255) / 16) * 16 * max_references + 52 * 1024; - return ctx_size; + return ((width + 255) / 16) * ((height + 255) / 16) * 16 * max_references + 52 * 1024; } /* calculate size of reference picture buffer */ diff --git a/src/gallium/drivers/radeonsi/si_blit.c b/src/gallium/drivers/radeonsi/si_blit.c index 48972bd170c..b7450b6fcec 100644 --- a/src/gallium/drivers/radeonsi/si_blit.c +++ b/src/gallium/drivers/radeonsi/si_blit.c @@ -586,7 +586,8 @@ void si_resource_copy_region(struct pipe_context *ctx, si_blitter_begin(ctx, SI_COPY); util_blitter_blit_generic(sctx->blitter, dst_view, &dstbox, src_view, src_box, src_width0, src_height0, - PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL); + PIPE_MASK_RGBAZS, PIPE_TEX_FILTER_NEAREST, NULL, + FALSE); si_blitter_end(ctx); pipe_surface_reference(&dst_view, NULL); diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c index 4288e9b2ab1..fa6c15a6591 100644 --- a/src/gallium/drivers/radeonsi/si_shader.c +++ b/src/gallium/drivers/radeonsi/si_shader.c @@ -2277,7 +2277,7 @@ static void tex_fetch_args( unsigned sampler_index; unsigned num_deriv_channels = 0; bool has_offset = HAVE_LLVM >= 0x0305 ? inst->Texture.NumOffsets > 0 : false; - LLVMValueRef res_ptr, samp_ptr; + LLVMValueRef res_ptr, samp_ptr, fmask_ptr = NULL; sampler_src = emit_data->inst->Instruction.NumSrcRegs - 1; sampler_index = emit_data->inst->Src[sampler_src].Register.Index; @@ -2293,9 +2293,19 @@ static void tex_fetch_args( samp_ptr = LLVMGetParam(si_shader_ctx->radeon_bld.main_fn, SI_PARAM_SAMPLER); samp_ptr = build_indexed_load_const(si_shader_ctx, samp_ptr, ind_index); + + if (target == TGSI_TEXTURE_2D_MSAA || + target == TGSI_TEXTURE_2D_ARRAY_MSAA) { + ind_index = LLVMBuildAdd(gallivm->builder, ind_index, + lp_build_const_int32(gallivm, + SI_FMASK_TEX_OFFSET), ""); + fmask_ptr = LLVMGetParam(si_shader_ctx->radeon_bld.main_fn, SI_PARAM_RESOURCE); + fmask_ptr = build_indexed_load_const(si_shader_ctx, res_ptr, ind_index); + } } else { res_ptr = si_shader_ctx->resources[sampler_index]; samp_ptr = si_shader_ctx->samplers[sampler_index]; + fmask_ptr = si_shader_ctx->resources[SI_FMASK_TEX_OFFSET + sampler_index]; } if (target == TGSI_TEXTURE_BUFFER) { @@ -2493,7 +2503,7 @@ static void tex_fetch_args( txf_emit_data.dst_type = LLVMVectorType( LLVMInt32TypeInContext(gallivm->context), 4); txf_emit_data.args[0] = lp_build_gather_values(gallivm, txf_address, txf_count); - txf_emit_data.args[1] = si_shader_ctx->resources[SI_FMASK_TEX_OFFSET + sampler_index]; + txf_emit_data.args[1] = fmask_ptr; txf_emit_data.args[2] = lp_build_const_int32(gallivm, inst.Texture.Texture); txf_emit_data.arg_count = 3; @@ -2524,8 +2534,7 @@ static void tex_fetch_args( * resource descriptor is 0 (invalid), */ LLVMValueRef fmask_desc = - LLVMBuildBitCast(gallivm->builder, - si_shader_ctx->resources[SI_FMASK_TEX_OFFSET + sampler_index], + LLVMBuildBitCast(gallivm->builder, fmask_ptr, LLVMVectorType(uint_bld->elem_type, 8), ""); LLVMValueRef fmask_word1 = @@ -3973,7 +3982,7 @@ static void si_dump_key(unsigned shader, union si_shader_key *key) fprintf(stderr, " es_enabled_outputs = 0x%"PRIx64"\n", key->vs.es_enabled_outputs); fprintf(stderr, " as_es = %u\n", key->vs.as_es); - fprintf(stderr, " as_es = %u\n", key->vs.as_ls); + fprintf(stderr, " as_ls = %u\n", key->vs.as_ls); break; case PIPE_SHADER_TESS_CTRL: diff --git a/src/gallium/drivers/vc4/vc4_context.h b/src/gallium/drivers/vc4/vc4_context.h index 654c46f3c0d..3a63af8f2b0 100644 --- a/src/gallium/drivers/vc4/vc4_context.h +++ b/src/gallium/drivers/vc4/vc4_context.h @@ -270,6 +270,7 @@ struct vc4_context { struct ra_regs *regs; unsigned int reg_class_any; + unsigned int reg_class_a_or_b_or_acc; unsigned int reg_class_r4_or_a; unsigned int reg_class_a; diff --git a/src/gallium/drivers/vc4/vc4_opt_algebraic.c b/src/gallium/drivers/vc4/vc4_opt_algebraic.c index 7978ea1829f..5b435832b92 100644 --- a/src/gallium/drivers/vc4/vc4_opt_algebraic.c +++ b/src/gallium/drivers/vc4/vc4_opt_algebraic.c @@ -143,15 +143,6 @@ qir_opt_algebraic(struct vc4_compile *c) case QOP_SEL_X_Y_ZC: case QOP_SEL_X_Y_NS: case QOP_SEL_X_Y_NC: - if (qir_reg_equals(inst->src[0], inst->src[1])) { - /* Turn "dst = (sf == x) ? a : a)" into - * "dst = a" - */ - replace_with_mov(c, inst, inst->src[1]); - progress = true; - break; - } - if (is_zero(c, inst->src[1])) { /* Replace references to a 0 uniform value * with the SEL_X_0 equivalent. @@ -207,6 +198,7 @@ qir_opt_algebraic(struct vc4_compile *c) /* FADD(a, FSUB(0, b)) -> FSUB(a, b) */ if (inst->src[1].file == QFILE_TEMP && + c->defs[inst->src[1].index] && c->defs[inst->src[1].index]->op == QOP_FSUB) { struct qinst *fsub = c->defs[inst->src[1].index]; if (is_zero(c, fsub->src[0])) { @@ -221,6 +213,7 @@ qir_opt_algebraic(struct vc4_compile *c) /* FADD(FSUB(0, b), a) -> FSUB(a, b) */ if (inst->src[0].file == QFILE_TEMP && + c->defs[inst->src[0].index] && c->defs[inst->src[0].index]->op == QOP_FSUB) { struct qinst *fsub = c->defs[inst->src[0].index]; if (is_zero(c, fsub->src[0])) { @@ -236,18 +229,20 @@ qir_opt_algebraic(struct vc4_compile *c) break; case QOP_FMUL: - if (replace_x_0_with_0(c, inst, 0) || - replace_x_0_with_0(c, inst, 1) || - fmul_replace_one(c, inst, 0) || - fmul_replace_one(c, inst, 1)) { + if (!inst->dst.pack && + (replace_x_0_with_0(c, inst, 0) || + replace_x_0_with_0(c, inst, 1) || + fmul_replace_one(c, inst, 0) || + fmul_replace_one(c, inst, 1))) { progress = true; break; } break; case QOP_MUL24: - if (replace_x_0_with_0(c, inst, 0) || - replace_x_0_with_0(c, inst, 1)) { + if (!inst->dst.pack && + (replace_x_0_with_0(c, inst, 0) || + replace_x_0_with_0(c, inst, 1))) { progress = true; break; } @@ -280,6 +275,14 @@ qir_opt_algebraic(struct vc4_compile *c) } break; + case QOP_RCP: + if (is_1f(c, inst->src[0])) { + replace_with_mov(c, inst, inst->src[0]); + progress = true; + break; + } + break; + default: break; } diff --git a/src/gallium/drivers/vc4/vc4_opt_copy_propagation.c b/src/gallium/drivers/vc4/vc4_opt_copy_propagation.c index a755de9aa41..fd2539aed95 100644 --- a/src/gallium/drivers/vc4/vc4_opt_copy_propagation.c +++ b/src/gallium/drivers/vc4/vc4_opt_copy_propagation.c @@ -39,21 +39,27 @@ qir_opt_copy_propagation(struct vc4_compile *c) { bool progress = false; bool debug = false; - struct qreg *movs = calloc(c->num_temps, sizeof(struct qreg)); list_for_each_entry(struct qinst, inst, &c->instructions, link) { for (int i = 0; i < qir_get_op_nsrc(inst->op); i++) { int index = inst->src[i].index; if (inst->src[i].file == QFILE_TEMP && - (movs[index].file == QFILE_TEMP || - movs[index].file == QFILE_UNIF)) { + c->defs[index] && + c->defs[index]->op == QOP_MOV && + (c->defs[index]->src[0].file == QFILE_TEMP || + c->defs[index]->src[0].file == QFILE_UNIF)) { + /* If it has a pack, it shouldn't be an SSA + * def. + */ + assert(!c->defs[index]->dst.pack); + if (debug) { fprintf(stderr, "Copy propagate: "); qir_dump_inst(c, inst); fprintf(stderr, "\n"); } - inst->src[i] = movs[index]; + inst->src[i] = c->defs[index]->src[0]; if (debug) { fprintf(stderr, "to: "); @@ -64,14 +70,6 @@ qir_opt_copy_propagation(struct vc4_compile *c) progress = true; } } - - if (inst->op == QOP_MOV && - inst->dst.file == QFILE_TEMP && - inst->src[0].file != QFILE_VPM) { - movs[inst->dst.index] = inst->src[0]; - } } - - free(movs); return progress; } diff --git a/src/gallium/drivers/vc4/vc4_opt_vpm_writes.c b/src/gallium/drivers/vc4/vc4_opt_vpm_writes.c index e04f02859d5..f2cdf8f694f 100644 --- a/src/gallium/drivers/vc4/vc4_opt_vpm_writes.c +++ b/src/gallium/drivers/vc4/vc4_opt_vpm_writes.c @@ -68,7 +68,7 @@ qir_opt_vpm_writes(struct vc4_compile *c) continue; struct qinst *inst = c->defs[temp]; - if (qir_is_multi_instruction(inst)) + if (!inst || qir_is_multi_instruction(inst)) continue; if (qir_depends_on_flags(inst) || inst->sf) @@ -79,22 +79,6 @@ qir_opt_vpm_writes(struct vc4_compile *c) continue; } - /* A QOP_TEX_RESULT destination is r4, so we can't move - * accesses to it past another QOP_TEX_RESULT which would - * update it. - */ - int src; - for (src = 0; src < qir_get_op_nsrc(inst->op); src++) { - if (inst->src[src].file == QFILE_TEMP) { - if (c->defs[inst->src[src].index]->op == - QOP_TEX_RESULT) { - break; - } - } - } - if (src != qir_get_op_nsrc(inst->op)) - continue; - /* Move the generating instruction to the end of the program * to maintain the order of the VPM writes. */ diff --git a/src/gallium/drivers/vc4/vc4_program.c b/src/gallium/drivers/vc4/vc4_program.c index 13c472152d8..e002983fdbb 100644 --- a/src/gallium/drivers/vc4/vc4_program.c +++ b/src/gallium/drivers/vc4/vc4_program.c @@ -818,6 +818,72 @@ declare_uniform_range(struct vc4_compile *c, uint32_t start, uint32_t size) c->ubo_ranges[array_id].used = false; } +static bool +ntq_src_is_only_ssa_def_user(nir_src *src) +{ + if (!src->is_ssa) + return false; + + if (!list_empty(&src->ssa->if_uses)) + return false; + + return (src->ssa->uses.next == &src->use_link && + src->ssa->uses.next->next == &src->ssa->uses); +} + +/** + * In general, emits a nir_pack_unorm_4x8 as a series of MOVs with the pack + * bit set. + * + * However, as an optimization, it tries to find the instructions generating + * the sources to be packed and just emit the pack flag there, if possible. + */ +static void +ntq_emit_pack_unorm_4x8(struct vc4_compile *c, nir_alu_instr *instr) +{ + struct qreg result = qir_get_temp(c); + struct nir_alu_instr *vec4 = NULL; + + /* If packing from a vec4 op (as expected), identify it so that we can + * peek back at what generated its sources. + */ + if (instr->src[0].src.is_ssa && + instr->src[0].src.ssa->parent_instr->type == nir_instr_type_alu && + nir_instr_as_alu(instr->src[0].src.ssa->parent_instr)->op == + nir_op_vec4) { + vec4 = nir_instr_as_alu(instr->src[0].src.ssa->parent_instr); + } + + for (int i = 0; i < 4; i++) { + int swiz = instr->src[0].swizzle[i]; + struct qreg src; + if (vec4) { + src = ntq_get_src(c, vec4->src[swiz].src, + vec4->src[swiz].swizzle[0]); + } else { + src = ntq_get_src(c, instr->src[0].src, swiz); + } + + if (vec4 && + ntq_src_is_only_ssa_def_user(&vec4->src[swiz].src) && + src.file == QFILE_TEMP && + c->defs[src.index] && + qir_is_mul(c->defs[src.index]) && + !c->defs[src.index]->dst.pack) { + struct qinst *rewrite = c->defs[src.index]; + c->defs[src.index] = NULL; + rewrite->dst = result; + rewrite->dst.pack = QPU_PACK_MUL_8A + i; + continue; + } + + qir_PACK_8_F(c, result, src, i); + } + + struct qreg *dest = ntq_get_dest(c, &instr->dest.dest); + *dest = result; +} + static void ntq_emit_alu(struct vc4_compile *c, nir_alu_instr *instr) { @@ -839,17 +905,7 @@ ntq_emit_alu(struct vc4_compile *c, nir_alu_instr *instr) } if (instr->op == nir_op_pack_unorm_4x8) { - struct qreg result; - for (int i = 0; i < 4; i++) { - struct qreg src = ntq_get_src(c, instr->src[0].src, - instr->src[0].swizzle[i]); - if (i == 0) - result = qir_PACK_8888_F(c, src); - else - result = qir_PACK_8_F(c, result, src, i); - } - struct qreg *dest = ntq_get_dest(c, &instr->dest.dest); - *dest = result; + ntq_emit_pack_unorm_4x8(c, instr); return; } @@ -1130,20 +1186,24 @@ emit_frag_end(struct vc4_compile *c) static void emit_scaled_viewport_write(struct vc4_compile *c, struct qreg rcp_w) { - struct qreg xyi[2]; + struct qreg packed = qir_get_temp(c); for (int i = 0; i < 2; i++) { struct qreg scale = qir_uniform(c, QUNIFORM_VIEWPORT_X_SCALE + i, 0); - xyi[i] = qir_FTOI(c, qir_FMUL(c, - qir_FMUL(c, - c->outputs[c->output_position_index + i], - scale), - rcp_w)); + struct qreg packed_chan = packed; + packed_chan.pack = QPU_PACK_A_16A + i; + + qir_FTOI_dest(c, packed_chan, + qir_FMUL(c, + qir_FMUL(c, + c->outputs[c->output_position_index + i], + scale), + rcp_w)); } - qir_VPM_WRITE(c, qir_PACK_SCALED(c, xyi[0], xyi[1])); + qir_VPM_WRITE(c, packed); } static void diff --git a/src/gallium/drivers/vc4/vc4_qir.c b/src/gallium/drivers/vc4/vc4_qir.c index 254140a72f5..9d930715f9b 100644 --- a/src/gallium/drivers/vc4/vc4_qir.c +++ b/src/gallium/drivers/vc4/vc4_qir.c @@ -71,12 +71,11 @@ static const struct qir_op_info qir_op_info[] = { [QOP_RSQ] = { "rsq", 1, 1, false, true }, [QOP_EXP2] = { "exp2", 1, 2, false, true }, [QOP_LOG2] = { "log2", 1, 2, false, true }, - [QOP_PACK_8888_F] = { "pack_8888_f", 1, 1, false, true }, - [QOP_PACK_8A_F] = { "pack_8a_f", 1, 2, false, true }, - [QOP_PACK_8B_F] = { "pack_8b_f", 1, 2, false, true }, - [QOP_PACK_8C_F] = { "pack_8c_f", 1, 2, false, true }, - [QOP_PACK_8D_F] = { "pack_8d_f", 1, 2, false, true }, - [QOP_PACK_SCALED] = { "pack_scaled", 1, 2, false, true }, + [QOP_PACK_8888_F] = { "pack_8888_f", 1, 1 }, + [QOP_PACK_8A_F] = { "pack_8a_f", 1, 1 }, + [QOP_PACK_8B_F] = { "pack_8b_f", 1, 1 }, + [QOP_PACK_8C_F] = { "pack_8c_f", 1, 1 }, + [QOP_PACK_8D_F] = { "pack_8d_f", 1, 1 }, [QOP_TLB_DISCARD_SETUP] = { "discard", 0, 1, true }, [QOP_TLB_STENCIL_SETUP] = { "tlb_stencil_setup", 0, 1, true }, [QOP_TLB_Z_WRITE] = { "tlb_z", 0, 1, true }, @@ -169,6 +168,18 @@ qir_is_multi_instruction(struct qinst *inst) } bool +qir_is_mul(struct qinst *inst) +{ + switch (inst->op) { + case QOP_FMUL: + case QOP_MUL24: + return true; + default: + return false; + } +} + +bool qir_is_tex(struct qinst *inst) { return inst->op >= QOP_TEX_S && inst->op <= QOP_TEX_DIRECT; @@ -273,6 +284,14 @@ qir_dump_inst(struct vc4_compile *c, struct qinst *inst) inst->sf ? ".sf" : ""); qir_print_reg(c, inst->dst, true); + if (inst->dst.pack) { + if (inst->dst.pack) { + if (qir_is_mul(inst)) + vc4_qpu_disasm_pack_mul(stderr, inst->dst.pack); + else + vc4_qpu_disasm_pack_a(stderr, inst->dst.pack); + } + } for (int i = 0; i < qir_get_op_nsrc(inst->op); i++) { fprintf(stderr, ", "); qir_print_reg(c, inst->src[i], false); @@ -348,7 +367,7 @@ qir_emit(struct vc4_compile *c, struct qinst *inst) if (inst->dst.file == QFILE_TEMP) c->defs[inst->dst.index] = inst; - list_addtail(&inst->link, &c->instructions); + qir_emit_nodef(c, inst); } bool @@ -389,8 +408,11 @@ qir_remove_instruction(struct vc4_compile *c, struct qinst *qinst) struct qreg qir_follow_movs(struct vc4_compile *c, struct qreg reg) { - while (reg.file == QFILE_TEMP && c->defs[reg.index]->op == QOP_MOV) + while (reg.file == QFILE_TEMP && + c->defs[reg.index] && + c->defs[reg.index]->op == QOP_MOV) { reg = c->defs[reg.index]->src[0]; + } return reg; } diff --git a/src/gallium/drivers/vc4/vc4_qir.h b/src/gallium/drivers/vc4/vc4_qir.h index cade795c12a..a2b21fa17bb 100644 --- a/src/gallium/drivers/vc4/vc4_qir.h +++ b/src/gallium/drivers/vc4/vc4_qir.h @@ -58,6 +58,7 @@ enum qfile { struct qreg { enum qfile file; uint32_t index; + int pack; }; enum qop { @@ -104,7 +105,6 @@ enum qop { QOP_LOG2, QOP_VW_SETUP, QOP_VR_SETUP, - QOP_PACK_SCALED, QOP_PACK_8888_F, QOP_PACK_8A_F, QOP_PACK_8B_F, @@ -444,13 +444,20 @@ struct qreg qir_uniform(struct vc4_compile *c, enum quniform_contents contents, uint32_t data); void qir_reorder_uniforms(struct vc4_compile *c); + void qir_emit(struct vc4_compile *c, struct qinst *inst); +static inline void qir_emit_nodef(struct vc4_compile *c, struct qinst *inst) +{ + list_addtail(&inst->link, &c->instructions); +} + struct qreg qir_get_temp(struct vc4_compile *c); int qir_get_op_nsrc(enum qop qop); bool qir_reg_equals(struct qreg a, struct qreg b); bool qir_has_side_effects(struct vc4_compile *c, struct qinst *inst); bool qir_has_side_effect_reads(struct vc4_compile *c, struct qinst *inst); bool qir_is_multi_instruction(struct qinst *inst); +bool qir_is_mul(struct qinst *inst); bool qir_is_tex(struct qinst *inst); bool qir_depends_on_flags(struct qinst *inst); bool qir_writes_r4(struct qinst *inst); @@ -509,6 +516,12 @@ qir_##name(struct vc4_compile *c, struct qreg a) \ struct qreg t = qir_get_temp(c); \ qir_emit(c, qir_inst(QOP_##name, t, a, c->undef)); \ return t; \ +} \ +static inline void \ +qir_##name##_dest(struct vc4_compile *c, struct qreg dest, \ + struct qreg a) \ +{ \ + qir_emit_nodef(c, qir_inst(QOP_##name, dest, a, c->undef)); \ } #define QIR_ALU2(name) \ @@ -518,6 +531,12 @@ qir_##name(struct vc4_compile *c, struct qreg a, struct qreg b) \ struct qreg t = qir_get_temp(c); \ qir_emit(c, qir_inst(QOP_##name, t, a, b)); \ return t; \ +} \ +static inline void \ +qir_##name##_dest(struct vc4_compile *c, struct qreg dest, \ + struct qreg a, struct qreg b) \ +{ \ + qir_emit_nodef(c, qir_inst(QOP_##name, dest, a, b)); \ } #define QIR_NODST_1(name) \ @@ -534,6 +553,14 @@ qir_##name(struct vc4_compile *c, struct qreg a, struct qreg b) \ qir_emit(c, qir_inst(QOP_##name, c->undef, a, b)); \ } +#define QIR_PACK(name) \ +static inline struct qreg \ +qir_##name(struct vc4_compile *c, struct qreg dest, struct qreg a) \ +{ \ + qir_emit_nodef(c, qir_inst(QOP_##name, dest, a, c->undef)); \ + return dest; \ +} + QIR_ALU1(MOV) QIR_ALU2(FADD) QIR_ALU2(FSUB) @@ -570,12 +597,11 @@ QIR_ALU1(RCP) QIR_ALU1(RSQ) QIR_ALU1(EXP2) QIR_ALU1(LOG2) -QIR_ALU2(PACK_SCALED) QIR_ALU1(PACK_8888_F) -QIR_ALU2(PACK_8A_F) -QIR_ALU2(PACK_8B_F) -QIR_ALU2(PACK_8C_F) -QIR_ALU2(PACK_8D_F) +QIR_PACK(PACK_8A_F) +QIR_PACK(PACK_8B_F) +QIR_PACK(PACK_8C_F) +QIR_PACK(PACK_8D_F) QIR_ALU1(VARY_ADD_C) QIR_NODST_2(TEX_S) QIR_NODST_2(TEX_T) @@ -627,11 +653,12 @@ qir_UNPACK_16_I(struct vc4_compile *c, struct qreg src, int i) } static inline struct qreg -qir_PACK_8_F(struct vc4_compile *c, struct qreg rest, struct qreg val, int chan) +qir_PACK_8_F(struct vc4_compile *c, struct qreg dest, struct qreg val, int chan) { - struct qreg t = qir_get_temp(c); - qir_emit(c, qir_inst(QOP_PACK_8A_F + chan, t, rest, val)); - return t; + qir_emit(c, qir_inst(QOP_PACK_8A_F + chan, dest, val, c->undef)); + if (dest.file == QFILE_TEMP) + c->defs[dest.index] = NULL; + return dest; } static inline struct qreg diff --git a/src/gallium/drivers/vc4/vc4_qpu.h b/src/gallium/drivers/vc4/vc4_qpu.h index fbb90ba12a0..0719d2828b5 100644 --- a/src/gallium/drivers/vc4/vc4_qpu.h +++ b/src/gallium/drivers/vc4/vc4_qpu.h @@ -24,6 +24,7 @@ #ifndef VC4_QPU_H #define VC4_QPU_H +#include <stdio.h> #include <stdint.h> #include "util/u_math.h" @@ -206,6 +207,12 @@ void vc4_qpu_disasm(const uint64_t *instructions, int num_instructions); void +vc4_qpu_disasm_pack_mul(FILE *out, uint32_t pack); + +void +vc4_qpu_disasm_pack_a(FILE *out, uint32_t pack); + +void vc4_qpu_validate(uint64_t *insts, uint32_t num_inst); #endif /* VC4_QPU_H */ diff --git a/src/gallium/drivers/vc4/vc4_qpu_disasm.c b/src/gallium/drivers/vc4/vc4_qpu_disasm.c index 00aeb300a9b..0879787ec03 100644 --- a/src/gallium/drivers/vc4/vc4_qpu_disasm.c +++ b/src/gallium/drivers/vc4/vc4_qpu_disasm.c @@ -245,6 +245,18 @@ get_special_write_desc(int reg, bool is_a) return special_write[reg]; } +void +vc4_qpu_disasm_pack_mul(FILE *out, uint32_t pack) +{ + fprintf(out, ".%s", DESC(qpu_pack_mul, pack)); +} + +void +vc4_qpu_disasm_pack_a(FILE *out, uint32_t pack) +{ + fprintf(out, "%s", DESC(qpu_pack_a, pack)); +} + static void print_alu_dst(uint64_t inst, bool is_mul) { @@ -263,9 +275,9 @@ print_alu_dst(uint64_t inst, bool is_mul) fprintf(stderr, "%s%d?", file, waddr); if (is_mul && (inst & QPU_PM)) { - fprintf(stderr, ".%s", DESC(qpu_pack_mul, pack)); + vc4_qpu_disasm_pack_mul(stderr, pack); } else if (is_a && !(inst & QPU_PM)) { - fprintf(stderr, "%s", DESC(qpu_pack_a, pack)); + vc4_qpu_disasm_pack_a(stderr, pack); } } diff --git a/src/gallium/drivers/vc4/vc4_qpu_emit.c b/src/gallium/drivers/vc4/vc4_qpu_emit.c index f324056258c..adf3a8b3658 100644 --- a/src/gallium/drivers/vc4/vc4_qpu_emit.c +++ b/src/gallium/drivers/vc4/vc4_qpu_emit.c @@ -179,10 +179,9 @@ vc4_generate_code(struct vc4_context *vc4, struct vc4_compile *c) static const struct { uint32_t op; - bool is_mul; } translate[] = { -#define A(name) [QOP_##name] = {QPU_A_##name, false} -#define M(name) [QOP_##name] = {QPU_M_##name, true} +#define A(name) [QOP_##name] = {QPU_A_##name} +#define M(name) [QOP_##name] = {QPU_M_##name} A(FADD), A(FSUB), A(FMIN), @@ -336,28 +335,12 @@ vc4_generate_code(struct vc4_context *vc4, struct vc4_compile *c) case QOP_PACK_8B_F: case QOP_PACK_8C_F: case QOP_PACK_8D_F: - /* If dst doesn't happen to already contain src[0], - * then we have to move it in. - */ - if (qinst->src[0].file != QFILE_NULL && - (src[0].mux != dst.mux || src[0].addr != dst.addr)) { - /* Don't overwrite src1 while setting up - * the dst! - */ - if (dst.mux == src[1].mux && - dst.addr == src[1].addr) { - queue(c, qpu_m_MOV(qpu_rb(31), src[1])); - src[1] = qpu_rb(31); - } - - queue(c, qpu_m_MOV(dst, src[0])); - } - - queue(c, qpu_m_MOV(dst, src[1])); - *last_inst(c) |= QPU_PM; - *last_inst(c) |= QPU_SET_FIELD(QPU_PACK_MUL_8A + - qinst->op - QOP_PACK_8A_F, - QPU_PACK); + queue(c, + qpu_m_MOV(dst, src[0]) | + QPU_PM | + QPU_SET_FIELD(QPU_PACK_MUL_8A + + qinst->op - QOP_PACK_8A_F, + QPU_PACK)); break; case QOP_FRAG_X: @@ -419,24 +402,6 @@ vc4_generate_code(struct vc4_context *vc4, struct vc4_compile *c) queue(c, qpu_a_FADD(dst, src[0], qpu_r5())); break; - case QOP_PACK_SCALED: { - uint64_t a = (qpu_a_MOV(dst, src[0]) | - QPU_SET_FIELD(QPU_PACK_A_16A, - QPU_PACK)); - uint64_t b = (qpu_a_MOV(dst, src[1]) | - QPU_SET_FIELD(QPU_PACK_A_16B, - QPU_PACK)); - - if (dst.mux == src[1].mux && dst.addr == src[1].addr) { - queue(c, b); - queue(c, a); - } else { - queue(c, a); - queue(c, b); - } - break; - } - case QOP_TEX_S: case QOP_TEX_T: case QOP_TEX_R: @@ -529,14 +494,24 @@ vc4_generate_code(struct vc4_context *vc4, struct vc4_compile *c) fixup_raddr_conflict(c, dst, &src[0], &src[1]); - if (translate[qinst->op].is_mul) { + if (qir_is_mul(qinst)) { queue(c, qpu_m_alu2(translate[qinst->op].op, dst, src[0], src[1])); + if (qinst->dst.pack) { + *last_inst(c) |= QPU_PM; + *last_inst(c) |= QPU_SET_FIELD(qinst->dst.pack, + QPU_PACK); + } } else { queue(c, qpu_a_alu2(translate[qinst->op].op, dst, src[0], src[1])); + if (qinst->dst.pack) { + assert(dst.mux == QPU_MUX_A); + *last_inst(c) |= QPU_SET_FIELD(qinst->dst.pack, + QPU_PACK); + } } break; diff --git a/src/gallium/drivers/vc4/vc4_register_allocate.c b/src/gallium/drivers/vc4/vc4_register_allocate.c index a29db1f3abe..3ced50f3a44 100644 --- a/src/gallium/drivers/vc4/vc4_register_allocate.c +++ b/src/gallium/drivers/vc4/vc4_register_allocate.c @@ -113,9 +113,10 @@ vc4_alloc_reg_set(struct vc4_context *vc4) if (vc4->regs) return; - vc4->regs = ra_alloc_reg_set(vc4, ARRAY_SIZE(vc4_regs)); + vc4->regs = ra_alloc_reg_set(vc4, ARRAY_SIZE(vc4_regs), true); vc4->reg_class_any = ra_alloc_reg_class(vc4->regs); + vc4->reg_class_a_or_b_or_acc = ra_alloc_reg_class(vc4->regs); vc4->reg_class_r4_or_a = ra_alloc_reg_class(vc4->regs); vc4->reg_class_a = ra_alloc_reg_class(vc4->regs); for (uint32_t i = 0; i < ARRAY_SIZE(vc4_regs); i++) { @@ -130,10 +131,12 @@ vc4_alloc_reg_set(struct vc4_context *vc4) */ if (vc4_regs[i].mux == QPU_MUX_R4) { ra_class_add_reg(vc4->regs, vc4->reg_class_r4_or_a, i); + ra_class_add_reg(vc4->regs, vc4->reg_class_any, i); continue; } ra_class_add_reg(vc4->regs, vc4->reg_class_any, i); + ra_class_add_reg(vc4->regs, vc4->reg_class_a_or_b_or_acc, i); } for (uint32_t i = AB_INDEX; i < AB_INDEX + 64; i += 2) { @@ -177,7 +180,8 @@ vc4_register_allocate(struct vc4_context *vc4, struct vc4_compile *c) uint8_t class_bits[c->num_temps]; struct qpu_reg *temp_registers = calloc(c->num_temps, sizeof(*temp_registers)); - memset(def, 0, sizeof(def)); + for (int i = 0; i < ARRAY_SIZE(def); i++) + def[i] = ~0; memset(use, 0, sizeof(use)); /* If things aren't ever written (undefined values), just read from @@ -196,7 +200,7 @@ vc4_register_allocate(struct vc4_context *vc4, struct vc4_compile *c) uint32_t ip = 0; list_for_each_entry(struct qinst, inst, &c->instructions, link) { if (inst->dst.file == QFILE_TEMP) { - def[inst->dst.index] = ip; + def[inst->dst.index] = MIN2(ip, def[inst->dst.index]); use[inst->dst.index] = ip; } @@ -267,17 +271,33 @@ vc4_register_allocate(struct vc4_context *vc4, struct vc4_compile *c) AB_INDEX + QPU_R_FRAG_PAYLOAD_ZW * 2); break; - case QOP_PACK_SCALED: - /* The pack flags require an A-file dst register. */ - class_bits[inst->dst.index] &= CLASS_BIT_A; - break; - default: break; } + if (inst->dst.pack && !qir_is_mul(inst)) { + /* The non-MUL pack flags require an A-file dst + * register. + */ + class_bits[inst->dst.index] &= CLASS_BIT_A; + } + if (qir_src_needs_a_file(inst)) { - class_bits[inst->src[0].index] &= CLASS_BIT_A; + switch (inst->op) { + case QOP_UNPACK_8A_F: + case QOP_UNPACK_8B_F: + case QOP_UNPACK_8C_F: + case QOP_UNPACK_8D_F: + /* Special case: these can be done as R4 + * unpacks, as well. + */ + class_bits[inst->src[0].index] &= (CLASS_BIT_A | + CLASS_BIT_R4); + break; + default: + class_bits[inst->src[0].index] &= CLASS_BIT_A; + break; + } } ip++; } @@ -287,9 +307,11 @@ vc4_register_allocate(struct vc4_context *vc4, struct vc4_compile *c) switch (class_bits[i]) { case CLASS_BIT_A | CLASS_BIT_B_OR_ACC | CLASS_BIT_R4: - case CLASS_BIT_A | CLASS_BIT_B_OR_ACC: ra_set_node_class(g, node, vc4->reg_class_any); break; + case CLASS_BIT_A | CLASS_BIT_B_OR_ACC: + ra_set_node_class(g, node, vc4->reg_class_a_or_b_or_acc); + break; case CLASS_BIT_A | CLASS_BIT_R4: ra_set_node_class(g, node, vc4->reg_class_r4_or_a); break; diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h index 1e493f47ccf..266ebbafe36 100644 --- a/src/gallium/include/pipe/p_state.h +++ b/src/gallium/include/pipe/p_state.h @@ -663,6 +663,7 @@ struct pipe_blit_info boolean render_condition_enable; /**< whether the blit should honor the current render condition */ + boolean alpha_blend; /* dst.rgb = src.rgb * src.a + dst.rgb * (1 - src.a) */ }; diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp b/src/gallium/state_trackers/clover/llvm/invocation.cpp index 63c3f8ee49b..7c23a27150b 100644 --- a/src/gallium/state_trackers/clover/llvm/invocation.cpp +++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp @@ -346,6 +346,15 @@ namespace { // Kernel metadata + struct kernel_arg_md { + llvm::StringRef type_name; + llvm::StringRef access_qual; + kernel_arg_md(llvm::StringRef type_name_, llvm::StringRef access_qual_): + type_name(type_name_), access_qual(access_qual_) {} + }; + +#if HAVE_LLVM >= 0x0306 + const llvm::MDNode * get_kernel_metadata(const llvm::Function *kernel_func) { auto mod = kernel_func->getParent(); @@ -356,12 +365,8 @@ namespace { const llvm::MDNode *kernel_node = nullptr; for (unsigned i = 0; i < kernels_node->getNumOperands(); ++i) { -#if HAVE_LLVM >= 0x0306 auto func = llvm::mdconst::dyn_extract<llvm::Function>( -#else - auto func = llvm::dyn_cast<llvm::Function>( -#endif - kernels_node->getOperand(i)->getOperand(0)); + kernels_node->getOperand(i)->getOperand(0)); if (func == kernel_func) { kernel_node = kernels_node->getOperand(i); break; @@ -387,13 +392,6 @@ namespace { return node; } - struct kernel_arg_md { - llvm::StringRef type_name; - llvm::StringRef access_qual; - kernel_arg_md(llvm::StringRef type_name_, llvm::StringRef access_qual_): - type_name(type_name_), access_qual(access_qual_) {} - }; - std::vector<kernel_arg_md> get_kernel_arg_md(const llvm::Function *kernel_func) { auto num_args = kernel_func->getArgumentList().size(); @@ -415,6 +413,17 @@ namespace { return res; } +#else + + std::vector<kernel_arg_md> + get_kernel_arg_md(const llvm::Function *kernel_func) { + return std::vector<kernel_arg_md>( + kernel_func->getArgumentList().size(), + kernel_arg_md("", "")); + } + +#endif // HAVE_LLVM >= 0x0306 + std::vector<module::argument> get_kernel_args(const llvm::Module *mod, const std::string &kernel_name, const clang::LangAS::Map &address_spaces) { diff --git a/src/gallium/state_trackers/nine/adapter9.c b/src/gallium/state_trackers/nine/adapter9.c index c5ffcb15a18..69e0fa25961 100644 --- a/src/gallium/state_trackers/nine/adapter9.c +++ b/src/gallium/state_trackers/nine/adapter9.c @@ -545,7 +545,7 @@ NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This, /*D3DDEVCAPS_RTPATCHES |*/ /*D3DDEVCAPS_RTPATCHHANDLEZERO |*/ /*D3DDEVCAPS_SEPARATETEXTUREMEMORIES |*/ - /*D3DDEVCAPS_TEXTURENONLOCALVIDMEM |*/ + D3DDEVCAPS_TEXTURENONLOCALVIDMEM | /* D3DDEVCAPS_TEXTURESYSTEMMEMORY |*/ D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | @@ -561,32 +561,32 @@ NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This, D3DPMISCCAPS_TSSARGTEMP | D3DPMISCCAPS_BLENDOP | D3DPIPECAP(INDEP_BLEND_ENABLE, D3DPMISCCAPS_INDEPENDENTWRITEMASKS) | - /*D3DPMISCCAPS_PERSTAGECONSTANT |*/ + /*D3DPMISCCAPS_PERSTAGECONSTANT |*/ /* TODO */ /*D3DPMISCCAPS_POSTBLENDSRGBCONVERT |*/ /* TODO */ D3DPMISCCAPS_FOGANDSPECULARALPHA | D3DPIPECAP(BLEND_EQUATION_SEPARATE, D3DPMISCCAPS_SEPARATEALPHABLEND) | D3DPIPECAP(MIXED_COLORBUFFER_FORMATS, D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS) | D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING | - /*D3DPMISCCAPS_FOGVERTEXCLAMPED*/0; + D3DPMISCCAPS_FOGVERTEXCLAMPED; if (!screen->get_param(screen, PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION)) pCaps->PrimitiveMiscCaps |= D3DPMISCCAPS_CLIPTLVERTS; pCaps->RasterCaps = D3DPIPECAP(ANISOTROPIC_FILTER, D3DPRASTERCAPS_ANISOTROPY) | - /*D3DPRASTERCAPS_COLORPERSPECTIVE |*/ + D3DPRASTERCAPS_COLORPERSPECTIVE | D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_DEPTHBIAS | - /*D3DPRASTERCAPS_FOGRANGE |*/ - /*D3DPRASTERCAPS_FOGTABLE |*/ - /*D3DPRASTERCAPS_FOGVERTEX |*/ + D3DPRASTERCAPS_FOGRANGE | + D3DPRASTERCAPS_FOGTABLE | + D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_MIPMAPLODBIAS | D3DPRASTERCAPS_MULTISAMPLE_TOGGLE | D3DPRASTERCAPS_SCISSORTEST | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS | /*D3DPRASTERCAPS_WBUFFER |*/ - /*D3DPRASTERCAPS_WFOG |*/ + D3DPRASTERCAPS_WFOG | /*D3DPRASTERCAPS_ZBUFFERLESSHSR |*/ - /*D3DPRASTERCAPS_ZFOG |*/ + D3DPRASTERCAPS_ZFOG | D3DPRASTERCAPS_ZTEST; pCaps->ZCmpCaps = D3DPCMPCAPS_NEVER | @@ -697,15 +697,12 @@ NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This, pCaps->MaxAnisotropy = (DWORD)screen->get_paramf(screen, PIPE_CAPF_MAX_TEXTURE_ANISOTROPY); - pCaps->MaxVertexW = 1.0f; /* XXX */ - pCaps->GuardBandLeft = screen->get_paramf(screen, - PIPE_CAPF_GUARD_BAND_LEFT); - pCaps->GuardBandTop = screen->get_paramf(screen, - PIPE_CAPF_GUARD_BAND_TOP); - pCaps->GuardBandRight = screen->get_paramf(screen, - PIPE_CAPF_GUARD_BAND_RIGHT); - pCaps->GuardBandBottom = screen->get_paramf(screen, - PIPE_CAPF_GUARD_BAND_BOTTOM); + /* Values for GeForce 9600 GT */ + pCaps->MaxVertexW = 1e10f; + pCaps->GuardBandLeft = -1e9f; + pCaps->GuardBandTop = -1e9f; + pCaps->GuardBandRight = 1e9f; + pCaps->GuardBandBottom = 1e9f; pCaps->ExtentsAdjust = 0.0f; pCaps->StencilCaps = @@ -724,8 +721,6 @@ NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This, /*D3DFVFCAPS_DONOTSTRIPELEMENTS |*/ D3DFVFCAPS_PSIZE; - /* XXX: Some of these are probably not in SM2.0 so cap them when I figure - * them out. For now leave them all enabled. */ pCaps->TextureOpCaps = D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 | @@ -796,7 +791,8 @@ NineAdapter9_GetDeviceCaps( struct NineAdapter9 *This, pCaps->MaxVertexShaderConst = NINE_MAX_CONST_F; pCaps->PixelShaderVersion = D3DPS_VERSION(3,0); - pCaps->PixelShader1xMaxValue = 8.0f; /* XXX: wine */ + /* Value for GeForce 9600 GT */ + pCaps->PixelShader1xMaxValue = 65504.f; pCaps->DevCaps2 = D3DDEVCAPS2_STREAMOFFSET | D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET | diff --git a/src/gallium/state_trackers/nine/basetexture9.c b/src/gallium/state_trackers/nine/basetexture9.c index 17a8f448ee6..d13138b7d5c 100644 --- a/src/gallium/state_trackers/nine/basetexture9.c +++ b/src/gallium/state_trackers/nine/basetexture9.c @@ -57,7 +57,8 @@ NineBaseTexture9_ctor( struct NineBaseTexture9 *This, user_assert(!(Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)) || Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); user_assert(!(Usage & D3DUSAGE_DYNAMIC) || - Pool != D3DPOOL_MANAGED, D3DERR_INVALIDCALL); + !(Pool == D3DPOOL_MANAGED || + Pool == D3DPOOL_SCRATCH), D3DERR_INVALIDCALL); hr = NineResource9_ctor(&This->base, pParams, initResource, alloc, Type, Pool, Usage); if (FAILED(hr)) @@ -85,6 +86,9 @@ NineBaseTexture9_ctor( struct NineBaseTexture9 *This, util_format_has_depth(util_format_description(This->base.info.format)); list_inithead(&This->list); + list_inithead(&This->list2); + if (Pool == D3DPOOL_MANAGED) + list_add(&This->list2, &This->base.base.device->managed_textures); return D3D_OK; } @@ -98,7 +102,9 @@ NineBaseTexture9_dtor( struct NineBaseTexture9 *This ) pipe_sampler_view_reference(&This->view[1], NULL); if (This->list.prev != NULL && This->list.next != NULL) - list_del(&This->list), + list_del(&This->list); + if (This->list2.prev != NULL && This->list2.next != NULL) + list_del(&This->list2); NineResource9_dtor(&This->base); } @@ -153,6 +159,8 @@ NineBaseTexture9_SetAutoGenFilterType( struct NineBaseTexture9 *This, user_assert(FilterType != D3DTEXF_NONE, D3DERR_INVALIDCALL); This->mipfilter = FilterType; + This->dirty_mip = TRUE; + NineBaseTexture9_GenerateMipSubLevels(This); return D3D_OK; } @@ -310,14 +318,12 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This ) tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth); if (tex->dirty_box.width) { - for (l = 0; l <= last_level; ++l) { + for (l = min_level_dirty; l <= last_level; ++l) { u_box_minify_2d(&box, &tex->dirty_box, l); - NineVolume9_AddDirtyRegion(tex->volumes[l], &tex->dirty_box); + NineVolume9_UploadSelf(tex->volumes[l], &box); } memset(&tex->dirty_box, 0, sizeof(tex->dirty_box)); } - for (l = min_level_dirty; l <= last_level; ++l) - NineVolume9_UploadSelf(tex->volumes[l]); } else { assert(!"invalid texture type"); } @@ -361,8 +367,7 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This ) box.width = u_minify(This->base.info.width0, l); box.height = u_minify(This->base.info.height0, l); box.depth = u_minify(This->base.info.depth0, l); - NineVolume9_AddDirtyRegion(tex->volumes[l], &box); - NineVolume9_UploadSelf(tex->volumes[l]); + NineVolume9_UploadSelf(tex->volumes[l], &box); } } else { assert(!"invalid texture type"); @@ -381,8 +386,7 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This ) void WINAPI NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This ) { - struct pipe_resource *resource = This->base.resource; - + struct pipe_resource *resource; unsigned base_level = 0; unsigned last_level = This->base.info.last_level - This->managed.lod; unsigned first_layer = 0; @@ -405,6 +409,8 @@ NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This ) last_layer = util_max_layer(This->view[0]->texture, base_level); + resource = This->base.resource; + util_gen_mipmap(This->pipe, resource, resource->format, base_level, last_level, first_layer, last_layer, filter); @@ -530,6 +536,11 @@ NineBaseTexture9_UpdateSamplerView( struct NineBaseTexture9 *This, swizzle[2] = PIPE_SWIZZLE_RED; swizzle[3] = PIPE_SWIZZLE_RED; } + } else if (resource->format == PIPE_FORMAT_RGTC2_UNORM) { + swizzle[0] = PIPE_SWIZZLE_GREEN; + swizzle[1] = PIPE_SWIZZLE_RED; + swizzle[2] = PIPE_SWIZZLE_ONE; + swizzle[3] = PIPE_SWIZZLE_ONE; } else if (resource->format != PIPE_FORMAT_A8_UNORM && resource->format != PIPE_FORMAT_RGTC1_UNORM) { /* exceptions: @@ -578,6 +589,21 @@ NineBaseTexture9_PreLoad( struct NineBaseTexture9 *This ) NineBaseTexture9_UploadSelf(This); } +void +NineBaseTexture9_UnLoad( struct NineBaseTexture9 *This ) +{ + if (This->base.pool != D3DPOOL_MANAGED || + This->managed.lod_resident == -1) + return; + + pipe_resource_reference(&This->base.resource, NULL); + This->managed.lod_resident = -1; + This->managed.dirty = TRUE; + + /* If the texture is bound, we have to re-upload it */ + BASETEX_REGISTER_UPDATE(This); +} + #ifdef DEBUG void NineBaseTexture9_Dump( struct NineBaseTexture9 *This ) diff --git a/src/gallium/state_trackers/nine/basetexture9.h b/src/gallium/state_trackers/nine/basetexture9.h index 9d6fb0c002a..b19a62195fc 100644 --- a/src/gallium/state_trackers/nine/basetexture9.h +++ b/src/gallium/state_trackers/nine/basetexture9.h @@ -30,7 +30,8 @@ struct NineBaseTexture9 { struct NineResource9 base; - struct list_head list; + struct list_head list; /* for update_textures */ + struct list_head list2; /* for managed_textures */ /* g3d */ struct pipe_context *pipe; @@ -94,6 +95,9 @@ NineBaseTexture9_GenerateMipSubLevels( struct NineBaseTexture9 *This ); void WINAPI NineBaseTexture9_PreLoad( struct NineBaseTexture9 *This ); +void +NineBaseTexture9_UnLoad( struct NineBaseTexture9 *This ); + /* For D3DPOOL_MANAGED only (after SetLOD change): */ HRESULT NineBaseTexture9_CreatePipeResource( struct NineBaseTexture9 *This, diff --git a/src/gallium/state_trackers/nine/cubetexture9.c b/src/gallium/state_trackers/nine/cubetexture9.c index edea1f28a8d..abba2637946 100644 --- a/src/gallium/state_trackers/nine/cubetexture9.c +++ b/src/gallium/state_trackers/nine/cubetexture9.c @@ -43,7 +43,7 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This, struct pipe_screen *screen = pParams->device->screen; enum pipe_format pf; unsigned i, l, f, offset, face_size = 0; - unsigned *level_offsets; + unsigned *level_offsets = NULL; D3DSURFACE_DESC sfdesc; void *p; HRESULT hr; @@ -70,6 +70,13 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This, if (Format == D3DFMT_ATI1 || Format == D3DFMT_ATI2) return D3DERR_INVALIDCALL; + if (compressed_format(Format)) { + const unsigned w = util_format_get_blockwidth(pf); + const unsigned h = util_format_get_blockheight(pf); + + user_assert(!(EdgeLength % w) && !(EdgeLength % h), D3DERR_INVALIDCALL); + } + info->screen = pParams->device->screen; info->target = PIPE_TEXTURE_CUBE; info->format = pf; @@ -106,7 +113,7 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This, face_size = nine_format_get_size_and_offsets(pf, level_offsets, EdgeLength, EdgeLength, info->last_level); - This->managed_buffer = MALLOC(6 * face_size); + This->managed_buffer = align_malloc(6 * face_size, 32); if (!This->managed_buffer) return E_OUTOFMEMORY; } @@ -150,8 +157,12 @@ NineCubeTexture9_ctor( struct NineCubeTexture9 *This, } } - for (i = 0; i < 6; ++i) /* width = 0 means empty, depth stays 1 */ + for (i = 0; i < 6; ++i) { + /* Textures start initially dirty */ + This->dirty_rect[i].width = EdgeLength; + This->dirty_rect[i].height = EdgeLength; This->dirty_rect[i].depth = 1; + } return D3D_OK; } @@ -259,13 +270,17 @@ NineCubeTexture9_AddDirtyRect( struct NineCubeTexture9 *This, user_assert(FaceType < 6, D3DERR_INVALIDCALL); if (This->base.base.pool != D3DPOOL_MANAGED) { - if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) + if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) { This->base.dirty_mip = TRUE; + BASETEX_REGISTER_UPDATE(&This->base); + } return D3D_OK; } - This->base.managed.dirty = TRUE; - BASETEX_REGISTER_UPDATE(&This->base); + if (This->base.base.pool == D3DPOOL_MANAGED) { + This->base.managed.dirty = TRUE; + BASETEX_REGISTER_UPDATE(&This->base); + } if (!pDirtyRect) { u_box_origin_2d(This->base.base.info.width0, diff --git a/src/gallium/state_trackers/nine/device9.c b/src/gallium/state_trackers/nine/device9.c index 55948cbb67f..99197a4361b 100644 --- a/src/gallium/state_trackers/nine/device9.c +++ b/src/gallium/state_trackers/nine/device9.c @@ -119,48 +119,6 @@ NineDevice9_SetDefaultState( struct NineDevice9 *This, boolean is_reset ) This, (IDirect3DSurface9 *)This->swapchains[0]->zsbuf); } -void -NineDevice9_RestoreNonCSOState( struct NineDevice9 *This, unsigned mask ) -{ - struct pipe_context *pipe = This->pipe; - - DBG("This=%p mask=%u\n", This, mask); - - if (mask & 0x1) { - struct pipe_constant_buffer cb; - cb.buffer_offset = 0; - - if (This->prefer_user_constbuf) { - cb.buffer = NULL; - cb.user_buffer = This->state.vs_const_f; - } else { - cb.buffer = This->constbuf_vs; - cb.user_buffer = NULL; - } - cb.buffer_size = This->vs_const_size; - pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &cb); - - if (This->prefer_user_constbuf) { - cb.user_buffer = This->state.ps_const_f; - } else { - cb.buffer = This->constbuf_ps; - } - cb.buffer_size = This->ps_const_size; - pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &cb); - } - - if (mask & 0x2) { - struct pipe_poly_stipple stipple; - memset(&stipple, ~0, sizeof(stipple)); - pipe->set_polygon_stipple(pipe, &stipple); - } - - This->state.changed.group = NINE_STATE_ALL; - This->state.changed.vtxbuf = (1ULL << This->caps.MaxStreams) - 1; - This->state.changed.ucp = (1 << PIPE_MAX_CLIP_PLANES) - 1; - This->state.changed.texture = NINE_PS_SAMPLERS_MASK | NINE_VS_SAMPLERS_MASK; -} - #define GET_PCAP(n) pScreen->get_param(pScreen, PIPE_CAP_##n) HRESULT NineDevice9_ctor( struct NineDevice9 *This, @@ -186,6 +144,7 @@ NineDevice9_ctor( struct NineDevice9 *This, if (FAILED(hr)) { return hr; } list_inithead(&This->update_textures); + list_inithead(&This->managed_textures); This->screen = pScreen; This->caps = *pCaps; @@ -341,16 +300,19 @@ NineDevice9_ctor( struct NineDevice9 *This, This->state.vs_const_f = CALLOC(This->vs_const_size, 1); This->state.ps_const_f = CALLOC(This->ps_const_size, 1); This->state.vs_lconstf_temp = CALLOC(This->vs_const_size,1); + This->state.ps_lconstf_temp = CALLOC(This->ps_const_size,1); if (!This->state.vs_const_f || !This->state.ps_const_f || - !This->state.vs_lconstf_temp) + !This->state.vs_lconstf_temp || !This->state.ps_lconstf_temp) return E_OUTOFMEMORY; if (strstr(pScreen->get_name(pScreen), "AMD") || strstr(pScreen->get_name(pScreen), "ATI")) { - This->prefer_user_constbuf = TRUE; This->driver_bugs.buggy_barycentrics = TRUE; } + /* Disable NV path for now, needs some fixes */ + This->prefer_user_constbuf = TRUE; + tmpl.target = PIPE_BUFFER; tmpl.format = PIPE_FORMAT_R8_UNORM; tmpl.height0 = 1; @@ -376,6 +338,8 @@ NineDevice9_ctor( struct NineDevice9 *This, { struct pipe_resource tmplt; struct pipe_sampler_view templ; + struct pipe_sampler_state samp; + memset(&samp, 0, sizeof(samp)); tmplt.target = PIPE_TEXTURE_2D; tmplt.width0 = 1; @@ -404,22 +368,39 @@ NineDevice9_ctor( struct NineDevice9 *This, templ.swizzle_a = PIPE_SWIZZLE_ONE; templ.target = This->dummy_texture->target; - This->dummy_sampler = This->pipe->create_sampler_view(This->pipe, This->dummy_texture, &templ); - if (!This->dummy_sampler) + This->dummy_sampler_view = This->pipe->create_sampler_view(This->pipe, This->dummy_texture, &templ); + if (!This->dummy_sampler_view) return D3DERR_DRIVERINTERNALERROR; + + samp.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + samp.max_lod = 15.0f; + samp.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samp.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samp.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samp.min_img_filter = PIPE_TEX_FILTER_NEAREST; + samp.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + samp.compare_mode = PIPE_TEX_COMPARE_NONE; + samp.compare_func = PIPE_FUNC_LEQUAL; + samp.normalized_coords = 1; + samp.seamless_cube_map = 1; + This->dummy_sampler_state = samp; } /* Allocate upload helper for drivers that suck (from st pov ;). */ - { - unsigned bind = 0; - This->driver_caps.user_vbufs = GET_PCAP(USER_VERTEX_BUFFERS); - This->driver_caps.user_ibufs = GET_PCAP(USER_INDEX_BUFFERS); + This->driver_caps.user_vbufs = GET_PCAP(USER_VERTEX_BUFFERS); + This->driver_caps.user_ibufs = GET_PCAP(USER_INDEX_BUFFERS); + This->driver_caps.user_cbufs = GET_PCAP(USER_CONSTANT_BUFFERS); + + if (!This->driver_caps.user_vbufs) + This->vertex_uploader = u_upload_create(This->pipe, 65536, 4, PIPE_BIND_VERTEX_BUFFER); + if (!This->driver_caps.user_ibufs) + This->index_uploader = u_upload_create(This->pipe, 128 * 1024, 4, PIPE_BIND_INDEX_BUFFER); + if (!This->driver_caps.user_cbufs) { + unsigned alignment = GET_PCAP(CONSTANT_BUFFER_OFFSET_ALIGNMENT); - if (!This->driver_caps.user_vbufs) bind |= PIPE_BIND_VERTEX_BUFFER; - if (!This->driver_caps.user_ibufs) bind |= PIPE_BIND_INDEX_BUFFER; - if (bind) - This->upload = u_upload_create(This->pipe, 1 << 20, 4, bind); + This->constbuf_uploader = u_upload_create(This->pipe, This->vs_const_size, + alignment, PIPE_BIND_CONSTANT_BUFFER); } This->driver_caps.window_space_position_support = GET_PCAP(TGSI_VS_WINDOW_SPACE_POSITION); @@ -429,10 +410,15 @@ NineDevice9_ctor( struct NineDevice9 *This, nine_ff_init(This); /* initialize fixed function code */ NineDevice9_SetDefaultState(This, FALSE); - NineDevice9_RestoreNonCSOState(This, ~0); + + { + struct pipe_poly_stipple stipple; + memset(&stipple, ~0, sizeof(stipple)); + This->pipe->set_polygon_stipple(This->pipe, &stipple); + } This->update = &This->state; - nine_update_state(This, ~0); + nine_update_state(This); ID3DPresentGroup_Release(This->present); @@ -452,12 +438,16 @@ NineDevice9_dtor( struct NineDevice9 *This ) nine_ff_fini(This); nine_state_clear(&This->state, TRUE); - if (This->upload) - u_upload_destroy(This->upload); + if (This->vertex_uploader) + u_upload_destroy(This->vertex_uploader); + if (This->index_uploader) + u_upload_destroy(This->index_uploader); + if (This->constbuf_uploader) + u_upload_destroy(This->constbuf_uploader); nine_bind(&This->record, NULL); - pipe_sampler_view_reference(&This->dummy_sampler, NULL); + pipe_sampler_view_reference(&This->dummy_sampler_view, NULL); pipe_resource_reference(&This->dummy_texture, NULL); pipe_resource_reference(&This->constbuf_vs, NULL); pipe_resource_reference(&This->constbuf_ps, NULL); @@ -465,6 +455,7 @@ NineDevice9_dtor( struct NineDevice9 *This ) FREE(This->state.vs_const_f); FREE(This->state.ps_const_f); FREE(This->state.vs_lconstf_temp); + FREE(This->state.ps_lconstf_temp); if (This->swapchains) { for (i = 0; i < This->nswapchains; ++i) @@ -547,10 +538,14 @@ NineDevice9_GetAvailableTextureMem( struct NineDevice9 *This ) HRESULT WINAPI NineDevice9_EvictManagedResources( struct NineDevice9 *This ) { - /* We don't really need to do anything here, but might want to free up - * the GPU virtual address space by killing pipe_resources. - */ - STUB(D3D_OK); + struct NineBaseTexture9 *tex; + + DBG("This=%p\n", This); + LIST_FOR_EACH_ENTRY(tex, &This->managed_textures, list2) { + NineBaseTexture9_UnLoad(tex); + } + + return D3D_OK; } HRESULT WINAPI @@ -599,11 +594,11 @@ NineDevice9_SetCursorProperties( struct NineDevice9 *This, UINT YHotSpot, IDirect3DSurface9 *pCursorBitmap ) { - /* TODO: hardware cursor */ struct NineSurface9 *surf = NineSurface9(pCursorBitmap); struct pipe_context *pipe = This->pipe; struct pipe_box box; struct pipe_transfer *transfer; + BOOL hw_cursor; void *ptr; DBG_FLAG(DBG_SWAPCHAIN, "This=%p XHotSpot=%u YHotSpot=%u " @@ -611,8 +606,15 @@ NineDevice9_SetCursorProperties( struct NineDevice9 *This, user_assert(pCursorBitmap, D3DERR_INVALIDCALL); - This->cursor.w = MIN2(surf->desc.Width, This->cursor.image->width0); - This->cursor.h = MIN2(surf->desc.Height, This->cursor.image->height0); + if (This->swapchains[0]->params.Windowed) { + This->cursor.w = MIN2(surf->desc.Width, 32); + This->cursor.h = MIN2(surf->desc.Height, 32); + hw_cursor = 1; /* always use hw cursor for windowed mode */ + } else { + This->cursor.w = MIN2(surf->desc.Width, This->cursor.image->width0); + This->cursor.h = MIN2(surf->desc.Height, This->cursor.image->height0); + hw_cursor = This->cursor.w == 32 && This->cursor.h == 32; + } u_box_origin_2d(This->cursor.w, This->cursor.h, &box); @@ -643,16 +645,21 @@ NineDevice9_SetCursorProperties( struct NineDevice9 *This, lock.pBits, lock.Pitch, This->cursor.w, This->cursor.h); - if (!This->cursor.software && - This->cursor.w == 32 && This->cursor.h == 32) - ID3DPresent_SetCursor(This->swapchains[0]->present, - lock.pBits, &This->cursor.hotspot, - This->cursor.visible); + if (hw_cursor) + hw_cursor = ID3DPresent_SetCursor(This->swapchains[0]->present, + lock.pBits, + &This->cursor.hotspot, + This->cursor.visible) == D3D_OK; NineSurface9_UnlockRect(surf); } pipe->transfer_unmap(pipe, transfer); + /* hide cursor if we emulate it */ + if (!hw_cursor) + ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, FALSE); + This->cursor.software = !hw_cursor; + return D3D_OK; } @@ -670,7 +677,7 @@ NineDevice9_SetCursorPosition( struct NineDevice9 *This, This->cursor.pos.y = Y; if (!This->cursor.software) - ID3DPresent_SetCursorPos(swap->present, &This->cursor.pos); + This->cursor.software = ID3DPresent_SetCursorPos(swap->present, &This->cursor.pos) != D3D_OK; } BOOL WINAPI @@ -683,7 +690,7 @@ NineDevice9_ShowCursor( struct NineDevice9 *This, This->cursor.visible = bShow && (This->cursor.hotspot.x != -1); if (!This->cursor.software) - ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, bShow); + This->cursor.software = ID3DPresent_SetCursor(This->swapchains[0]->present, NULL, NULL, bShow) != D3D_OK; return old; } @@ -752,8 +759,8 @@ NineDevice9_Reset( struct NineDevice9 *This, for (i = 0; i < This->nswapchains; ++i) { D3DPRESENT_PARAMETERS *params = &pPresentationParameters[i]; hr = NineSwapChain9_Resize(This->swapchains[i], params, NULL); - if (FAILED(hr)) - return (hr == D3DERR_OUTOFVIDEOMEMORY) ? hr : D3DERR_DEVICELOST; + if (hr != D3D_OK) + return hr; } nine_pipe_context_clear(This); @@ -1108,6 +1115,13 @@ create_zs_or_rt_surface(struct NineDevice9 *This, default: break; } + if (compressed_format(Format)) { + const unsigned w = util_format_get_blockwidth(templ.format); + const unsigned h = util_format_get_blockheight(templ.format); + + user_assert(!(Width % w) && !(Height % h), D3DERR_INVALIDCALL); + } + if (Pool == D3DPOOL_DEFAULT && Format != D3DFMT_NULL) { /* resource_create doesn't return an error code, so check format here */ user_assert(templ.format != PIPE_FORMAT_NONE, D3DERR_INVALIDCALL); @@ -1173,6 +1187,8 @@ NineDevice9_UpdateSurface( struct NineDevice9 *This, { struct NineSurface9 *dst = NineSurface9(pDestinationSurface); struct NineSurface9 *src = NineSurface9(pSourceSurface); + int copy_width, copy_height; + RECT destRect; DBG("This=%p pSourceSurface=%p pDestinationSurface=%p " "pSourceRect=%p pDestPoint=%p\n", This, @@ -1184,13 +1200,75 @@ NineDevice9_UpdateSurface( struct NineDevice9 *This, if (pDestPoint) DBG("pDestPoint = (%u,%u)\n", pDestPoint->x, pDestPoint->y); + user_assert(dst && src, D3DERR_INVALIDCALL); + user_assert(dst->base.pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); user_assert(src->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL); user_assert(dst->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL); user_assert(src->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL); - return NineSurface9_CopySurface(dst, src, pDestPoint, pSourceRect); + user_assert(!src->lock_count, D3DERR_INVALIDCALL); + user_assert(!dst->lock_count, D3DERR_INVALIDCALL); + + user_assert(dst->desc.Format == src->desc.Format, D3DERR_INVALIDCALL); + user_assert(!depth_stencil_format(dst->desc.Format), D3DERR_INVALIDCALL); + + if (pSourceRect) { + copy_width = pSourceRect->right - pSourceRect->left; + copy_height = pSourceRect->bottom - pSourceRect->top; + + user_assert(pSourceRect->left >= 0 && + copy_width > 0 && + pSourceRect->right <= src->desc.Width && + pSourceRect->top >= 0 && + copy_height > 0 && + pSourceRect->bottom <= src->desc.Height, + D3DERR_INVALIDCALL); + } else { + copy_width = src->desc.Width; + copy_height = src->desc.Height; + } + + destRect.right = copy_width; + destRect.bottom = copy_height; + + if (pDestPoint) { + user_assert(pDestPoint->x >= 0 && pDestPoint->y >= 0, + D3DERR_INVALIDCALL); + destRect.right += pDestPoint->x; + destRect.bottom += pDestPoint->y; + } + + user_assert(destRect.right <= dst->desc.Width && + destRect.bottom <= dst->desc.Height, + D3DERR_INVALIDCALL); + + if (compressed_format(dst->desc.Format)) { + const unsigned w = util_format_get_blockwidth(dst->base.info.format); + const unsigned h = util_format_get_blockheight(dst->base.info.format); + + if (pDestPoint) { + user_assert(!(pDestPoint->x % w) && !(pDestPoint->y % h), + D3DERR_INVALIDCALL); + } + + if (pSourceRect) { + user_assert(!(pSourceRect->left % w) && !(pSourceRect->top % h), + D3DERR_INVALIDCALL); + } + if (!(copy_width == src->desc.Width && + copy_width == dst->desc.Width && + copy_height == src->desc.Height && + copy_height == dst->desc.Height)) { + user_assert(!(copy_width % w) && !(copy_height % h), + D3DERR_INVALIDCALL); + } + } + + NineSurface9_CopyMemToDefault(dst, src, pDestPoint, pSourceRect); + + return D3D_OK; } HRESULT WINAPI @@ -1202,6 +1280,7 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This, struct NineBaseTexture9 *srcb = NineBaseTexture9(pSourceTexture); unsigned l, m; unsigned last_level = dstb->base.info.last_level; + RECT rect; DBG("This=%p pSourceTexture=%p pDestinationTexture=%p\n", This, pSourceTexture, pDestinationTexture); @@ -1227,10 +1306,6 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This, user_assert(dstb->base.type == srcb->base.type, D3DERR_INVALIDCALL); - /* TODO: We can restrict the update to the dirty portions of the source. - * Yes, this seems silly, but it's what MSDN says ... - */ - /* Find src level that matches dst level 0: */ user_assert(srcb->base.info.width0 >= dstb->base.info.width0 && srcb->base.info.height0 >= dstb->base.info.height0 && @@ -1254,9 +1329,25 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This, struct NineTexture9 *dst = NineTexture9(dstb); struct NineTexture9 *src = NineTexture9(srcb); - for (l = 0; l <= last_level; ++l, ++m) - NineSurface9_CopySurface(dst->surfaces[l], - src->surfaces[m], NULL, NULL); + if (src->dirty_rect.width == 0) + return D3D_OK; + + pipe_box_to_rect(&rect, &src->dirty_rect); + for (l = 0; l < m; ++l) + rect_minify_inclusive(&rect); + + for (l = 0; l <= last_level; ++l, ++m) { + fit_rect_format_inclusive(dst->base.base.info.format, + &rect, + dst->surfaces[l]->desc.Width, + dst->surfaces[l]->desc.Height); + NineSurface9_CopyMemToDefault(dst->surfaces[l], + src->surfaces[m], + (POINT *)&rect, + &rect); + rect_minify_inclusive(&rect); + } + u_box_origin_2d(0, 0, &src->dirty_rect); } else if (dstb->base.type == D3DRTYPE_CUBETEXTURE) { struct NineCubeTexture9 *dst = NineCubeTexture9(dstb); @@ -1265,10 +1356,25 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This, /* GPUs usually have them stored as arrays of mip-mapped 2D textures. */ for (z = 0; z < 6; ++z) { + if (src->dirty_rect[z].width == 0) + continue; + + pipe_box_to_rect(&rect, &src->dirty_rect[z]); + for (l = 0; l < m; ++l) + rect_minify_inclusive(&rect); + for (l = 0; l <= last_level; ++l, ++m) { - NineSurface9_CopySurface(dst->surfaces[l * 6 + z], - src->surfaces[m * 6 + z], NULL, NULL); + fit_rect_format_inclusive(dst->base.base.info.format, + &rect, + dst->surfaces[l * 6 + z]->desc.Width, + dst->surfaces[l * 6 + z]->desc.Height); + NineSurface9_CopyMemToDefault(dst->surfaces[l * 6 + z], + src->surfaces[m * 6 + z], + (POINT *)&rect, + &rect); + rect_minify_inclusive(&rect); } + u_box_origin_2d(0, 0, &src->dirty_rect[z]); m -= l; } } else @@ -1276,9 +1382,12 @@ NineDevice9_UpdateTexture( struct NineDevice9 *This, struct NineVolumeTexture9 *dst = NineVolumeTexture9(dstb); struct NineVolumeTexture9 *src = NineVolumeTexture9(srcb); + if (src->dirty_box.width == 0) + return D3D_OK; for (l = 0; l <= last_level; ++l, ++m) - NineVolume9_CopyVolume(dst->volumes[l], - src->volumes[m], 0, 0, 0, NULL); + NineVolume9_CopyMemToDefault(dst->volumes[l], + src->volumes[m], 0, 0, 0, NULL); + u_box_3d(0, 0, 0, 0, 0, 0, &src->dirty_box); } else{ assert(!"invalid texture type"); } @@ -1308,7 +1417,12 @@ NineDevice9_GetRenderTargetData( struct NineDevice9 *This, user_assert(dst->desc.MultiSampleType < 2, D3DERR_INVALIDCALL); user_assert(src->desc.MultiSampleType < 2, D3DERR_INVALIDCALL); - return NineSurface9_CopySurface(dst, src, NULL, NULL); + user_assert(src->desc.Width == dst->desc.Width, D3DERR_INVALIDCALL); + user_assert(src->desc.Height == dst->desc.Height, D3DERR_INVALIDCALL); + + NineSurface9_CopyDefaultToMem(dst, src); + + return D3D_OK; } HRESULT WINAPI @@ -1448,6 +1562,7 @@ NineDevice9_StretchRect( struct NineDevice9 *This, blit.filter = Filter == D3DTEXF_LINEAR ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; + blit.alpha_blend = FALSE; /* If both of a src and dst dimension are negative, flip them. */ if (blit.dst.box.width < 0 && blit.src.box.width < 0) { @@ -1464,8 +1579,12 @@ NineDevice9_StretchRect( struct NineDevice9 *This, user_assert(!scaled || dst != src, D3DERR_INVALIDCALL); user_assert(!scaled || - !NineSurface9_IsOffscreenPlain(dst) || + !NineSurface9_IsOffscreenPlain(dst), D3DERR_INVALIDCALL); + user_assert(!NineSurface9_IsOffscreenPlain(dst) || NineSurface9_IsOffscreenPlain(src), D3DERR_INVALIDCALL); + user_assert(NineSurface9_IsOffscreenPlain(dst) || + dst->desc.Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL), + D3DERR_INVALIDCALL); user_assert(!scaled || (!util_format_is_compressed(dst->base.info.format) && !util_format_is_compressed(src->base.info.format)), @@ -1561,11 +1680,8 @@ NineDevice9_ColorFill( struct NineDevice9 *This, } d3dcolor_to_pipe_color_union(&rgba, color); - fallback = - !This->screen->is_format_supported(This->screen, surf->base.info.format, - surf->base.info.target, - surf->base.info.nr_samples, - PIPE_BIND_RENDER_TARGET); + fallback = !(surf->base.info.bind & PIPE_BIND_RENDER_TARGET); + if (!fallback) { psurf = NineSurface9_GetSurface(surf, 0); if (!psurf) @@ -1774,7 +1890,7 @@ NineDevice9_Clear( struct NineDevice9 *This, return D3D_OK; d3dcolor_to_pipe_color_union(&rgba, Color); - nine_update_state(This, NINE_STATE_FB); + nine_update_state_framebuffer(This); rect.x1 = This->state.viewport.X; rect.y1 = This->state.viewport.Y; @@ -2012,8 +2128,10 @@ NineDevice9_SetLight( struct NineDevice9 *This, return E_OUTOFMEMORY; state->ff.num_lights = N; - for (; n < Index; ++n) + for (; n < Index; ++n) { + memset(&state->ff.light[n], 0, sizeof(D3DLIGHT9)); state->ff.light[n].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID; + } } state->ff.light[Index] = *pLight; @@ -2508,6 +2626,7 @@ NineDevice9_SetTextureStageState( struct NineDevice9 *This, DWORD Value ) { struct nine_state *state = This->update; + int bumpmap_index = -1; DBG("Stage=%u Type=%u Value=%08x\n", Stage, Type, Value); nine_dump_D3DTSS_value(DBG_FF, Type, Value); @@ -2516,6 +2635,36 @@ NineDevice9_SetTextureStageState( struct NineDevice9 *This, user_assert(Type < Elements(state->ff.tex_stage[0]), D3DERR_INVALIDCALL); state->ff.tex_stage[Stage][Type] = Value; + switch (Type) { + case D3DTSS_BUMPENVMAT00: + bumpmap_index = 4 * Stage; + break; + case D3DTSS_BUMPENVMAT10: + bumpmap_index = 4 * Stage + 1; + break; + case D3DTSS_BUMPENVMAT01: + bumpmap_index = 4 * Stage + 2; + break; + case D3DTSS_BUMPENVMAT11: + bumpmap_index = 4 * Stage + 3; + break; + case D3DTSS_BUMPENVLSCALE: + bumpmap_index = 4 * 8 + 2 * Stage; + break; + case D3DTSS_BUMPENVLOFFSET: + bumpmap_index = 4 * 8 + 2 * Stage + 1; + break; + case D3DTSS_TEXTURETRANSFORMFLAGS: + state->changed.group |= NINE_STATE_PS1X_SHADER; + break; + default: + break; + } + + if (bumpmap_index >= 0) { + state->bumpmap_vars[bumpmap_index] = Value; + state->changed.group |= NINE_STATE_PS_CONST; + } state->changed.group |= NINE_STATE_FF_PSSTAGES; state->ff.changed.tex_stage[Stage][Type / 32] |= 1 << (Type % 32); @@ -2560,12 +2709,11 @@ NineDevice9_SetSamplerState( struct NineDevice9 *This, if (Sampler >= D3DDMAPSAMPLER) Sampler = Sampler - D3DDMAPSAMPLER + NINE_MAX_SAMPLERS_PS; - state->samp[Sampler][Type] = Value; - state->changed.group |= NINE_STATE_SAMPLER; - state->changed.sampler[Sampler] |= 1 << Type; - - if (Type == D3DSAMP_SRGBTEXTURE) - state->changed.srgb = TRUE; + if (state->samp[Sampler][Type] != Value || unlikely(This->is_recording)) { + state->samp[Sampler][Type] = Value; + state->changed.group |= NINE_STATE_SAMPLER; + state->changed.sampler[Sampler] |= 1 << Type; + } return D3D_OK; } @@ -2724,7 +2872,7 @@ NineDevice9_DrawPrimitive( struct NineDevice9 *This, DBG("iface %p, PrimitiveType %u, StartVertex %u, PrimitiveCount %u\n", This, PrimitiveType, StartVertex, PrimitiveCount); - nine_update_state(This, ~0); + nine_update_state(This); init_draw_info(&info, This, PrimitiveType, PrimitiveCount); info.indexed = FALSE; @@ -2757,7 +2905,7 @@ NineDevice9_DrawIndexedPrimitive( struct NineDevice9 *This, user_assert(This->state.idxbuf, D3DERR_INVALIDCALL); user_assert(This->state.vdecl, D3DERR_INVALIDCALL); - nine_update_state(This, ~0); + nine_update_state(This); init_draw_info(&info, This, PrimitiveType, PrimitiveCount); info.indexed = TRUE; @@ -2789,7 +2937,7 @@ NineDevice9_DrawPrimitiveUP( struct NineDevice9 *This, user_assert(pVertexStreamZeroData && VertexStreamZeroStride, D3DERR_INVALIDCALL); - nine_update_state(This, ~0); + nine_update_state(This); init_draw_info(&info, This, PrimitiveType, PrimitiveCount); info.indexed = FALSE; @@ -2803,13 +2951,16 @@ NineDevice9_DrawPrimitiveUP( struct NineDevice9 *This, vtxbuf.buffer = NULL; vtxbuf.user_buffer = pVertexStreamZeroData; - if (!This->driver_caps.user_vbufs) - u_upload_data(This->upload, + if (!This->driver_caps.user_vbufs) { + u_upload_data(This->vertex_uploader, 0, (info.max_index + 1) * VertexStreamZeroStride, /* XXX */ vtxbuf.user_buffer, &vtxbuf.buffer_offset, &vtxbuf.buffer); + u_upload_unmap(This->vertex_uploader); + vtxbuf.user_buffer = NULL; + } This->pipe->set_vertex_buffers(This->pipe, 0, 1, &vtxbuf); @@ -2851,7 +3002,7 @@ NineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This, user_assert(IndexDataFormat == D3DFMT_INDEX16 || IndexDataFormat == D3DFMT_INDEX32, D3DERR_INVALIDCALL); - nine_update_state(This, ~0); + nine_update_state(This); init_draw_info(&info, This, PrimitiveType, PrimitiveCount); info.indexed = TRUE; @@ -2872,23 +3023,28 @@ NineDevice9_DrawIndexedPrimitiveUP( struct NineDevice9 *This, if (!This->driver_caps.user_vbufs) { const unsigned base = info.min_index * VertexStreamZeroStride; - u_upload_data(This->upload, + u_upload_data(This->vertex_uploader, base, (info.max_index - info.min_index + 1) * VertexStreamZeroStride, /* XXX */ (const uint8_t *)vbuf.user_buffer + base, &vbuf.buffer_offset, &vbuf.buffer); + u_upload_unmap(This->vertex_uploader); /* Won't be used: */ vbuf.buffer_offset -= base; + vbuf.user_buffer = NULL; } - if (!This->driver_caps.user_ibufs) - u_upload_data(This->upload, + if (!This->driver_caps.user_ibufs) { + u_upload_data(This->index_uploader, 0, info.count * ibuf.index_size, ibuf.user_buffer, &ibuf.offset, &ibuf.buffer); + u_upload_unmap(This->index_uploader); + ibuf.user_buffer = NULL; + } This->pipe->set_vertex_buffers(This->pipe, 0, 1, &vbuf); This->pipe->set_index_buffer(This->pipe, &ibuf); @@ -2935,7 +3091,7 @@ NineDevice9_ProcessVertices( struct NineDevice9 *This, if (!screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS)) STUB(D3DERR_INVALIDCALL); - nine_update_state(This, ~0); + nine_update_state(This); /* TODO: Create shader with stream output. */ STUB(D3DERR_INVALIDCALL); @@ -3105,6 +3261,13 @@ NineDevice9_SetVertexShader( struct NineDevice9 *This, DBG("This=%p pShader=%p\n", This, pShader); + if (!This->is_recording && state->vs == (struct NineVertexShader9*)pShader) + return D3D_OK; + + /* ff -> non-ff: commit back non-ff constants */ + if (!state->vs && pShader) + state->commit |= NINE_STATE_COMMIT_CONST_VS; + nine_bind(&state->vs, pShader); state->changed.group |= NINE_STATE_VS; @@ -3139,6 +3302,12 @@ NineDevice9_SetVertexShaderConstantF( struct NineDevice9 *This, return D3D_OK; user_assert(pConstantData, D3DERR_INVALIDCALL); + if (!This->is_recording) { + if (!memcmp(&state->vs_const_f[StartRegister * 4], pConstantData, + Vector4fCount * 4 * sizeof(state->vs_const_f[0]))) + return D3D_OK; + } + memcpy(&state->vs_const_f[StartRegister * 4], pConstantData, Vector4fCount * 4 * sizeof(state->vs_const_f[0])); @@ -3188,6 +3357,11 @@ NineDevice9_SetVertexShaderConstantI( struct NineDevice9 *This, user_assert(pConstantData, D3DERR_INVALIDCALL); if (This->driver_caps.vs_integer) { + if (!This->is_recording) { + if (!memcmp(&state->vs_const_i[StartRegister][0], pConstantData, + Vector4iCount * sizeof(state->vs_const_i[0]))) + return D3D_OK; + } memcpy(&state->vs_const_i[StartRegister][0], pConstantData, Vector4iCount * sizeof(state->vs_const_i[0])); @@ -3252,6 +3426,16 @@ NineDevice9_SetVertexShaderConstantB( struct NineDevice9 *This, user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL); user_assert(pConstantData, D3DERR_INVALIDCALL); + if (!This->is_recording) { + bool noChange = true; + for (i = 0; i < BoolCount; i++) { + if (!!state->vs_const_b[StartRegister + i] != !!pConstantData[i]) + noChange = false; + } + if (noChange) + return D3D_OK; + } + for (i = 0; i < BoolCount; i++) state->vs_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0; @@ -3433,6 +3617,13 @@ NineDevice9_SetPixelShader( struct NineDevice9 *This, DBG("This=%p pShader=%p\n", This, pShader); + if (!This->is_recording && state->ps == (struct NinePixelShader9*)pShader) + return D3D_OK; + + /* ff -> non-ff: commit back non-ff constants */ + if (!state->ps && pShader) + state->commit |= NINE_STATE_COMMIT_CONST_PS; + nine_bind(&state->ps, pShader); state->changed.group |= NINE_STATE_PS; @@ -3473,6 +3664,12 @@ NineDevice9_SetPixelShaderConstantF( struct NineDevice9 *This, return D3D_OK; user_assert(pConstantData, D3DERR_INVALIDCALL); + if (!This->is_recording) { + if (!memcmp(&state->ps_const_f[StartRegister * 4], pConstantData, + Vector4fCount * 4 * sizeof(state->ps_const_f[0]))) + return D3D_OK; + } + memcpy(&state->ps_const_f[StartRegister * 4], pConstantData, Vector4fCount * 4 * sizeof(state->ps_const_f[0])); @@ -3522,6 +3719,11 @@ NineDevice9_SetPixelShaderConstantI( struct NineDevice9 *This, user_assert(pConstantData, D3DERR_INVALIDCALL); if (This->driver_caps.ps_integer) { + if (!This->is_recording) { + if (!memcmp(&state->ps_const_i[StartRegister][0], pConstantData, + Vector4iCount * sizeof(state->ps_const_i[0]))) + return D3D_OK; + } memcpy(&state->ps_const_i[StartRegister][0], pConstantData, Vector4iCount * sizeof(state->ps_const_i[0])); @@ -3585,6 +3787,16 @@ NineDevice9_SetPixelShaderConstantB( struct NineDevice9 *This, user_assert(StartRegister + BoolCount <= NINE_MAX_CONST_B, D3DERR_INVALIDCALL); user_assert(pConstantData, D3DERR_INVALIDCALL); + if (!This->is_recording) { + bool noChange = true; + for (i = 0; i < BoolCount; i++) { + if (!!state->ps_const_b[StartRegister + i] != !!pConstantData[i]) + noChange = false; + } + if (noChange) + return D3D_OK; + } + for (i = 0; i < BoolCount; i++) state->ps_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0; diff --git a/src/gallium/state_trackers/nine/device9.h b/src/gallium/state_trackers/nine/device9.h index 74607451c5f..98d9c4df06a 100644 --- a/src/gallium/state_trackers/nine/device9.h +++ b/src/gallium/state_trackers/nine/device9.h @@ -69,6 +69,7 @@ struct NineDevice9 struct nine_state state; /* device state */ struct list_head update_textures; + struct list_head managed_textures; boolean is_recording; boolean in_scene; @@ -83,7 +84,8 @@ struct NineDevice9 uint16_t max_ps_const_f; struct pipe_resource *dummy_texture; - struct pipe_sampler_view *dummy_sampler; + struct pipe_sampler_view *dummy_sampler_view; + struct pipe_sampler_state dummy_sampler_state; struct gen_mipmap_state *gen_mipmap; @@ -113,6 +115,7 @@ struct NineDevice9 struct { boolean user_vbufs; boolean user_ibufs; + boolean user_cbufs; boolean window_space_position_support; boolean vs_integer; boolean ps_integer; @@ -122,7 +125,9 @@ struct NineDevice9 boolean buggy_barycentrics; } driver_bugs; - struct u_upload_mgr *upload; + struct u_upload_mgr *vertex_uploader; + struct u_upload_mgr *index_uploader; + struct u_upload_mgr *constbuf_uploader; struct nine_range_pool range_pool; @@ -180,10 +185,6 @@ NineDevice9_GetCSO( struct NineDevice9 *This ); const D3DCAPS9 * NineDevice9_GetCaps( struct NineDevice9 *This ); -/* Mask: 0x1 = constant buffers, 0x2 = stipple */ -void -NineDevice9_RestoreNonCSOState( struct NineDevice9 *This, unsigned mask ); - /*** Direct3D public ***/ HRESULT WINAPI diff --git a/src/gallium/state_trackers/nine/nine_ff.c b/src/gallium/state_trackers/nine/nine_ff.c index 8a53f0d9038..fe8933be69a 100644 --- a/src/gallium/state_trackers/nine/nine_ff.c +++ b/src/gallium/state_trackers/nine/nine_ff.c @@ -22,6 +22,7 @@ #include "tgsi/tgsi_dump.h" #include "util/u_box.h" #include "util/u_hash_table.h" +#include "util/u_upload_mgr.h" #define NINE_TGSI_LAZY_DEVS 1 @@ -30,13 +31,6 @@ #define NINE_FF_NUM_VS_CONST 256 #define NINE_FF_NUM_PS_CONST 24 -#define NINED3DTSS_TCI_DISABLE 0 -#define NINED3DTSS_TCI_PASSTHRU 1 -#define NINED3DTSS_TCI_CAMERASPACENORMAL 2 -#define NINED3DTSS_TCI_CAMERASPACEPOSITION 3 -#define NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR 4 -#define NINED3DTSS_TCI_SPHEREMAP 5 - struct fvec4 { float x, y, z, w; @@ -63,16 +57,20 @@ struct nine_ff_vs_key uint32_t fog_range : 1; uint32_t color0in_one : 1; uint32_t color1in_one : 1; - uint32_t pad1 : 8; - uint32_t tc_gen : 24; /* 8 * 3 bits */ - uint32_t pad2 : 8; - uint32_t tc_idx : 24; + uint32_t fog : 1; + uint32_t pad1 : 7; + uint32_t tc_dim_input: 16; /* 8 * 2 bits */ + uint32_t pad2 : 16; + uint32_t tc_dim_output: 24; /* 8 * 3 bits */ uint32_t pad3 : 8; - uint32_t tc_dim : 24; /* 8 * 3 bits */ + uint32_t tc_gen : 24; /* 8 * 3 bits */ uint32_t pad4 : 8; + uint32_t tc_idx : 24; + uint32_t pad5 : 8; + uint32_t passthrough; }; - uint64_t value64[2]; /* don't forget to resize VertexShader9.ff_key */ - uint32_t value32[4]; + uint64_t value64[3]; /* don't forget to resize VertexShader9.ff_key */ + uint32_t value32[6]; }; }; @@ -106,15 +104,18 @@ struct nine_ff_ps_key uint32_t alphaarg2 : 3; uint32_t resultarg : 1; /* CURRENT:0 or TEMP:1 */ uint32_t textarget : 2; /* 1D/2D/3D/CUBE */ - uint32_t projected : 1; + uint32_t pad : 1; /* that's 32 bit exactly */ } ts[8]; - uint32_t fog : 1; /* for vFog with programmable VS */ + uint32_t projected : 16; + uint32_t fog : 1; /* for vFog coming from VS */ uint32_t fog_mode : 2; - uint32_t specular : 1; /* 9 32-bit words with this */ + uint32_t specular : 1; + uint32_t pad1 : 12; /* 9 32-bit words with this */ uint8_t colorarg_b4[3]; uint8_t colorarg_b5[3]; uint8_t alphaarg_b4[3]; /* 11 32-bit words plus a byte */ + uint8_t pad2[3]; }; uint64_t value64[6]; /* don't forget to resize PixelShader9.ff_key */ uint32_t value32[12]; @@ -222,7 +223,6 @@ static void nine_ureg_tgsi_dump(struct ureg_program *ureg, boolean override) * CONST[28].x___ RS.FogEnd * CONST[28]._y__ 1.0f / (RS.FogEnd - RS.FogStart) * CONST[28].__z_ RS.FogDensity - * CONST[29] RS.FogColor * CONST[30].x___ TWEENFACTOR * @@ -334,16 +334,15 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) { const struct nine_ff_vs_key *key = vs->key; struct ureg_program *ureg = ureg_create(TGSI_PROCESSOR_VERTEX); - struct ureg_dst oPos, oCol[2], oTex[8], oPsz, oFog; - struct ureg_dst rCol[2]; /* oCol if no fog, TEMP otherwise */ + struct ureg_dst oPos, oCol[2], oPsz, oFog; struct ureg_dst rVtx, rNrm; struct ureg_dst r[8]; struct ureg_dst AR; - struct ureg_dst tmp, tmp_x, tmp_z; + struct ureg_dst tmp, tmp_x, tmp_y, tmp_z; unsigned i, c; unsigned label[32], l = 0; unsigned num_r = 8; - boolean need_rNrm = key->lighting || key->pointscale; + boolean need_rNrm = key->lighting || key->pointscale || key->passthrough & (1 << NINE_DECLUSAGE_NORMAL); boolean need_rVtx = key->lighting || key->fog_mode; const unsigned texcoord_sn = get_texcoord_sn(device->screen); @@ -406,9 +405,9 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) if (key->vertexpointsize) vs->aPsz = build_vs_add_input(vs, NINE_DECLUSAGE_PSIZE); - if (key->vertexblend_indexed) + if (key->vertexblend_indexed || key->passthrough & (1 << NINE_DECLUSAGE_BLENDINDICES)) vs->aInd = build_vs_add_input(vs, NINE_DECLUSAGE_BLENDINDICES); - if (key->vertexblend) + if (key->vertexblend || key->passthrough & (1 << NINE_DECLUSAGE_BLENDWEIGHT)) vs->aWgt = build_vs_add_input(vs, NINE_DECLUSAGE_BLENDWEIGHT); if (key->vertextween) { vs->aVtx1 = build_vs_add_input(vs, NINE_DECLUSAGE_i(POSITION,1)); @@ -420,19 +419,16 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) oPos = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); /* HPOS */ oCol[0] = ureg_saturate(ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0)); oCol[1] = ureg_saturate(ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 1)); + if (key->fog || key->passthrough & (1 << NINE_DECLUSAGE_FOG)) { + oFog = ureg_DECL_output(ureg, TGSI_SEMANTIC_FOG, 0); + oFog = ureg_writemask(oFog, TGSI_WRITEMASK_X); + } if (key->vertexpointsize || key->pointscale) { oPsz = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_PSIZE, 0, TGSI_WRITEMASK_X, 0, 1); oPsz = ureg_writemask(oPsz, TGSI_WRITEMASK_X); } - if (key->fog_mode) { - /* We apply fog to the vertex colors, oFog is for programmable shaders only ? - */ - oFog = ureg_DECL_output_masked(ureg, TGSI_SEMANTIC_FOG, 0, - TGSI_WRITEMASK_X, 0, 1); - oFog = ureg_writemask(oFog, TGSI_WRITEMASK_X); - } /* Declare TEMPs: */ @@ -440,18 +436,11 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) r[i] = ureg_DECL_local_temporary(ureg); tmp = r[0]; tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X); + tmp_y = ureg_writemask(tmp, TGSI_WRITEMASK_Y); tmp_z = ureg_writemask(tmp, TGSI_WRITEMASK_Z); if (key->lighting || key->vertexblend) AR = ureg_DECL_address(ureg); - if (key->fog_mode) { - rCol[0] = r[2]; - rCol[1] = r[3]; - } else { - rCol[0] = oCol[0]; - rCol[1] = oCol[1]; - } - rVtx = ureg_writemask(r[1], TGSI_WRITEMASK_XYZ); rNrm = ureg_writemask(r[2], TGSI_WRITEMASK_XYZ); @@ -560,8 +549,6 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) ureg_CLAMP(ureg, oPsz, vs->aPsz, _XXXX(cPsz1), _YYYY(cPsz1)); #endif } else if (key->pointscale) { - struct ureg_dst tmp_x = ureg_writemask(tmp, TGSI_WRITEMASK_X); - struct ureg_dst tmp_y = ureg_writemask(tmp, TGSI_WRITEMASK_Y); struct ureg_src cPsz1 = ureg_DECL_constant(ureg, 26); struct ureg_src cPsz2 = ureg_DECL_constant(ureg, 27); @@ -582,72 +569,85 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) #endif } - /* Texture coordinate generation: - * XXX: D3DTTFF_PROJECTED, transform matrix - */ for (i = 0; i < 8; ++i) { - struct ureg_dst dst[5]; - struct ureg_src src; - unsigned c; + struct ureg_dst oTex, input_coord, transformed, t; + unsigned c, writemask; const unsigned tci = (key->tc_gen >> (i * 3)) & 0x7; const unsigned idx = (key->tc_idx >> (i * 3)) & 0x7; - const unsigned dim = (key->tc_dim >> (i * 3)) & 0x7; + unsigned dim_input = 1 + ((key->tc_dim_input >> (i * 2)) & 0x3); + const unsigned dim_output = (key->tc_dim_output >> (i * 3)) & 0x7; + /* No texture output of index s */ if (tci == NINED3DTSS_TCI_DISABLE) continue; - oTex[i] = ureg_DECL_output(ureg, texcoord_sn, i); - - if (tci == NINED3DTSS_TCI_PASSTHRU) - vs->aTex[idx] = build_vs_add_input(vs, NINE_DECLUSAGE_i(TEXCOORD,idx)); - - if (!dim) { - dst[c = 4] = oTex[i]; - } else { - dst[4] = r[5]; - src = ureg_src(dst[4]); - for (c = 0; c < (dim - 1); ++c) - dst[c] = ureg_writemask(tmp, (1 << dim) - 1); - dst[c] = ureg_writemask(oTex[i], (1 << dim) - 1); - } + oTex = ureg_DECL_output(ureg, texcoord_sn, i); + input_coord = r[5]; + transformed = r[6]; + /* Get the coordinate */ switch (tci) { case NINED3DTSS_TCI_PASSTHRU: - ureg_MOV(ureg, dst[4], vs->aTex[idx]); + /* NINED3DTSS_TCI_PASSTHRU => Use texcoord coming from index idx * + * Else the idx is used only to determine wrapping mode. */ + vs->aTex[idx] = build_vs_add_input(vs, NINE_DECLUSAGE_i(TEXCOORD,idx)); + ureg_MOV(ureg, input_coord, vs->aTex[idx]); break; case NINED3DTSS_TCI_CAMERASPACENORMAL: - assert(dim <= 3); - ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_XYZ), ureg_src(rNrm)); - ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_XYZ), ureg_src(rNrm)); + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + dim_input = 4; break; case NINED3DTSS_TCI_CAMERASPACEPOSITION: - ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_XYZ), ureg_src(rVtx)); - ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_XYZ), ureg_src(rVtx)); + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + dim_input = 4; break; case NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR: tmp.WriteMask = TGSI_WRITEMASK_XYZ; ureg_DP3(ureg, tmp_x, ureg_src(rVtx), ureg_src(rNrm)); ureg_MUL(ureg, tmp, ureg_src(rNrm), _X(tmp)); ureg_ADD(ureg, tmp, ureg_src(tmp), ureg_src(tmp)); - ureg_SUB(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_XYZ), ureg_src(rVtx), ureg_src(tmp)); - ureg_MOV(ureg, ureg_writemask(dst[4], TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + ureg_SUB(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_XYZ), ureg_src(rVtx), ureg_src(tmp)); + ureg_MOV(ureg, ureg_writemask(input_coord, TGSI_WRITEMASK_W), ureg_imm1f(ureg, 1.0f)); + dim_input = 4; tmp.WriteMask = TGSI_WRITEMASK_XYZW; break; case NINED3DTSS_TCI_SPHEREMAP: assert(!"TODO"); break; default: + assert(0); break; } - if (!dim) - continue; - dst[c].WriteMask = ~dst[c].WriteMask; - if (dst[c].WriteMask) - ureg_MOV(ureg, dst[c], src); /* store untransformed components */ - dst[c].WriteMask = ~dst[c].WriteMask; - if (dim > 0) ureg_MUL(ureg, dst[0], _XXXX(src), _CONST(128 + i * 4)); - if (dim > 1) ureg_MAD(ureg, dst[1], _YYYY(src), _CONST(129 + i * 4), ureg_src(tmp)); - if (dim > 2) ureg_MAD(ureg, dst[2], _ZZZZ(src), _CONST(130 + i * 4), ureg_src(tmp)); - if (dim > 3) ureg_MAD(ureg, dst[3], _WWWW(src), _CONST(131 + i * 4), ureg_src(tmp)); + + /* Apply the transformation */ + /* dim_output == 0 => do not transform the components. + * XYZRHW also disables transformation */ + if (!dim_output || key->position_t) { + transformed = input_coord; + writemask = TGSI_WRITEMASK_XYZW; + } else { + for (c = 0; c < dim_output; c++) { + t = ureg_writemask(transformed, 1 << c); + switch (dim_input) { + /* dim_input = 1 2 3: -> we add trailing 1 to input*/ + case 1: ureg_MAD(ureg, t, _X(input_coord), _XXXX(_CONST(128 + i * 4 + c)), _YYYY(_CONST(128 + i * 4 + c))); + break; + case 2: ureg_DP2(ureg, t, ureg_src(input_coord), _CONST(128 + i * 4 + c)); + ureg_ADD(ureg, t, ureg_src(transformed), _ZZZZ(_CONST(128 + i * 4 + c))); + break; + case 3: ureg_DP3(ureg, t, ureg_src(input_coord), _CONST(128 + i * 4 + c)); + ureg_ADD(ureg, t, ureg_src(transformed), _WWWW(_CONST(128 + i * 4 + c))); + break; + case 4: ureg_DP4(ureg, t, ureg_src(input_coord), _CONST(128 + i * 4 + c)); break; + default: + assert(0); + } + } + writemask = (1 << dim_output) - 1; + } + + ureg_MOV(ureg, ureg_writemask(oTex, writemask), ureg_src(transformed)); } /* === Lighting: @@ -692,8 +692,6 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) * specular += light.specular * atten * powFact; */ if (key->lighting) { - struct ureg_dst tmp_y = ureg_writemask(tmp, TGSI_WRITEMASK_Y); - struct ureg_dst rAtt = ureg_writemask(r[1], TGSI_WRITEMASK_W); struct ureg_dst rHit = ureg_writemask(r[3], TGSI_WRITEMASK_XYZ); struct ureg_dst rMid = ureg_writemask(r[4], TGSI_WRITEMASK_XYZ); @@ -851,22 +849,22 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ), vs->mtlA, ureg_src(tmp), vs->mtlE); ureg_ADD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_W ), vs->mtlA, vs->mtlE); } - ureg_MAD(ureg, rCol[0], ureg_src(rD), vs->mtlD, ureg_src(tmp)); - ureg_MUL(ureg, rCol[1], ureg_src(rS), vs->mtlS); + ureg_MAD(ureg, oCol[0], ureg_src(rD), vs->mtlD, ureg_src(tmp)); + ureg_MUL(ureg, oCol[1], ureg_src(rS), vs->mtlS); } else /* COLOR */ if (key->darkness) { if (key->mtl_emissive == 0 && key->mtl_ambient == 0) { - ureg_MAD(ureg, rCol[0], vs->mtlD, ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f), _CONST(19)); + ureg_MAD(ureg, oCol[0], vs->mtlD, ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f), _CONST(19)); } else { - ureg_MAD(ureg, ureg_writemask(rCol[0], TGSI_WRITEMASK_XYZ), vs->mtlA, _CONST(25), vs->mtlE); + ureg_MAD(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_XYZ), vs->mtlA, _CONST(25), vs->mtlE); ureg_ADD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_W), vs->mtlA, vs->mtlE); - ureg_ADD(ureg, ureg_writemask(rCol[0], TGSI_WRITEMASK_W), vs->mtlD, _W(tmp)); + ureg_ADD(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_W), vs->mtlD, _W(tmp)); } - ureg_MUL(ureg, rCol[1], ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f), vs->mtlS); + ureg_MUL(ureg, oCol[1], ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f), vs->mtlS); } else { - ureg_MOV(ureg, rCol[0], vs->aCol[0]); - ureg_MOV(ureg, rCol[1], vs->aCol[1]); + ureg_MOV(ureg, oCol[0], vs->aCol[0]); + ureg_MOV(ureg, oCol[1], vs->aCol[1]); } /* === Process fog. @@ -874,10 +872,6 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) * exp(x) = ex2(log2(e) * x) */ if (key->fog_mode) { - /* Fog doesn't affect alpha, TODO: combine with light code output */ - ureg_MOV(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_W), _W(rCol[0])); - ureg_MOV(ureg, ureg_writemask(oCol[1], TGSI_WRITEMASK_W), _W(rCol[1])); - if (key->position_t) { ureg_MOV(ureg, ureg_saturate(tmp_x), ureg_scalar(vs->aCol[1], TGSI_SWIZZLE_W)); } else @@ -905,10 +899,58 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs) ureg_MUL(ureg, ureg_saturate(tmp_x), _X(tmp), _YYYY(_CONST(28))); } ureg_MOV(ureg, oFog, _X(tmp)); - ureg_LRP(ureg, ureg_writemask(oCol[0], TGSI_WRITEMASK_XYZ), _X(tmp), ureg_src(rCol[0]), _CONST(29)); - ureg_LRP(ureg, ureg_writemask(oCol[1], TGSI_WRITEMASK_XYZ), _X(tmp), ureg_src(rCol[1]), _CONST(29)); + } else if (key->fog && !(key->passthrough & (1 << NINE_DECLUSAGE_FOG))) { + ureg_MOV(ureg, oFog, ureg_scalar(vs->aCol[1], TGSI_SWIZZLE_W)); } + if (key->passthrough & (1 << NINE_DECLUSAGE_BLENDWEIGHT)) { + struct ureg_src input; + struct ureg_dst output; + input = vs->aWgt; + output = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 18); + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_BLENDINDICES)) { + struct ureg_src input; + struct ureg_dst output; + input = vs->aInd; + output = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 19); + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_NORMAL)) { + struct ureg_src input; + struct ureg_dst output; + input = vs->aNrm; + output = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 20); + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_TANGENT)) { + struct ureg_src input; + struct ureg_dst output; + input = build_vs_add_input(vs, NINE_DECLUSAGE_TANGENT); + output = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 21); + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_BINORMAL)) { + struct ureg_src input; + struct ureg_dst output; + input = build_vs_add_input(vs, NINE_DECLUSAGE_BINORMAL); + output = ureg_DECL_output(ureg, TGSI_SEMANTIC_GENERIC, 22); + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_FOG)) { + struct ureg_src input; + struct ureg_dst output; + input = build_vs_add_input(vs, NINE_DECLUSAGE_FOG); + input = ureg_scalar(input, TGSI_SWIZZLE_X); + output = oFog; + ureg_MOV(ureg, output, input); + } + if (key->passthrough & (1 << NINE_DECLUSAGE_DEPTH)) { + (void) 0; /* TODO: replace z of position output ? */ + } + + if (key->position_t && device->driver_caps.window_space_position_support) ureg_property(ureg, TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION, TRUE); @@ -1270,10 +1312,18 @@ nine_ff_build_ps(struct NineDevice9 *device, struct nine_ff_ps_key *key) if (key->ts[s].colorop == D3DTOP_BUMPENVMAP || key->ts[s].colorop == D3DTOP_BUMPENVMAPLUMINANCE) { } - if (key->ts[s].projected) - ureg_TXP(ureg, ps.rTex, target, ps.vT[s], ps.s[s]); - else + if (key->projected & (3 << (s *2))) { + unsigned dim = 1 + ((key->projected >> (2 * s)) & 3); + if (dim == 4) + ureg_TXP(ureg, ps.rTex, target, ps.vT[s], ps.s[s]); + else { + ureg_RCP(ureg, ureg_writemask(ps.rTmp, TGSI_WRITEMASK_X), ureg_scalar(ps.vT[s], dim-1)); + ureg_MUL(ureg, ps.rTmp, _XXXX(ps.rTmpSrc), ps.vT[s]); + ureg_TEX(ureg, ps.rTex, target, ps.rTmpSrc, ps.s[s]); + } + } else { ureg_TEX(ureg, ps.rTex, target, ps.vT[s], ps.s[s]); + } } if (s == 0 && @@ -1316,6 +1366,10 @@ nine_ff_build_ps(struct NineDevice9 *device, struct nine_ff_ps_key *key) colorarg[2] != alphaarg[2]) dst.WriteMask = TGSI_WRITEMASK_XYZ; + /* Special DOTPRODUCT behaviour (see wine tests) */ + if (key->ts[s].colorop == D3DTOP_DOTPRODUCT3) + dst.WriteMask = TGSI_WRITEMASK_XYZW; + if (used_c & 0x1) arg[0] = ps_get_ts_arg(&ps, colorarg[0]); if (used_c & 0x2) arg[1] = ps_get_ts_arg(&ps, colorarg[1]); if (used_c & 0x4) arg[2] = ps_get_ts_arg(&ps, colorarg[2]); @@ -1406,12 +1460,18 @@ nine_ff_get_vs(struct NineDevice9 *device) else if (usage % NINE_DECLUSAGE_COUNT == NINE_DECLUSAGE_TEXCOORD) { s = usage / NINE_DECLUSAGE_COUNT; if (s < 8) - input_texture_coord[s] = 1; + input_texture_coord[s] = nine_decltype_get_dim(state->vdecl->decls[i].Type); else DBG("FF given texture coordinate >= 8. Ignoring\n"); - } + } else if (usage < NINE_DECLUSAGE_NONE) + key.passthrough |= 1 << usage; } } + /* ff vs + ps 3.0: some elements are passed to the ps (wine test). + * We do restrict to indices 0 */ + key.passthrough &= ~((1 << NINE_DECLUSAGE_POSITION) | (1 << NINE_DECLUSAGE_PSIZE) | + (1 << NINE_DECLUSAGE_TEXCOORD) | (1 << NINE_DECLUSAGE_POSITIONT) | + (1 << NINE_DECLUSAGE_TESSFACTOR) | (1 << NINE_DECLUSAGE_SAMPLE)); if (!key.vertexpointsize) key.pointscale = !!state->rs[D3DRS_POINTSCALEENABLE]; @@ -1427,6 +1487,7 @@ nine_ff_get_vs(struct NineDevice9 *device) key.mtl_specular = state->rs[D3DRS_SPECULARMATERIALSOURCE]; key.mtl_emissive = state->rs[D3DRS_EMISSIVEMATERIALSOURCE]; } + key.fog = !!state->rs[D3DRS_FOGENABLE]; key.fog_mode = state->rs[D3DRS_FOGENABLE] ? state->rs[D3DRS_FOGVERTEXMODE] : 0; if (key.fog_mode) key.fog_range = !key.position_t && state->rs[D3DRS_RANGEFOGENABLE]; @@ -1448,7 +1509,7 @@ nine_ff_get_vs(struct NineDevice9 *device) for (s = 0; s < 8; ++s) { unsigned gen = (state->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] >> 16) + 1; - unsigned dim = MIN2(state->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & 0x7, 4); + unsigned dim; if (key.position_t && gen > NINED3DTSS_TCI_PASSTHRU) gen = NINED3DTSS_TCI_PASSTHRU; @@ -1458,7 +1519,14 @@ nine_ff_get_vs(struct NineDevice9 *device) key.tc_gen |= gen << (s * 3); key.tc_idx |= (state->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] & 7) << (s * 3); - key.tc_dim |= dim << (s * 3); + key.tc_dim_input |= ((input_texture_coord[s]-1) & 0x3) << (s * 2); + + dim = state->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & 0x7; + if (dim > 4) + dim = input_texture_coord[s]; + if (dim == 1) /* NV behaviour */ + dim = 0; + key.tc_dim_output |= dim << (s * 3); } vs = util_hash_table_get(device->ff.ht_vs, &key); @@ -1473,6 +1541,7 @@ nine_ff_get_vs(struct NineDevice9 *device) memcpy(&vs->ff_key, &key, sizeof(vs->ff_key)); err = util_hash_table_set(device->ff.ht_vs, &vs->ff_key, vs); + (void)err; assert(err == PIPE_OK); device->ff.num_vs++; NineUnknown_ConvertRefToBind(NineUnknown(vs)); @@ -1543,8 +1612,6 @@ nine_ff_get_ps(struct NineDevice9 *device) } key.ts[s].resultarg = state->ff.tex_stage[s][D3DTSS_RESULTARG] == D3DTA_TEMP; - key.ts[s].projected = !!(state->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED); - if (state->texture[s]) { switch (state->texture[s]->base.type) { case D3DRTYPE_TEXTURE: key.ts[s].textarget = 1; break; @@ -1558,10 +1625,14 @@ nine_ff_get_ps(struct NineDevice9 *device) key.ts[s].textarget = 1; } } + + key.projected = nine_ff_get_projected_key(state); + for (; s < 8; ++s) key.ts[s].colorop = key.ts[s].alphaop = D3DTOP_DISABLE; if (state->rs[D3DRS_FOGENABLE]) key.fog_mode = state->rs[D3DRS_FOGTABLEMODE]; + key.fog = !!state->rs[D3DRS_FOGENABLE]; ps = util_hash_table_get(device->ff.ht_ps, &key); if (ps) @@ -1573,6 +1644,7 @@ nine_ff_get_ps(struct NineDevice9 *device) memcpy(&ps->ff_key, &key, sizeof(ps->ff_key)); err = util_hash_table_set(device->ff.ht_ps, &ps->ff_key, ps); + (void)err; assert(err == PIPE_OK); device->ff.num_ps++; NineUnknown_ConvertRefToBind(NineUnknown(ps)); @@ -1689,7 +1761,6 @@ nine_ff_load_point_and_fog_params(struct NineDevice9 *device) if (isinf(dst[28].y)) dst[28].y = 0.0f; dst[28].z = asfloat(state->rs[D3DRS_FOGDENSITY]); - d3dcolor_to_rgba(&dst[29].x, state->rs[D3DRS_FOGCOLOR]); } static void @@ -1703,7 +1774,7 @@ nine_ff_load_tex_matrices(struct NineDevice9 *device) return; for (s = 0; s < 8; ++s) { if (IS_D3DTS_DIRTY(state, TEXTURE0 + s)) - M[32 + s] = *nine_state_access_transform(state, D3DTS_TEXTURE0 + s, FALSE); + nine_d3d_matrix_transpose(&M[32 + s], nine_state_access_transform(state, D3DTS_TEXTURE0 + s, FALSE)); } } @@ -1762,28 +1833,22 @@ nine_ff_load_viewport_info(struct NineDevice9 *device) void nine_ff_update(struct NineDevice9 *device) { - struct pipe_context *pipe = device->pipe; struct nine_state *state = &device->state; + struct pipe_constant_buffer cb; DBG("vs=%p ps=%p\n", device->state.vs, device->state.ps); /* NOTE: the only reference belongs to the hash table */ - if (!device->state.vs) + if (!device->state.vs) { device->ff.vs = nine_ff_get_vs(device); - if (!device->state.ps) + device->state.changed.group |= NINE_STATE_VS; + } + if (!device->state.ps) { device->ff.ps = nine_ff_get_ps(device); + device->state.changed.group |= NINE_STATE_PS; + } if (!device->state.vs) { - if (device->state.ff.clobber.vs_const) { - device->state.ff.clobber.vs_const = FALSE; - device->state.changed.group |= - NINE_STATE_FF_VSTRANSF | - NINE_STATE_FF_MATERIAL | - NINE_STATE_FF_LIGHTING | - NINE_STATE_FF_OTHER; - device->state.ff.changed.transform[0] |= 0xff000c; - device->state.ff.changed.transform[8] |= 0xff; - } nine_ff_load_vs_transforms(device); nine_ff_load_tex_matrices(device); nine_ff_load_lights(device); @@ -1792,57 +1857,45 @@ nine_ff_update(struct NineDevice9 *device) memset(state->ff.changed.transform, 0, sizeof(state->ff.changed.transform)); - device->state.changed.group |= NINE_STATE_VS; - device->state.changed.group |= NINE_STATE_VS_CONST; - - if (device->prefer_user_constbuf) { - struct pipe_context *pipe = device->pipe; - struct pipe_constant_buffer cb; - cb.buffer_offset = 0; - cb.buffer = NULL; - cb.user_buffer = device->ff.vs_const; - cb.buffer_size = NINE_FF_NUM_VS_CONST * 4 * sizeof(float); - pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &cb); - } else { - struct pipe_box box; - u_box_1d(0, NINE_FF_NUM_VS_CONST * 4 * sizeof(float), &box); - pipe->transfer_inline_write(pipe, device->constbuf_vs, 0, - 0, &box, - device->ff.vs_const, 0, 0); - nine_ranges_insert(&device->state.changed.vs_const_f, 0, NINE_FF_NUM_VS_CONST, - &device->range_pool); + cb.buffer_offset = 0; + cb.buffer = NULL; + cb.user_buffer = device->ff.vs_const; + cb.buffer_size = NINE_FF_NUM_VS_CONST * 4 * sizeof(float); + + if (!device->driver_caps.user_cbufs) { + u_upload_data(device->constbuf_uploader, + 0, + cb.buffer_size, + cb.user_buffer, + &cb.buffer_offset, + &cb.buffer); + u_upload_unmap(device->constbuf_uploader); + cb.user_buffer = NULL; } + state->pipe.cb_vs_ff = cb; + state->commit |= NINE_STATE_COMMIT_CONST_VS; } if (!device->state.ps) { - if (device->state.ff.clobber.ps_const) { - device->state.ff.clobber.ps_const = FALSE; - device->state.changed.group |= - NINE_STATE_FF_PSSTAGES | - NINE_STATE_FF_OTHER; - } nine_ff_load_ps_params(device); - device->state.changed.group |= NINE_STATE_PS; - device->state.changed.group |= NINE_STATE_PS_CONST; - - if (device->prefer_user_constbuf) { - struct pipe_context *pipe = device->pipe; - struct pipe_constant_buffer cb; - cb.buffer_offset = 0; - cb.buffer = NULL; - cb.user_buffer = device->ff.ps_const; - cb.buffer_size = NINE_FF_NUM_PS_CONST * 4 * sizeof(float); - pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &cb); - } else { - struct pipe_box box; - u_box_1d(0, NINE_FF_NUM_PS_CONST * 4 * sizeof(float), &box); - pipe->transfer_inline_write(pipe, device->constbuf_ps, 0, - 0, &box, - device->ff.ps_const, 0, 0); - nine_ranges_insert(&device->state.changed.ps_const_f, 0, NINE_FF_NUM_PS_CONST, - &device->range_pool); + cb.buffer_offset = 0; + cb.buffer = NULL; + cb.user_buffer = device->ff.ps_const; + cb.buffer_size = NINE_FF_NUM_PS_CONST * 4 * sizeof(float); + + if (!device->driver_caps.user_cbufs) { + u_upload_data(device->constbuf_uploader, + 0, + cb.buffer_size, + cb.user_buffer, + &cb.buffer_offset, + &cb.buffer); + u_upload_unmap(device->constbuf_uploader); + cb.user_buffer = NULL; } + state->pipe.cb_ps_ff = cb; + state->commit |= NINE_STATE_COMMIT_CONST_PS; } device->state.changed.group &= ~NINE_STATE_FF; diff --git a/src/gallium/state_trackers/nine/nine_ff.h b/src/gallium/state_trackers/nine/nine_ff.h index 7cefa65b1c4..9c33c76370d 100644 --- a/src/gallium/state_trackers/nine/nine_ff.h +++ b/src/gallium/state_trackers/nine/nine_ff.h @@ -3,6 +3,7 @@ #define _NINE_FF_H_ #include "device9.h" +#include "vertexdeclaration9.h" boolean nine_ff_init(struct NineDevice9 *); void nine_ff_fini(struct NineDevice9 *); @@ -29,4 +30,84 @@ nine_d3d_matrix_inverse_3x3(D3DMATRIX *, const D3DMATRIX *); void nine_d3d_matrix_transpose(D3DMATRIX *, const D3DMATRIX *); +#define NINED3DTSS_TCI_DISABLE 0 +#define NINED3DTSS_TCI_PASSTHRU 1 +#define NINED3DTSS_TCI_CAMERASPACENORMAL 2 +#define NINED3DTSS_TCI_CAMERASPACEPOSITION 3 +#define NINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR 4 +#define NINED3DTSS_TCI_SPHEREMAP 5 + +static inline unsigned +nine_decltype_get_dim(BYTE type) +{ + switch (type) { + case D3DDECLTYPE_FLOAT1: return 1; + case D3DDECLTYPE_FLOAT2: return 2; + case D3DDECLTYPE_FLOAT3: return 3; + case D3DDECLTYPE_FLOAT4: return 4; + case D3DDECLTYPE_D3DCOLOR: return 1; + case D3DDECLTYPE_UBYTE4: return 4; + case D3DDECLTYPE_SHORT2: return 2; + case D3DDECLTYPE_SHORT4: return 4; + case D3DDECLTYPE_UBYTE4N: return 4; + case D3DDECLTYPE_SHORT2N: return 2; + case D3DDECLTYPE_SHORT4N: return 4; + case D3DDECLTYPE_USHORT2N: return 2; + case D3DDECLTYPE_USHORT4N: return 4; + case D3DDECLTYPE_UDEC3: return 3; + case D3DDECLTYPE_DEC3N: return 3; + case D3DDECLTYPE_FLOAT16_2: return 2; + case D3DDECLTYPE_FLOAT16_4: return 4; + default: + assert(!"Implementation error !"); + } + return 0; +} + +static inline uint16_t +nine_ff_get_projected_key(struct nine_state *state) +{ + unsigned s, i; + uint16_t projected = 0; + char input_texture_coord[8]; + memset(&input_texture_coord, 0, sizeof(input_texture_coord)); + + if (state->vdecl) { + for (i = 0; i < state->vdecl->nelems; i++) { + uint16_t usage = state->vdecl->usage_map[i]; + if (usage % NINE_DECLUSAGE_COUNT == NINE_DECLUSAGE_TEXCOORD) { + s = usage / NINE_DECLUSAGE_COUNT; + if (s < 8) + input_texture_coord[s] = nine_decltype_get_dim(state->vdecl->decls[i].Type); + } + } + } + + for (s = 0; s < 8; ++s) { + unsigned gen = (state->ff.tex_stage[s][D3DTSS_TEXCOORDINDEX] >> 16) + 1; + unsigned dim = state->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & 0x7; + unsigned proj = !!(state->ff.tex_stage[s][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED); + + if (!state->vs) { + if (dim > 4) + dim = input_texture_coord[s]; + + if (!dim && gen == NINED3DTSS_TCI_PASSTHRU) + dim = input_texture_coord[s]; + else if (!dim) + dim = 4; + + if (dim == 1) /* NV behaviour */ + proj = 0; + if (dim > input_texture_coord[s] && gen == NINED3DTSS_TCI_PASSTHRU) + proj = 0; + } else { + dim = 4; + } + if (proj) + projected |= (dim-1) << (2 * s); + } + return projected; +} + #endif /* _NINE_FF_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_pipe.c b/src/gallium/state_trackers/nine/nine_pipe.c index 4cf37b9f59c..2be30f7e097 100644 --- a/src/gallium/state_trackers/nine/nine_pipe.c +++ b/src/gallium/state_trackers/nine/nine_pipe.c @@ -27,7 +27,8 @@ #include "cso_cache/cso_context.h" void -nine_convert_dsa_state(struct cso_context *ctx, const DWORD *rs) +nine_convert_dsa_state(struct pipe_depth_stencil_alpha_state *dsa_state, + const DWORD *rs) { struct pipe_depth_stencil_alpha_state dsa; @@ -65,16 +66,15 @@ nine_convert_dsa_state(struct cso_context *ctx, const DWORD *rs) dsa.alpha.ref_value = (float)rs[D3DRS_ALPHAREF] / 255.0f; } - cso_set_depth_stencil_alpha(ctx, &dsa); + *dsa_state = dsa; } -/* TODO: Keep a static copy in device so we don't have to memset every time ? */ void -nine_convert_rasterizer_state(struct cso_context *ctx, const DWORD *rs) +nine_convert_rasterizer_state(struct pipe_rasterizer_state *rast_state, const DWORD *rs) { struct pipe_rasterizer_state rast; - memset(&rast, 0, sizeof(rast)); /* memcmp safety */ + memset(&rast, 0, sizeof(rast)); rast.flatshade = rs[D3DRS_SHADEMODE] == D3DSHADE_FLAT; /* rast.light_twoside = 0; */ @@ -92,7 +92,7 @@ nine_convert_rasterizer_state(struct cso_context *ctx, const DWORD *rs) /* rast.poly_stipple_enable = 0; */ /* rast.point_smooth = 0; */ rast.sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT; - rast.point_quad_rasterization = !!rs[D3DRS_POINTSPRITEENABLE]; + rast.point_quad_rasterization = 1; rast.point_size_per_vertex = rs[NINED3DRS_VSPOINTSIZE]; rast.multisample = !!rs[D3DRS_MULTISAMPLEANTIALIAS]; rast.line_smooth = !!rs[D3DRS_ANTIALIASEDLINEENABLE]; @@ -110,12 +110,28 @@ nine_convert_rasterizer_state(struct cso_context *ctx, const DWORD *rs) /* rast.line_stipple_pattern = 0; */ rast.sprite_coord_enable = rs[D3DRS_POINTSPRITEENABLE] ? 0xff : 0x00; rast.line_width = 1.0f; - rast.point_size = rs[NINED3DRS_VSPOINTSIZE] ? 1.0f : asfloat(rs[D3DRS_POINTSIZE]); /* XXX: D3DRS_POINTSIZE_MIN/MAX */ - rast.offset_units = asfloat(rs[D3DRS_DEPTHBIAS]) * asfloat(rs[NINED3DRS_ZBIASSCALE]); + if (rs[NINED3DRS_VSPOINTSIZE]) { + rast.point_size = 1.0f; + } else { + rast.point_size = CLAMP(asfloat(rs[D3DRS_POINTSIZE]), + asfloat(rs[D3DRS_POINTSIZE_MIN]), + asfloat(rs[D3DRS_POINTSIZE_MAX])); + } + /* offset_units has the ogl/d3d11 meaning. + * d3d9: offset = scale * dz + bias + * ogl/d3d11: offset = scale * dz + r * bias + * with r implementation dependant and is supposed to be + * the smallest value the depth buffer format can hold. + * In practice on current and past hw it seems to be 2^-23 + * for all formats except float formats where it varies depending + * on the content. + * For now use 1 << 23, but in the future perhaps add a way in gallium + * to get r for the format or get the gallium behaviour */ + rast.offset_units = asfloat(rs[D3DRS_DEPTHBIAS]) * (float)(1 << 23); rast.offset_scale = asfloat(rs[D3DRS_SLOPESCALEDEPTHBIAS]); /* rast.offset_clamp = 0.0f; */ - cso_set_rasterizer(ctx, &rast); + *rast_state = rast; } static inline void @@ -137,7 +153,7 @@ nine_convert_blend_state_fixup(struct pipe_blend_state *blend, const DWORD *rs) } void -nine_convert_blend_state(struct cso_context *ctx, const DWORD *rs) +nine_convert_blend_state(struct pipe_blend_state *blend_state, const DWORD *rs) { struct pipe_blend_state blend; @@ -181,7 +197,7 @@ nine_convert_blend_state(struct cso_context *ctx, const DWORD *rs) /* blend.force_srgb = !!rs[D3DRS_SRGBWRITEENABLE]; */ - cso_set_blend(ctx, &blend); + *blend_state = blend; } void @@ -239,8 +255,8 @@ nine_pipe_context_clear(struct NineDevice9 *This) cso_set_samplers(cso, PIPE_SHADER_VERTEX, 0, NULL); cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 0, NULL); - pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 0, NULL); - pipe->set_sampler_views(pipe, PIPE_SHADER_VERTEX, 0, 0, NULL); + cso_set_sampler_views(cso, PIPE_SHADER_VERTEX, 0, NULL); + cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, 0, NULL); pipe->set_vertex_buffers(pipe, 0, This->caps.MaxStreams, NULL); pipe->set_index_buffer(pipe, NULL); diff --git a/src/gallium/state_trackers/nine/nine_pipe.h b/src/gallium/state_trackers/nine/nine_pipe.h index 43a7737cdf9..86117866ed5 100644 --- a/src/gallium/state_trackers/nine/nine_pipe.h +++ b/src/gallium/state_trackers/nine/nine_pipe.h @@ -27,6 +27,7 @@ #include "pipe/p_format.h" #include "pipe/p_screen.h" #include "pipe/p_state.h" /* pipe_box */ +#include "util/macros.h" #include "util/u_rect.h" #include "util/u_format.h" #include "nine_helpers.h" @@ -36,9 +37,9 @@ struct cso_context; extern const enum pipe_format nine_d3d9_to_pipe_format_map[120]; extern const D3DFORMAT nine_pipe_to_d3d9_format_map[PIPE_FORMAT_COUNT]; -void nine_convert_dsa_state(struct cso_context *, const DWORD *); -void nine_convert_rasterizer_state(struct cso_context *, const DWORD *); -void nine_convert_blend_state(struct cso_context *, const DWORD *); +void nine_convert_dsa_state(struct pipe_depth_stencil_alpha_state *, const DWORD *); +void nine_convert_rasterizer_state(struct pipe_rasterizer_state *, const DWORD *); +void nine_convert_blend_state(struct pipe_blend_state *, const DWORD *); void nine_convert_sampler_state(struct cso_context *, int idx, const DWORD *); void nine_pipe_context_clear(struct NineDevice9 *); @@ -81,6 +82,49 @@ rect_to_pipe_box(struct pipe_box *dst, const RECT *src) dst->depth = 1; } +static inline void +pipe_box_to_rect(RECT *dst, const struct pipe_box *src) +{ + dst->left = src->x; + dst->right = src->x + src->width; + dst->top = src->y; + dst->bottom = src->y + src->height; +} + +static inline void +rect_minify_inclusive(RECT *rect) +{ + rect->left = rect->left >> 2; + rect->top = rect->top >> 2; + rect->right = DIV_ROUND_UP(rect->right, 2); + rect->bottom = DIV_ROUND_UP(rect->bottom, 2); +} + +/* We suppose: + * 0 <= rect->left < rect->right + * 0 <= rect->top < rect->bottom + */ +static inline void +fit_rect_format_inclusive(enum pipe_format format, RECT *rect, int width, int height) +{ + const unsigned w = util_format_get_blockwidth(format); + const unsigned h = util_format_get_blockheight(format); + + if (util_format_is_compressed(format)) { + rect->left = rect->left - rect->left % w; + rect->top = rect->top - rect->top % h; + rect->right = (rect->right % w) == 0 ? + rect->right : + rect->right - (rect->right % w) + w; + rect->bottom = (rect->bottom % h) == 0 ? + rect->bottom : + rect->bottom - (rect->bottom % h) + h; + } + + rect->right = MIN2(rect->right, width); + rect->bottom = MIN2(rect->bottom, height); +} + static inline boolean rect_to_pipe_box_clamp(struct pipe_box *dst, const RECT *src) { @@ -164,6 +208,23 @@ pipe_to_d3d9_format(enum pipe_format format) return nine_pipe_to_d3d9_format_map[format]; } +/* ATI1 and ATI2 are not officially compressed in d3d9 */ +static inline boolean +compressed_format( D3DFORMAT fmt ) +{ + switch (fmt) { + case D3DFMT_DXT1: + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: + return TRUE; + default: + break; + } + return FALSE; +} + static inline boolean depth_stencil_format( D3DFORMAT fmt ) { diff --git a/src/gallium/state_trackers/nine/nine_shader.c b/src/gallium/state_trackers/nine/nine_shader.c index 754f5af6b8e..28f27870dc8 100644 --- a/src/gallium/state_trackers/nine/nine_shader.c +++ b/src/gallium/state_trackers/nine/nine_shader.c @@ -89,6 +89,15 @@ static inline const char *d3dsio_to_string(unsigned opcode); #define NINE_SWIZZLE4(x,y,z,w) \ TGSI_SWIZZLE_##x, TGSI_SWIZZLE_##y, TGSI_SWIZZLE_##z, TGSI_SWIZZLE_##w +#define NINE_CONSTANT_SRC(index) \ + ureg_src_register(TGSI_FILE_CONSTANT, index) + +#define NINE_APPLY_SWIZZLE(src, s) \ + ureg_swizzle(src, NINE_SWIZZLE4(s, s, s, s)) + +#define NINE_CONSTANT_SRC_SWIZZLE(index, s) \ + NINE_APPLY_SWIZZLE(NINE_CONSTANT_SRC(index), s) + #define NINED3DSPDM_SATURATE (D3DSPDM_SATURATE >> D3DSP_DSTMOD_SHIFT) #define NINED3DSPDM_PARTIALP (D3DSPDM_PARTIALPRECISION >> D3DSP_DSTMOD_SHIFT) #define NINED3DSPDM_CENTROID (D3DSPDM_MSAMPCENTROID >> D3DSP_DSTMOD_SHIFT) @@ -444,6 +453,9 @@ struct shader_translator BYTE minor; } version; unsigned processor; /* TGSI_PROCESSOR_VERTEX/FRAMGENT */ + unsigned num_constf_allowed; + unsigned num_consti_allowed; + unsigned num_constb_allowed; boolean native_integers; boolean inline_subroutines; @@ -505,7 +517,6 @@ struct shader_translator #define IS_VS (tx->processor == TGSI_PROCESSOR_VERTEX) #define IS_PS (tx->processor == TGSI_PROCESSOR_FRAGMENT) -#define NINE_MAX_CONST_F_SHADER (tx->processor == TGSI_PROCESSOR_VERTEX ? NINE_MAX_CONST_F : NINE_MAX_CONST_F_PS3) #define FAILURE_VOID(cond) if ((cond)) {tx->failure=1;return;} @@ -528,7 +539,7 @@ static boolean tx_lconstf(struct shader_translator *tx, struct ureg_src *src, INT index) { INT i; - if (index < 0 || index >= NINE_MAX_CONST_F_SHADER) { + if (index < 0 || index >= tx->num_constf_allowed) { tx->failure = TRUE; return FALSE; } @@ -543,7 +554,7 @@ tx_lconstf(struct shader_translator *tx, struct ureg_src *src, INT index) static boolean tx_lconsti(struct shader_translator *tx, struct ureg_src *src, INT index) { - if (index < 0 || index >= NINE_MAX_CONST_I) { + if (index < 0 || index >= tx->num_consti_allowed) { tx->failure = TRUE; return FALSE; } @@ -554,7 +565,7 @@ tx_lconsti(struct shader_translator *tx, struct ureg_src *src, INT index) static boolean tx_lconstb(struct shader_translator *tx, struct ureg_src *src, INT index) { - if (index < 0 || index >= NINE_MAX_CONST_B) { + if (index < 0 || index >= tx->num_constb_allowed) { tx->failure = TRUE; return FALSE; } @@ -568,9 +579,7 @@ tx_set_lconstf(struct shader_translator *tx, INT index, float f[4]) { unsigned n; - FAILURE_VOID(index < 0 || index >= NINE_MAX_CONST_F_SHADER) - if (IS_VS && index >= NINE_MAX_CONST_F_SHADER) - WARN("lconstf index %i too high, indirect access won't work\n", index); + FAILURE_VOID(index < 0 || index >= tx->num_constf_allowed) for (n = 0; n < tx->num_lconstf; ++n) if (tx->lconstf[n].idx == index) @@ -592,7 +601,7 @@ tx_set_lconstf(struct shader_translator *tx, INT index, float f[4]) static void tx_set_lconsti(struct shader_translator *tx, INT index, int i[4]) { - FAILURE_VOID(index < 0 || index >= NINE_MAX_CONST_I) + FAILURE_VOID(index < 0 || index >= tx->num_consti_allowed) tx->lconsti[index].idx = index; tx->lconsti[index].reg = tx->native_integers ? ureg_imm4i(tx->ureg, i[0], i[1], i[2], i[3]) : @@ -601,7 +610,7 @@ tx_set_lconsti(struct shader_translator *tx, INT index, int i[4]) static void tx_set_lconstb(struct shader_translator *tx, INT index, BOOL b) { - FAILURE_VOID(index < 0 || index >= NINE_MAX_CONST_B) + FAILURE_VOID(index < 0 || index >= tx->num_constb_allowed) tx->lconstb[index].idx = index; tx->lconstb[index].reg = tx->native_integers ? ureg_imm1u(tx->ureg, b ? 0xffffffff : 0) : @@ -672,6 +681,54 @@ tx_pred_alloc(struct shader_translator *tx, INT idx) tx->regs.p = ureg_DECL_predicate(tx->ureg); } +/* NOTE: It's not very clear on which ps1.1-ps1.3 instructions + * the projection should be applied on the texture. It doesn't + * apply on texkill. + * The doc is very imprecise here (it says the projection is done + * before rasterization, thus in vs, which seems wrong since ps instructions + * are affected differently) + * For now we only apply to the ps TEX instruction and TEXBEM. + * Perhaps some other instructions would need it */ +static inline void +apply_ps1x_projection(struct shader_translator *tx, struct ureg_dst dst, + struct ureg_src src, INT idx) +{ + struct ureg_dst tmp; + unsigned dim = 1 + ((tx->info->projected >> (2 * idx)) & 3); + + /* no projection */ + if (dim == 1) { + ureg_MOV(tx->ureg, dst, src); + } else { + tmp = tx_scratch_scalar(tx); + ureg_RCP(tx->ureg, tmp, ureg_scalar(src, dim-1)); + ureg_MUL(tx->ureg, dst, tx_src_scalar(tmp), src); + } +} + +static inline void +TEX_with_ps1x_projection(struct shader_translator *tx, struct ureg_dst dst, + unsigned target, struct ureg_src src0, + struct ureg_src src1, INT idx) +{ + unsigned dim = 1 + ((tx->info->projected >> (2 * idx)) & 3); + struct ureg_dst tmp; + + /* dim == 1: no projection + * Looks like must be disabled when it makes no + * sense according the texture dimensions + */ + if (dim == 1 || dim <= target) { + ureg_TEX(tx->ureg, dst, target, src0, src1); + } else if (dim == 4) { + ureg_TXP(tx->ureg, dst, target, src0, src1); + } else { + tmp = tx_scratch(tx); + apply_ps1x_projection(tx, tmp, src0, idx); + ureg_TEX(tx->ureg, dst, target, ureg_src(tmp), src1); + } +} + static inline void tx_texcoord_alloc(struct shader_translator *tx, INT idx) { @@ -1086,9 +1143,18 @@ _tx_dst_param(struct shader_translator *tx, const struct sm1_dst_param *param) assert(param->idx >= 0 && param->idx < 4); assert(!param->rel); tx->info->rt_mask |= 1 << param->idx; - if (ureg_dst_is_undef(tx->regs.oCol[param->idx])) - tx->regs.oCol[param->idx] = - ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, param->idx); + if (ureg_dst_is_undef(tx->regs.oCol[param->idx])) { + /* ps < 3: oCol[0] will have fog blending afterward + * vs < 3: oD1.w (D3DPMISCCAPS_FOGANDSPECULARALPHA) set to 0 even if set */ + if (!IS_VS && tx->version.major < 3 && param->idx == 0) { + tx->regs.oCol[0] = ureg_DECL_temporary(tx->ureg); + } else if (IS_VS && tx->version.major < 3 && param->idx == 1) { + tx->regs.oCol[1] = ureg_DECL_temporary(tx->ureg); + } else { + tx->regs.oCol[param->idx] = + ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, param->idx); + } + } dst = tx->regs.oCol[param->idx]; if (IS_VS && tx->version.major < 3) dst = ureg_saturate(dst); @@ -1824,7 +1890,7 @@ sm1_declusage_to_tgsi(struct tgsi_declaration_semantic *sem, sem->Index = 0; break; default: - assert(!"Invalid DECLUSAGE."); + unreachable(!"Invalid DECLUSAGE."); break; } } @@ -2135,12 +2201,79 @@ DECL_SPECIAL(TEXKILL) DECL_SPECIAL(TEXBEM) { - STUB(D3DERR_INVALIDCALL); -} + struct ureg_program *ureg = tx->ureg; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_dst tmp, tmp2, texcoord; + struct ureg_src sample, m00, m01, m10, m11; + struct ureg_src bumpenvlscale, bumpenvloffset; + const int m = tx->insn.dst[0].idx; + const int n = tx->insn.src[0].idx; -DECL_SPECIAL(TEXBEML) -{ - STUB(D3DERR_INVALIDCALL); + assert(tx->version.major == 1); + + sample = ureg_DECL_sampler(ureg, m); + tx->info->sampler_mask |= 1 << m; + + tx_texcoord_alloc(tx, m); + + tmp = tx_scratch(tx); + tmp2 = tx_scratch(tx); + texcoord = tx_scratch(tx); + /* + * Bump-env-matrix: + * 00 is X + * 01 is Y + * 10 is Z + * 11 is W + */ + nine_info_mark_const_f_used(tx->info, 8 + 8 + m/2); + m00 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, X); + m01 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, Y); + m10 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, Z); + m11 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, W); + + /* These two attributes are packed as X=scale0 Y=offset0 Z=scale1 W=offset1 etc */ + if (m % 2 == 0) { + bumpenvlscale = NINE_CONSTANT_SRC_SWIZZLE(8 + 8 + m / 2, X); + bumpenvloffset = NINE_CONSTANT_SRC_SWIZZLE(8 + 8 + m / 2, Y); + } else { + bumpenvlscale = NINE_CONSTANT_SRC_SWIZZLE(8 + 8 + m / 2, Z); + bumpenvloffset = NINE_CONSTANT_SRC_SWIZZLE(8 + 8 + m / 2, W); + } + + apply_ps1x_projection(tx, texcoord, tx->regs.vT[m], m); + + /* u' = TextureCoordinates(stage m)u + D3DTSS_BUMPENVMAT00(stage m)*t(n)R */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m00, + NINE_APPLY_SWIZZLE(ureg_src(tx->regs.tS[n]), X), ureg_src(texcoord)); + /* u' = u' + D3DTSS_BUMPENVMAT10(stage m)*t(n)G */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m10, + NINE_APPLY_SWIZZLE(ureg_src(tx->regs.tS[n]), Y), + NINE_APPLY_SWIZZLE(ureg_src(tmp), X)); + + /* v' = TextureCoordinates(stage m)v + D3DTSS_BUMPENVMAT01(stage m)*t(n)R */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m01, + NINE_APPLY_SWIZZLE(ureg_src(tx->regs.tS[n]), X), ureg_src(texcoord)); + /* v' = v' + D3DTSS_BUMPENVMAT11(stage m)*t(n)G*/ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m11, + NINE_APPLY_SWIZZLE(ureg_src(tx->regs.tS[n]), Y), + NINE_APPLY_SWIZZLE(ureg_src(tmp), Y)); + + /* Now the texture coordinates are in tmp.xy */ + + if (tx->insn.opcode == D3DSIO_TEXBEM) { + ureg_TEX(ureg, dst, ps1x_sampler_type(tx->info, m), ureg_src(tmp), sample); + } else if (tx->insn.opcode == D3DSIO_TEXBEML) { + /* t(m)RGBA = t(m)RGBA * [(t(n)B * D3DTSS_BUMPENVLSCALE(stage m)) + D3DTSS_BUMPENVLOFFSET(stage m)] */ + ureg_TEX(ureg, tmp, ps1x_sampler_type(tx->info, m), ureg_src(tmp), sample); + ureg_MAD(ureg, tmp2, NINE_APPLY_SWIZZLE(ureg_src(tx->regs.tS[n]), Z), + bumpenvlscale, bumpenvloffset); + ureg_MUL(ureg, dst, ureg_src(tmp), ureg_src(tmp2)); + } + + tx->info->bumpenvmat_needed = 1; + + return D3D_OK; } DECL_SPECIAL(TEXREG2AR) @@ -2421,7 +2554,43 @@ DECL_SPECIAL(TEXDEPTH) DECL_SPECIAL(BEM) { - STUB(D3DERR_INVALIDCALL); + struct ureg_program *ureg = tx->ureg; + struct ureg_dst dst = tx_dst_param(tx, &tx->insn.dst[0]); + struct ureg_src src0 = tx_src_param(tx, &tx->insn.src[0]); + struct ureg_src src1 = tx_src_param(tx, &tx->insn.src[1]); + struct ureg_src m00, m01, m10, m11; + const int m = tx->insn.dst[0].idx; + struct ureg_dst tmp; + /* + * Bump-env-matrix: + * 00 is X + * 01 is Y + * 10 is Z + * 11 is W + */ + nine_info_mark_const_f_used(tx->info, 8 + m); + m00 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, X); + m01 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, Y); + m10 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, Z); + m11 = NINE_CONSTANT_SRC_SWIZZLE(8 + m, W); + /* dest.r = src0.r + D3DTSS_BUMPENVMAT00(stage n) * src1.r */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m00, + NINE_APPLY_SWIZZLE(src1, X), NINE_APPLY_SWIZZLE(src0, X)); + /* dest.r = dest.r + D3DTSS_BUMPENVMAT10(stage n) * src1.g; */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_X), m10, + NINE_APPLY_SWIZZLE(src1, Y), NINE_APPLY_SWIZZLE(ureg_src(tmp), X)); + + /* dest.g = src0.g + D3DTSS_BUMPENVMAT01(stage n) * src1.r */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m01, + NINE_APPLY_SWIZZLE(src1, X), src0); + /* dest.g = dest.g + D3DTSS_BUMPENVMAT11(stage n) * src1.g */ + ureg_MAD(ureg, ureg_writemask(tmp, TGSI_WRITEMASK_Y), m11, + NINE_APPLY_SWIZZLE(src1, Y), NINE_APPLY_SWIZZLE(ureg_src(tmp), Y)); + ureg_MOV(ureg, ureg_writemask(dst, TGSI_WRITEMASK_XY), ureg_src(tmp)); + + tx->info->bumpenvmat_needed = 1; + + return D3D_OK; } DECL_SPECIAL(TEXLD) @@ -2482,7 +2651,7 @@ DECL_SPECIAL(TEX) src[1] = ureg_DECL_sampler(ureg, s); tx->info->sampler_mask |= 1 << s; - ureg_TEX(ureg, dst, t, src[0], src[1]); + TEX_with_ps1x_projection(tx, dst, t, src[0], src[1], s); return D3D_OK; } @@ -2616,7 +2785,7 @@ struct sm1_op_info inst_table[] = _OPI(TEX, TEX, V(0,0), V(0,0), V(1,4), V(1,4), 1, 1, SPECIAL(TEXLD_14)), _OPI(TEX, TEX, V(0,0), V(0,0), V(2,0), V(3,0), 1, 2, SPECIAL(TEXLD)), _OPI(TEXBEM, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXBEM)), - _OPI(TEXBEML, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXBEML)), + _OPI(TEXBEML, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXBEM)), _OPI(TEXREG2AR, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXREG2AR)), _OPI(TEXREG2GB, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXREG2GB)), _OPI(TEXM3x2PAD, TEX, V(0,0), V(0,0), V(0,0), V(1,3), 1, 1, SPECIAL(TEXM3x2PAD)), @@ -3023,6 +3192,8 @@ tx_ctor(struct shader_translator *tx, struct nine_shader_info *info) info->lconstf.data = NULL; info->lconstf.ranges = NULL; + info->bumpenvmat_needed = 0; + for (i = 0; i < Elements(tx->regs.rL); ++i) { tx->regs.rL[i] = ureg_dst_undef(); } @@ -3074,6 +3245,57 @@ tgsi_processor_from_type(unsigned shader_type) } } +static void +shader_add_ps_fog_stage(struct shader_translator *tx, struct ureg_src src_col) +{ + struct ureg_program *ureg = tx->ureg; + struct ureg_dst oCol0 = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); + struct ureg_src fog_end, fog_coeff, fog_density; + struct ureg_src fog_vs, depth, fog_color; + struct ureg_dst fog_factor; + + if (!tx->info->fog_enable) { + ureg_MOV(ureg, oCol0, src_col); + return; + } + + if (tx->info->fog_mode != D3DFOG_NONE) + depth = ureg_scalar(ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_POSITION, 0, + TGSI_INTERPOLATE_LINEAR), + TGSI_SWIZZLE_Z); + + nine_info_mark_const_f_used(tx->info, 33); + fog_color = NINE_CONSTANT_SRC(32); + fog_factor = tx_scratch_scalar(tx); + + if (tx->info->fog_mode == D3DFOG_LINEAR) { + fog_end = NINE_CONSTANT_SRC_SWIZZLE(33, X); + fog_coeff = NINE_CONSTANT_SRC_SWIZZLE(33, Y); + ureg_SUB(ureg, fog_factor, fog_end, depth); + ureg_MUL(ureg, ureg_saturate(fog_factor), tx_src_scalar(fog_factor), fog_coeff); + } else if (tx->info->fog_mode == D3DFOG_EXP) { + fog_density = NINE_CONSTANT_SRC_SWIZZLE(33, X); + ureg_MUL(ureg, fog_factor, depth, fog_density); + ureg_MUL(ureg, fog_factor, tx_src_scalar(fog_factor), ureg_imm1f(ureg, -1.442695f)); + ureg_EX2(ureg, fog_factor, tx_src_scalar(fog_factor)); + } else if (tx->info->fog_mode == D3DFOG_EXP2) { + fog_density = NINE_CONSTANT_SRC_SWIZZLE(33, X); + ureg_MUL(ureg, fog_factor, depth, fog_density); + ureg_MUL(ureg, fog_factor, tx_src_scalar(fog_factor), tx_src_scalar(fog_factor)); + ureg_MUL(ureg, fog_factor, tx_src_scalar(fog_factor), ureg_imm1f(ureg, -1.442695f)); + ureg_EX2(ureg, fog_factor, tx_src_scalar(fog_factor)); + } else { + fog_vs = ureg_scalar(ureg_DECL_fs_input(ureg, TGSI_SEMANTIC_FOG, 0, + TGSI_INTERPOLATE_PERSPECTIVE), + TGSI_SWIZZLE_X); + ureg_MOV(ureg, fog_factor, fog_vs); + } + + ureg_LRP(ureg, ureg_writemask(oCol0, TGSI_WRITEMASK_XYZ), + tx_src_scalar(fog_factor), src_col, fog_color); + ureg_MOV(ureg, ureg_writemask(oCol0, TGSI_WRITEMASK_W), src_col); +} + #define GET_CAP(n) device->screen->get_param( \ device->screen, PIPE_CAP_##n) #define GET_SHADER_CAP(n) device->screen->get_shader_param( \ @@ -3123,6 +3345,24 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info) tx->texcoord_sn = tx->want_texcoord ? TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC; + if (IS_VS) { + tx->num_constf_allowed = NINE_MAX_CONST_F; + } else if (tx->version.major < 2) {/* IS_PS v1 */ + tx->num_constf_allowed = 8; + } else if (tx->version.major == 2) {/* IS_PS v2 */ + tx->num_constf_allowed = 32; + } else {/* IS_PS v3 */ + tx->num_constf_allowed = NINE_MAX_CONST_F_PS3; + } + + if (tx->version.major < 2) { + tx->num_consti_allowed = 0; + tx->num_constb_allowed = 0; + } else { + tx->num_consti_allowed = NINE_MAX_CONST_I; + tx->num_constb_allowed = NINE_MAX_CONST_B; + } + /* VS must always write position. Declare it here to make it the 1st output. * (Some drivers like nv50 are buggy and rely on that.) */ @@ -3145,10 +3385,26 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info) goto out; } - if (IS_PS && (tx->version.major < 2) && tx->num_temp) { - ureg_MOV(tx->ureg, ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, 0), - ureg_src(tx->regs.r[0])); - info->rt_mask |= 0x1; + if (IS_PS && tx->version.major < 3) { + if (tx->version.major < 2) { + assert(tx->num_temp); /* there must be color output */ + info->rt_mask |= 0x1; + shader_add_ps_fog_stage(tx, ureg_src(tx->regs.r[0])); + } else { + shader_add_ps_fog_stage(tx, ureg_src(tx->regs.oCol[0])); + } + } + + if (IS_VS && tx->version.major < 3 && ureg_dst_is_undef(tx->regs.oFog) && info->fog_enable) { + tx->regs.oFog = ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_FOG, 0); + ureg_MOV(tx->ureg, ureg_writemask(tx->regs.oFog, TGSI_WRITEMASK_X), ureg_imm1f(tx->ureg, 0.0f)); + } + + /* vs < 3: oD1.w (D3DPMISCCAPS_FOGANDSPECULARALPHA) set to 0 even if set */ + if (IS_VS && tx->version.major < 3 && !ureg_dst_is_undef(tx->regs.oCol[1])) { + struct ureg_dst dst = ureg_DECL_output(tx->ureg, TGSI_SEMANTIC_COLOR, 1); + ureg_MOV(tx->ureg, ureg_writemask(dst, TGSI_WRITEMASK_XYZ), ureg_src(tx->regs.oCol[1])); + ureg_MOV(tx->ureg, ureg_writemask(dst, TGSI_WRITEMASK_W), ureg_imm1f(tx->ureg, 0.0f)); } if (info->position_t) @@ -3233,6 +3489,7 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info) info->const_int_slots > 0 ? max_const_f + info->const_int_slots : info->const_float_slots; + info->const_used_size = sizeof(float[4]) * slot_max; /* slots start from 1 */ for (s = 0; s < slot_max; s++) diff --git a/src/gallium/state_trackers/nine/nine_shader.h b/src/gallium/state_trackers/nine/nine_shader.h index ec256c153a9..41577ac572b 100644 --- a/src/gallium/state_trackers/nine/nine_shader.h +++ b/src/gallium/state_trackers/nine/nine_shader.h @@ -59,6 +59,10 @@ struct nine_shader_info uint16_t sampler_mask_shadow; /* in, which samplers use depth compare */ uint8_t rt_mask; /* out, which render targets are being written */ + uint8_t fog_enable; + uint8_t fog_mode; + uint16_t projected; /* ps 1.1 to 1.3 */ + unsigned const_i_base; /* in vec4 (16 byte) units */ unsigned const_b_base; /* in vec4 (16 byte) units */ unsigned const_used_size; @@ -68,6 +72,7 @@ struct nine_shader_info unsigned const_bool_slots; struct nine_lconstf lconstf; /* out, NOTE: members to be free'd by user */ + uint8_t bumpenvmat_needed; }; static inline void @@ -137,4 +142,48 @@ nine_shader_variants_free(struct nine_shader_variant *list) } } +struct nine_shader_variant64 +{ + struct nine_shader_variant64 *next; + void *cso; + uint64_t key; +}; + +static inline void * +nine_shader_variant_get64(struct nine_shader_variant64 *list, uint64_t key) +{ + while (list->key != key && list->next) + list = list->next; + if (list->key == key) + return list->cso; + return NULL; +} + +static inline boolean +nine_shader_variant_add64(struct nine_shader_variant64 *list, + uint64_t key, void *cso) +{ + while (list->next) { + assert(list->key != key); + list = list->next; + } + list->next = MALLOC_STRUCT(nine_shader_variant64); + if (!list->next) + return FALSE; + list->next->next = NULL; + list->next->key = key; + list->next->cso = cso; + return TRUE; +} + +static inline void +nine_shader_variants_free64(struct nine_shader_variant64 *list) +{ + while (list->next) { + struct nine_shader_variant64 *ptr = list->next; + list->next = ptr->next; + FREE(ptr); + } +} + #endif /* _NINE_SHADER_H_ */ diff --git a/src/gallium/state_trackers/nine/nine_state.c b/src/gallium/state_trackers/nine/nine_state.c index 6c835858d18..558d07a2bd0 100644 --- a/src/gallium/state_trackers/nine/nine_state.c +++ b/src/gallium/state_trackers/nine/nine_state.c @@ -33,352 +33,36 @@ #include "pipe/p_context.h" #include "pipe/p_state.h" #include "cso_cache/cso_context.h" +#include "util/u_upload_mgr.h" #include "util/u_math.h" #define DBG_CHANNEL DBG_DEVICE -static uint32_t -update_framebuffer(struct NineDevice9 *device) -{ - struct pipe_context *pipe = device->pipe; - struct nine_state *state = &device->state; - struct pipe_framebuffer_state *fb = &device->state.fb; - unsigned i; - struct NineSurface9 *rt0 = state->rt[0]; - unsigned w = rt0->desc.Width; - unsigned h = rt0->desc.Height; - D3DMULTISAMPLE_TYPE nr_samples = rt0->desc.MultiSampleType; - unsigned mask = state->ps ? state->ps->rt_mask : 1; - const int sRGB = state->rs[D3DRS_SRGBWRITEENABLE] ? 1 : 0; - - DBG("\n"); - - state->rt_mask = 0x0; - fb->nr_cbufs = 0; - - /* all render targets must have the same size and the depth buffer must be - * bigger. Multisample has to match, according to spec. But some apps do - * things wrong there, and no error is returned. The behaviour they get - * apparently is that depth buffer is disabled if it doesn't match. - * Surely the same for render targets. */ - - /* Special case: D3DFMT_NULL is used to bound no real render target, - * but render to depth buffer. We have to not take into account the render - * target info. TODO: know what should happen when there are several render targers - * and the first one is D3DFMT_NULL */ - if (rt0->desc.Format == D3DFMT_NULL && state->ds) { - w = state->ds->desc.Width; - h = state->ds->desc.Height; - nr_samples = state->ds->desc.MultiSampleType; - } - - for (i = 0; i < device->caps.NumSimultaneousRTs; ++i) { - struct NineSurface9 *rt = state->rt[i]; - - if (rt && rt->desc.Format != D3DFMT_NULL && (mask & (1 << i)) && - rt->desc.Width == w && rt->desc.Height == h && - rt->desc.MultiSampleType == nr_samples) { - fb->cbufs[i] = NineSurface9_GetSurface(rt, sRGB); - state->rt_mask |= 1 << i; - fb->nr_cbufs = i + 1; - - if (unlikely(rt->desc.Usage & D3DUSAGE_AUTOGENMIPMAP)) { - assert(rt->texture == D3DRTYPE_TEXTURE || - rt->texture == D3DRTYPE_CUBETEXTURE); - NineBaseTexture9(rt->base.base.container)->dirty_mip = TRUE; - } - } else { - /* Color outputs must match RT slot, - * drivers will have to handle NULL entries for GL, too. - */ - fb->cbufs[i] = NULL; - } - } - - if (state->ds && state->ds->desc.Width >= w && - state->ds->desc.Height >= h && - state->ds->desc.MultiSampleType == nr_samples) { - fb->zsbuf = NineSurface9_GetSurface(state->ds, 0); - } else { - fb->zsbuf = NULL; - } - - fb->width = w; - fb->height = h; - - pipe->set_framebuffer_state(pipe, fb); /* XXX: cso ? */ - - if (fb->zsbuf) { - DWORD scale; - switch (fb->zsbuf->format) { - case PIPE_FORMAT_Z32_FLOAT: - case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: - scale = fui(1.0f); - break; - case PIPE_FORMAT_Z16_UNORM: - scale = fui((float)(1 << 16)); - break; - default: - scale = fui((float)(1 << 24)); - break; - } - if (state->rs[NINED3DRS_ZBIASSCALE] != scale) { - state->rs[NINED3DRS_ZBIASSCALE] = scale; - state->changed.group |= NINE_STATE_RASTERIZER; - } - } - - return state->changed.group; -} - -static void -update_viewport(struct NineDevice9 *device) -{ - struct pipe_context *pipe = device->pipe; - const D3DVIEWPORT9 *vport = &device->state.viewport; - struct pipe_viewport_state pvport; - - /* D3D coordinates are: - * -1 .. +1 for X,Y and - * 0 .. +1 for Z (we use pipe_rasterizer_state.clip_halfz) - */ - pvport.scale[0] = (float)vport->Width * 0.5f; - pvport.scale[1] = (float)vport->Height * -0.5f; - pvport.scale[2] = vport->MaxZ - vport->MinZ; - pvport.translate[0] = (float)vport->Width * 0.5f + (float)vport->X; - pvport.translate[1] = (float)vport->Height * 0.5f + (float)vport->Y; - pvport.translate[2] = vport->MinZ; - - /* We found R600 and SI cards have some imprecision - * on the barycentric coordinates used for interpolation. - * Some shaders rely on having something precise. - * We found that the proprietary driver has the imprecision issue, - * except when the render target width and height are powers of two. - * It is using some sort of workaround for these cases - * which covers likely all the cases the applications rely - * on something precise. - * We haven't found the workaround, but it seems like it's better - * for applications if the imprecision is biased towards infinity - * instead of -infinity (which is what measured). So shift slightly - * the viewport: not enough to change rasterization result (in particular - * for multisampling), but enough to make the imprecision biased - * towards infinity. We do this shift only if render target width and - * height are powers of two. - * Solves 'red shadows' bug on UE3 games. - */ - if (device->driver_bugs.buggy_barycentrics && - ((vport->Width & (vport->Width-1)) == 0) && - ((vport->Height & (vport->Height-1)) == 0)) { - pvport.translate[0] -= 1.0f / 128.0f; - pvport.translate[1] -= 1.0f / 128.0f; - } - - pipe->set_viewport_states(pipe, 0, 1, &pvport); -} - -static inline void -update_scissor(struct NineDevice9 *device) -{ - struct pipe_context *pipe = device->pipe; - - pipe->set_scissor_states(pipe, 0, 1, &device->state.scissor); -} +/* State preparation only */ static inline void -update_blend(struct NineDevice9 *device) +prepare_blend(struct NineDevice9 *device) { - nine_convert_blend_state(device->cso, device->state.rs); + nine_convert_blend_state(&device->state.pipe.blend, device->state.rs); + device->state.commit |= NINE_STATE_COMMIT_BLEND; } static inline void -update_dsa(struct NineDevice9 *device) +prepare_dsa(struct NineDevice9 *device) { - nine_convert_dsa_state(device->cso, device->state.rs); + nine_convert_dsa_state(&device->state.pipe.dsa, device->state.rs); + device->state.commit |= NINE_STATE_COMMIT_DSA; } static inline void -update_rasterizer(struct NineDevice9 *device) +prepare_rasterizer(struct NineDevice9 *device) { - nine_convert_rasterizer_state(device->cso, device->state.rs); + nine_convert_rasterizer_state(&device->state.pipe.rast, device->state.rs); + device->state.commit |= NINE_STATE_COMMIT_RASTERIZER; } -/* Loop through VS inputs and pick the vertex elements with the declared - * usage from the vertex declaration, then insert the instance divisor from - * the stream source frequency setting. - */ static void -update_vertex_elements(struct NineDevice9 *device) -{ - struct nine_state *state = &device->state; - const struct NineVertexDeclaration9 *vdecl = device->state.vdecl; - const struct NineVertexShader9 *vs; - unsigned n, b, i; - int index; - char vdecl_index_map[16]; /* vs->num_inputs <= 16 */ - char used_streams[device->caps.MaxStreams]; - int dummy_vbo_stream = -1; - BOOL need_dummy_vbo = FALSE; - struct pipe_vertex_element ve[PIPE_MAX_ATTRIBS]; - - state->stream_usage_mask = 0; - memset(vdecl_index_map, -1, 16); - memset(used_streams, 0, device->caps.MaxStreams); - vs = device->state.vs ? device->state.vs : device->ff.vs; - - if (vdecl) { - for (n = 0; n < vs->num_inputs; ++n) { - DBG("looking up input %u (usage %u) from vdecl(%p)\n", - n, vs->input_map[n].ndecl, vdecl); - - for (i = 0; i < vdecl->nelems; i++) { - if (vdecl->usage_map[i] == vs->input_map[n].ndecl) { - vdecl_index_map[n] = i; - used_streams[vdecl->elems[i].vertex_buffer_index] = 1; - break; - } - } - if (vdecl_index_map[n] < 0) - need_dummy_vbo = TRUE; - } - } else { - /* No vertex declaration. Likely will never happen in practice, - * but we need not crash on this */ - need_dummy_vbo = TRUE; - } - - if (need_dummy_vbo) { - for (i = 0; i < device->caps.MaxStreams; i++ ) { - if (!used_streams[i]) { - dummy_vbo_stream = i; - break; - } - } - } - /* there are less vertex shader inputs than stream slots, - * so if we need a slot for the dummy vbo, we should have found one */ - assert (!need_dummy_vbo || dummy_vbo_stream != -1); - - for (n = 0; n < vs->num_inputs; ++n) { - index = vdecl_index_map[n]; - if (index >= 0) { - ve[n] = vdecl->elems[index]; - b = ve[n].vertex_buffer_index; - state->stream_usage_mask |= 1 << b; - /* XXX wine just uses 1 here: */ - if (state->stream_freq[b] & D3DSTREAMSOURCE_INSTANCEDATA) - ve[n].instance_divisor = state->stream_freq[b] & 0x7FFFFF; - } else { - /* if the vertex declaration is incomplete compared to what the - * vertex shader needs, we bind a dummy vbo with 0 0 0 0. - * This is not precised by the spec, but is the behaviour - * tested on win */ - ve[n].vertex_buffer_index = dummy_vbo_stream; - ve[n].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; - ve[n].src_offset = 0; - ve[n].instance_divisor = 0; - } - } - - if (state->dummy_vbo_bound_at != dummy_vbo_stream) { - if (state->dummy_vbo_bound_at >= 0) - state->changed.vtxbuf |= 1 << state->dummy_vbo_bound_at; - if (dummy_vbo_stream >= 0) { - state->changed.vtxbuf |= 1 << dummy_vbo_stream; - state->vbo_bound_done = FALSE; - } - state->dummy_vbo_bound_at = dummy_vbo_stream; - } - - cso_set_vertex_elements(device->cso, vs->num_inputs, ve); - - state->changed.stream_freq = 0; -} - -static inline uint32_t -update_shader_variant_keys(struct NineDevice9 *device) -{ - struct nine_state *state = &device->state; - uint32_t mask = 0; - uint32_t vs_key = state->samplers_shadow; - uint32_t ps_key = state->samplers_shadow; - - vs_key = (vs_key & NINE_VS_SAMPLERS_MASK) >> NINE_SAMPLER_VS(0); - ps_key = (ps_key & NINE_PS_SAMPLERS_MASK) >> NINE_SAMPLER_PS(0); - - if (state->vs) vs_key &= state->vs->sampler_mask; - if (state->ps) { - if (unlikely(state->ps->byte_code.version < 0x20)) { - /* no depth textures, but variable targets */ - uint32_t m = state->ps->sampler_mask; - ps_key = 0; - while (m) { - int s = ffs(m) - 1; - m &= ~(1 << s); - ps_key |= (state->texture[s] ? state->texture[s]->pstype : 1) << (s * 2); - } - } else { - ps_key &= state->ps->sampler_mask; - } - } - - if (state->vs && state->vs_key != vs_key) { - state->vs_key = vs_key; - mask |= NINE_STATE_VS; - } - if (state->ps && state->ps_key != ps_key) { - state->ps_key = ps_key; - mask |= NINE_STATE_PS; - } - return mask; -} - -static inline uint32_t -update_vs(struct NineDevice9 *device) -{ - struct nine_state *state = &device->state; - struct NineVertexShader9 *vs = state->vs; - uint32_t changed_group = 0; - - /* likely because we dislike FF */ - if (likely(vs)) { - state->cso.vs = NineVertexShader9_GetVariant(vs, state->vs_key); - } else { - vs = device->ff.vs; - state->cso.vs = vs->variant.cso; - } - device->pipe->bind_vs_state(device->pipe, state->cso.vs); - - if (state->rs[NINED3DRS_VSPOINTSIZE] != vs->point_size) { - state->rs[NINED3DRS_VSPOINTSIZE] = vs->point_size; - changed_group |= NINE_STATE_RASTERIZER; - } - - if ((state->bound_samplers_mask_vs & vs->sampler_mask) != vs->sampler_mask) - /* Bound dummy sampler. */ - changed_group |= NINE_STATE_SAMPLER; - return changed_group; -} - -static inline uint32_t -update_ps(struct NineDevice9 *device) -{ - struct nine_state *state = &device->state; - struct NinePixelShader9 *ps = state->ps; - uint32_t changed_group = 0; - - if (likely(ps)) { - state->cso.ps = NinePixelShader9_GetVariant(ps, state->ps_key); - } else { - ps = device->ff.ps; - state->cso.ps = ps->variant.cso; - } - device->pipe->bind_fs_state(device->pipe, state->cso.ps); - - if ((state->bound_samplers_mask_ps & ps->sampler_mask) != ps->sampler_mask) - /* Bound dummy sampler. */ - changed_group |= NINE_STATE_SAMPLER; - return changed_group; -} +prepare_ps_constants_userbuf(struct NineDevice9 *device); #define DO_UPLOAD_CONST_F(buf,p,c,d) \ do { \ @@ -391,7 +75,7 @@ update_ps(struct NineDevice9 *device) /* OK, this is a bit ugly ... */ static void -update_constants(struct NineDevice9 *device, unsigned shader_type) +upload_constants(struct NineDevice9 *device, unsigned shader_type) { struct pipe_context *pipe = device->pipe; struct pipe_resource *buf; @@ -438,10 +122,17 @@ update_constants(struct NineDevice9 *device, unsigned shader_type) lconstf_ranges = device->state.vs->lconstf.ranges; lconstf_data = device->state.vs->lconstf.data; - device->state.ff.clobber.vs_const = TRUE; device->state.changed.group &= ~NINE_STATE_VS_CONST; } else { DBG("PS\n"); + /* features only implemented on the userbuf path */ + if (device->state.ps->bumpenvmat_needed || ( + device->state.ps->byte_code.version < 0x30 && + device->state.rs[D3DRS_FOGENABLE])) { + device->prefer_user_constbuf = TRUE; + prepare_ps_constants_userbuf(device); + return; + } buf = device->constbuf_ps; const_f = device->state.ps_const_f; @@ -464,7 +155,6 @@ update_constants(struct NineDevice9 *device, unsigned shader_type) lconstf_ranges = NULL; lconstf_data = NULL; - device->state.ff.clobber.ps_const = TRUE; device->state.changed.group &= ~NINE_STATE_PS_CONST; } @@ -524,10 +214,9 @@ update_constants(struct NineDevice9 *device, unsigned shader_type) } static void -update_vs_constants_userbuf(struct NineDevice9 *device) +prepare_vs_constants_userbuf(struct NineDevice9 *device) { struct nine_state *state = &device->state; - struct pipe_context *pipe = device->pipe; struct pipe_constant_buffer cb; cb.buffer = NULL; cb.buffer_offset = 0; @@ -567,7 +256,18 @@ update_vs_constants_userbuf(struct NineDevice9 *device) cb.user_buffer = dst; } - pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &cb); + if (!device->driver_caps.user_cbufs) { + u_upload_data(device->constbuf_uploader, + 0, + cb.buffer_size, + cb.user_buffer, + &cb.buffer_offset, + &cb.buffer); + u_upload_unmap(device->constbuf_uploader); + cb.user_buffer = NULL; + } + + state->pipe.cb_vs = cb; if (device->state.changed.vs_const_f) { struct nine_range *r = device->state.changed.vs_const_f; @@ -578,22 +278,19 @@ update_vs_constants_userbuf(struct NineDevice9 *device) device->state.changed.vs_const_f = NULL; } state->changed.group &= ~NINE_STATE_VS_CONST; + state->commit |= NINE_STATE_COMMIT_CONST_VS; } static void -update_ps_constants_userbuf(struct NineDevice9 *device) +prepare_ps_constants_userbuf(struct NineDevice9 *device) { struct nine_state *state = &device->state; - struct pipe_context *pipe = device->pipe; struct pipe_constant_buffer cb; cb.buffer = NULL; cb.buffer_offset = 0; cb.buffer_size = device->state.ps->const_used_size; cb.user_buffer = device->state.ps_const_f; - if (!cb.buffer_size) - return; - if (state->changed.ps_const_i) { int *idst = (int *)&state->ps_const_f[4 * device->max_ps_const_f]; memcpy(idst, state->ps_const_i, sizeof(state->ps_const_i)); @@ -606,7 +303,47 @@ update_ps_constants_userbuf(struct NineDevice9 *device) state->changed.ps_const_b = 0; } - pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &cb); + /* Upload special constants needed to implement PS1.x instructions like TEXBEM,TEXBEML and BEM */ + if (device->state.ps->bumpenvmat_needed) { + memcpy(device->state.ps_lconstf_temp, cb.user_buffer, cb.buffer_size); + memcpy(&device->state.ps_lconstf_temp[4 * 8], &device->state.bumpmap_vars, sizeof(device->state.bumpmap_vars)); + + cb.user_buffer = device->state.ps_lconstf_temp; + } + + if (state->ps->byte_code.version < 0x30 && + state->rs[D3DRS_FOGENABLE]) { + float *dst = &state->ps_lconstf_temp[4 * 32]; + if (cb.user_buffer != state->ps_lconstf_temp) { + memcpy(state->ps_lconstf_temp, cb.user_buffer, cb.buffer_size); + cb.user_buffer = state->ps_lconstf_temp; + } + + d3dcolor_to_rgba(dst, state->rs[D3DRS_FOGCOLOR]); + if (state->rs[D3DRS_FOGTABLEMODE] == D3DFOG_LINEAR) { + dst[4] = asfloat(state->rs[D3DRS_FOGEND]); + dst[5] = 1.0f / (asfloat(state->rs[D3DRS_FOGEND]) - asfloat(state->rs[D3DRS_FOGSTART])); + } else if (state->rs[D3DRS_FOGTABLEMODE] != D3DFOG_NONE) { + dst[4] = asfloat(state->rs[D3DRS_FOGDENSITY]); + } + cb.buffer_size = 4 * 4 * 34; + } + + if (!cb.buffer_size) + return; + + if (!device->driver_caps.user_cbufs) { + u_upload_data(device->constbuf_uploader, + 0, + cb.buffer_size, + cb.user_buffer, + &cb.buffer_offset, + &cb.buffer); + u_upload_unmap(device->constbuf_uploader); + cb.user_buffer = NULL; + } + + state->pipe.cb_ps = cb; if (device->state.changed.ps_const_f) { struct nine_range *r = device->state.changed.ps_const_f; @@ -617,6 +354,286 @@ update_ps_constants_userbuf(struct NineDevice9 *device) device->state.changed.ps_const_f = NULL; } state->changed.group &= ~NINE_STATE_PS_CONST; + state->commit |= NINE_STATE_COMMIT_CONST_PS; +} + +static inline uint32_t +prepare_vs(struct NineDevice9 *device, uint8_t shader_changed) +{ + struct nine_state *state = &device->state; + struct NineVertexShader9 *vs = state->vs; + uint32_t changed_group = 0; + int has_key_changed = 0; + + if (likely(vs)) + has_key_changed = NineVertexShader9_UpdateKey(vs, state); + + if (!shader_changed && !has_key_changed) + return 0; + + /* likely because we dislike FF */ + if (likely(vs)) { + state->cso.vs = NineVertexShader9_GetVariant(vs); + } else { + vs = device->ff.vs; + state->cso.vs = vs->ff_cso; + } + + if (state->rs[NINED3DRS_VSPOINTSIZE] != vs->point_size) { + state->rs[NINED3DRS_VSPOINTSIZE] = vs->point_size; + changed_group |= NINE_STATE_RASTERIZER; + } + + if ((state->bound_samplers_mask_vs & vs->sampler_mask) != vs->sampler_mask) + /* Bound dummy sampler. */ + changed_group |= NINE_STATE_SAMPLER; + + state->commit |= NINE_STATE_COMMIT_VS; + return changed_group; +} + +static inline uint32_t +prepare_ps(struct NineDevice9 *device, uint8_t shader_changed) +{ + struct nine_state *state = &device->state; + struct NinePixelShader9 *ps = state->ps; + uint32_t changed_group = 0; + int has_key_changed = 0; + + if (likely(ps)) + has_key_changed = NinePixelShader9_UpdateKey(ps, state); + + if (!shader_changed && !has_key_changed) + return 0; + + if (likely(ps)) { + state->cso.ps = NinePixelShader9_GetVariant(ps); + } else { + ps = device->ff.ps; + state->cso.ps = ps->ff_cso; + } + + if ((state->bound_samplers_mask_ps & ps->sampler_mask) != ps->sampler_mask) + /* Bound dummy sampler. */ + changed_group |= NINE_STATE_SAMPLER; + + state->commit |= NINE_STATE_COMMIT_PS; + return changed_group; +} + +/* State preparation incremental */ + +/* State preparation + State commit */ + +static uint32_t +update_framebuffer(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + struct nine_state *state = &device->state; + struct pipe_framebuffer_state *fb = &device->state.fb; + unsigned i; + struct NineSurface9 *rt0 = state->rt[0]; + unsigned w = rt0->desc.Width; + unsigned h = rt0->desc.Height; + D3DMULTISAMPLE_TYPE nr_samples = rt0->desc.MultiSampleType; + unsigned mask = state->ps ? state->ps->rt_mask : 1; + const int sRGB = state->rs[D3DRS_SRGBWRITEENABLE] ? 1 : 0; + + DBG("\n"); + + state->rt_mask = 0x0; + fb->nr_cbufs = 0; + + /* all render targets must have the same size and the depth buffer must be + * bigger. Multisample has to match, according to spec. But some apps do + * things wrong there, and no error is returned. The behaviour they get + * apparently is that depth buffer is disabled if it doesn't match. + * Surely the same for render targets. */ + + /* Special case: D3DFMT_NULL is used to bound no real render target, + * but render to depth buffer. We have to not take into account the render + * target info. TODO: know what should happen when there are several render targers + * and the first one is D3DFMT_NULL */ + if (rt0->desc.Format == D3DFMT_NULL && state->ds) { + w = state->ds->desc.Width; + h = state->ds->desc.Height; + nr_samples = state->ds->desc.MultiSampleType; + } + + for (i = 0; i < device->caps.NumSimultaneousRTs; ++i) { + struct NineSurface9 *rt = state->rt[i]; + + if (rt && rt->desc.Format != D3DFMT_NULL && (mask & (1 << i)) && + rt->desc.Width == w && rt->desc.Height == h && + rt->desc.MultiSampleType == nr_samples) { + fb->cbufs[i] = NineSurface9_GetSurface(rt, sRGB); + state->rt_mask |= 1 << i; + fb->nr_cbufs = i + 1; + + if (unlikely(rt->desc.Usage & D3DUSAGE_AUTOGENMIPMAP)) { + assert(rt->texture == D3DRTYPE_TEXTURE || + rt->texture == D3DRTYPE_CUBETEXTURE); + NineBaseTexture9(rt->base.base.container)->dirty_mip = TRUE; + } + } else { + /* Color outputs must match RT slot, + * drivers will have to handle NULL entries for GL, too. + */ + fb->cbufs[i] = NULL; + } + } + + if (state->ds && state->ds->desc.Width >= w && + state->ds->desc.Height >= h && + state->ds->desc.MultiSampleType == nr_samples) { + fb->zsbuf = NineSurface9_GetSurface(state->ds, 0); + } else { + fb->zsbuf = NULL; + } + + fb->width = w; + fb->height = h; + + pipe->set_framebuffer_state(pipe, fb); /* XXX: cso ? */ + + return state->changed.group; +} + +static void +update_viewport(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + const D3DVIEWPORT9 *vport = &device->state.viewport; + struct pipe_viewport_state pvport; + + /* D3D coordinates are: + * -1 .. +1 for X,Y and + * 0 .. +1 for Z (we use pipe_rasterizer_state.clip_halfz) + */ + pvport.scale[0] = (float)vport->Width * 0.5f; + pvport.scale[1] = (float)vport->Height * -0.5f; + pvport.scale[2] = vport->MaxZ - vport->MinZ; + pvport.translate[0] = (float)vport->Width * 0.5f + (float)vport->X; + pvport.translate[1] = (float)vport->Height * 0.5f + (float)vport->Y; + pvport.translate[2] = vport->MinZ; + + /* We found R600 and SI cards have some imprecision + * on the barycentric coordinates used for interpolation. + * Some shaders rely on having something precise. + * We found that the proprietary driver has the imprecision issue, + * except when the render target width and height are powers of two. + * It is using some sort of workaround for these cases + * which covers likely all the cases the applications rely + * on something precise. + * We haven't found the workaround, but it seems like it's better + * for applications if the imprecision is biased towards infinity + * instead of -infinity (which is what measured). So shift slightly + * the viewport: not enough to change rasterization result (in particular + * for multisampling), but enough to make the imprecision biased + * towards infinity. We do this shift only if render target width and + * height are powers of two. + * Solves 'red shadows' bug on UE3 games. + */ + if (device->driver_bugs.buggy_barycentrics && + ((vport->Width & (vport->Width-1)) == 0) && + ((vport->Height & (vport->Height-1)) == 0)) { + pvport.translate[0] -= 1.0f / 128.0f; + pvport.translate[1] -= 1.0f / 128.0f; + } + + pipe->set_viewport_states(pipe, 0, 1, &pvport); +} + +/* Loop through VS inputs and pick the vertex elements with the declared + * usage from the vertex declaration, then insert the instance divisor from + * the stream source frequency setting. + */ +static void +update_vertex_elements(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + const struct NineVertexDeclaration9 *vdecl = device->state.vdecl; + const struct NineVertexShader9 *vs; + unsigned n, b, i; + int index; + char vdecl_index_map[16]; /* vs->num_inputs <= 16 */ + char used_streams[device->caps.MaxStreams]; + int dummy_vbo_stream = -1; + BOOL need_dummy_vbo = FALSE; + struct pipe_vertex_element ve[PIPE_MAX_ATTRIBS]; + + state->stream_usage_mask = 0; + memset(vdecl_index_map, -1, 16); + memset(used_streams, 0, device->caps.MaxStreams); + vs = device->state.vs ? device->state.vs : device->ff.vs; + + if (vdecl) { + for (n = 0; n < vs->num_inputs; ++n) { + DBG("looking up input %u (usage %u) from vdecl(%p)\n", + n, vs->input_map[n].ndecl, vdecl); + + for (i = 0; i < vdecl->nelems; i++) { + if (vdecl->usage_map[i] == vs->input_map[n].ndecl) { + vdecl_index_map[n] = i; + used_streams[vdecl->elems[i].vertex_buffer_index] = 1; + break; + } + } + if (vdecl_index_map[n] < 0) + need_dummy_vbo = TRUE; + } + } else { + /* No vertex declaration. Likely will never happen in practice, + * but we need not crash on this */ + need_dummy_vbo = TRUE; + } + + if (need_dummy_vbo) { + for (i = 0; i < device->caps.MaxStreams; i++ ) { + if (!used_streams[i]) { + dummy_vbo_stream = i; + break; + } + } + } + /* there are less vertex shader inputs than stream slots, + * so if we need a slot for the dummy vbo, we should have found one */ + assert (!need_dummy_vbo || dummy_vbo_stream != -1); + + for (n = 0; n < vs->num_inputs; ++n) { + index = vdecl_index_map[n]; + if (index >= 0) { + ve[n] = vdecl->elems[index]; + b = ve[n].vertex_buffer_index; + state->stream_usage_mask |= 1 << b; + /* XXX wine just uses 1 here: */ + if (state->stream_freq[b] & D3DSTREAMSOURCE_INSTANCEDATA) + ve[n].instance_divisor = state->stream_freq[b] & 0x7FFFFF; + } else { + /* if the vertex declaration is incomplete compared to what the + * vertex shader needs, we bind a dummy vbo with 0 0 0 0. + * This is not precised by the spec, but is the behaviour + * tested on win */ + ve[n].vertex_buffer_index = dummy_vbo_stream; + ve[n].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + ve[n].src_offset = 0; + ve[n].instance_divisor = 0; + } + } + + if (state->dummy_vbo_bound_at != dummy_vbo_stream) { + if (state->dummy_vbo_bound_at >= 0) + state->changed.vtxbuf |= 1 << state->dummy_vbo_bound_at; + if (dummy_vbo_stream >= 0) { + state->changed.vtxbuf |= 1 << dummy_vbo_stream; + state->vbo_bound_done = FALSE; + } + state->dummy_vbo_bound_at = dummy_vbo_stream; + } + + cso_set_vertex_elements(device->cso, vs->num_inputs, ve); + + state->changed.stream_freq = 0; } static void @@ -627,7 +644,6 @@ update_vertex_buffers(struct NineDevice9 *device) struct pipe_vertex_buffer dummy_vtxbuf; uint32_t mask = state->changed.vtxbuf; unsigned i; - unsigned start; DBG("mask=%x\n", mask); @@ -656,27 +672,6 @@ update_vertex_buffers(struct NineDevice9 *device) state->changed.vtxbuf = 0; } -static inline void -update_index_buffer(struct NineDevice9 *device) -{ - struct pipe_context *pipe = device->pipe; - if (device->state.idxbuf) - pipe->set_index_buffer(pipe, &device->state.idxbuf->buffer); - else - pipe->set_index_buffer(pipe, NULL); -} - -/* TODO: only go through dirty textures */ -static void -validate_textures(struct NineDevice9 *device) -{ - struct NineBaseTexture9 *tex, *ptr; - LIST_FOR_EACH_ENTRY_SAFE(tex, ptr, &device->update_textures, list) { - list_delinit(&tex->list); - NineBaseTexture9_Validate(tex); - } -} - static inline boolean update_sampler_derived(struct nine_state *state, unsigned s) { @@ -706,20 +701,16 @@ update_sampler_derived(struct nine_state *state, unsigned s) static void update_textures_and_samplers(struct NineDevice9 *device) { - struct pipe_context *pipe = device->pipe; struct nine_state *state = &device->state; struct pipe_sampler_view *view[NINE_MAX_SAMPLERS]; - struct pipe_sampler_state samp; unsigned num_textures; unsigned i; - boolean commit_views; boolean commit_samplers; uint16_t sampler_mask = state->ps ? state->ps->sampler_mask : device->ff.ps->sampler_mask; /* TODO: Can we reduce iterations here ? */ - commit_views = FALSE; commit_samplers = FALSE; state->bound_samplers_mask_ps = 0; for (num_textures = 0, i = 0; i < NINE_MAX_SAMPLERS_PS; ++i) { @@ -749,26 +740,12 @@ update_textures_and_samplers(struct NineDevice9 *device) * unbind dummy sampler directly when they are not needed * anymore, but they're going to be removed as long as texture * or sampler states are changed. */ - view[i] = device->dummy_sampler; + view[i] = device->dummy_sampler_view; num_textures = i + 1; - memset(&samp, 0, sizeof(samp)); - samp.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; - samp.max_lod = 15.0f; - samp.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - samp.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - samp.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - samp.min_img_filter = PIPE_TEX_FILTER_NEAREST; - samp.mag_img_filter = PIPE_TEX_FILTER_NEAREST; - samp.compare_mode = PIPE_TEX_COMPARE_NONE; - samp.compare_func = PIPE_FUNC_LEQUAL; - samp.normalized_coords = 1; - samp.seamless_cube_map = 1; - cso_single_sampler(device->cso, PIPE_SHADER_FRAGMENT, - s - NINE_SAMPLER_PS(0), &samp); + s - NINE_SAMPLER_PS(0), &device->dummy_sampler_state); - commit_views = TRUE; commit_samplers = TRUE; state->changed.sampler[s] = ~0; } @@ -776,16 +753,11 @@ update_textures_and_samplers(struct NineDevice9 *device) state->bound_samplers_mask_ps |= (1 << s); } - commit_views |= (state->changed.texture & NINE_PS_SAMPLERS_MASK) != 0; - commit_views |= state->changed.srgb; - if (commit_views) - pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, - num_textures, view); + cso_set_sampler_views(device->cso, PIPE_SHADER_FRAGMENT, num_textures, view); if (commit_samplers) cso_single_sampler_done(device->cso, PIPE_SHADER_FRAGMENT); - commit_views = FALSE; commit_samplers = FALSE; sampler_mask = state->vs ? state->vs->sampler_mask : 0; state->bound_samplers_mask_vs = 0; @@ -816,76 +788,170 @@ update_textures_and_samplers(struct NineDevice9 *device) * unbind dummy sampler directly when they are not needed * anymore, but they're going to be removed as long as texture * or sampler states are changed. */ - view[i] = device->dummy_sampler; + view[i] = device->dummy_sampler_view; num_textures = i + 1; - memset(&samp, 0, sizeof(samp)); - samp.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; - samp.max_lod = 15.0f; - samp.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - samp.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - samp.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; - samp.min_img_filter = PIPE_TEX_FILTER_NEAREST; - samp.mag_img_filter = PIPE_TEX_FILTER_NEAREST; - samp.compare_mode = PIPE_TEX_COMPARE_NONE; - samp.compare_func = PIPE_FUNC_LEQUAL; - samp.normalized_coords = 1; - samp.seamless_cube_map = 1; - cso_single_sampler(device->cso, PIPE_SHADER_VERTEX, - s - NINE_SAMPLER_VS(0), &samp); + s - NINE_SAMPLER_VS(0), &device->dummy_sampler_state); - commit_views = TRUE; commit_samplers = TRUE; state->changed.sampler[s] = ~0; } state->bound_samplers_mask_vs |= (1 << s); } - commit_views |= (state->changed.texture & NINE_VS_SAMPLERS_MASK) != 0; - commit_views |= state->changed.srgb; - if (commit_views) - pipe->set_sampler_views(pipe, PIPE_SHADER_VERTEX, 0, - num_textures, view); + + cso_set_sampler_views(device->cso, PIPE_SHADER_VERTEX, num_textures, view); if (commit_samplers) cso_single_sampler_done(device->cso, PIPE_SHADER_VERTEX); - state->changed.srgb = FALSE; state->changed.texture = 0; } +/* State commit only */ + +static inline void +commit_blend(struct NineDevice9 *device) +{ + cso_set_blend(device->cso, &device->state.pipe.blend); +} + +static inline void +commit_dsa(struct NineDevice9 *device) +{ + cso_set_depth_stencil_alpha(device->cso, &device->state.pipe.dsa); +} + +static inline void +commit_scissor(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + + pipe->set_scissor_states(pipe, 0, 1, &device->state.scissor); +} + +static inline void +commit_rasterizer(struct NineDevice9 *device) +{ + cso_set_rasterizer(device->cso, &device->state.pipe.rast); +} -#define NINE_STATE_FREQ_GROUP_0 \ - (NINE_STATE_FB | \ - NINE_STATE_VIEWPORT | \ - NINE_STATE_SCISSOR | \ - NINE_STATE_BLEND | \ - NINE_STATE_DSA | \ - NINE_STATE_RASTERIZER | \ - NINE_STATE_VS | \ - NINE_STATE_PS | \ - NINE_STATE_BLEND_COLOR | \ - NINE_STATE_STENCIL_REF | \ +static inline void +commit_index_buffer(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + if (device->state.idxbuf) + pipe->set_index_buffer(pipe, &device->state.idxbuf->buffer); + else + pipe->set_index_buffer(pipe, NULL); +} + +static inline void +commit_vs_constants(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + + if (unlikely(!device->state.vs)) + pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &device->state.pipe.cb_vs_ff); + else + pipe->set_constant_buffer(pipe, PIPE_SHADER_VERTEX, 0, &device->state.pipe.cb_vs); +} + +static inline void +commit_ps_constants(struct NineDevice9 *device) +{ + struct pipe_context *pipe = device->pipe; + + if (unlikely(!device->state.ps)) + pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &device->state.pipe.cb_ps_ff); + else + pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, 0, &device->state.pipe.cb_ps); +} + +static inline void +commit_vs(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + + device->pipe->bind_vs_state(device->pipe, state->cso.vs); +} + + +static inline void +commit_ps(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + + device->pipe->bind_fs_state(device->pipe, state->cso.ps); +} +/* State Update */ + +#define NINE_STATE_SHADER_CHANGE_VS \ + (NINE_STATE_VS | \ + NINE_STATE_TEXTURE | \ + NINE_STATE_FOG_SHADER) + +#define NINE_STATE_SHADER_CHANGE_PS \ + (NINE_STATE_PS | \ + NINE_STATE_TEXTURE | \ + NINE_STATE_FOG_SHADER | \ + NINE_STATE_PS1X_SHADER) + +#define NINE_STATE_FREQUENT \ + (NINE_STATE_RASTERIZER | \ + NINE_STATE_TEXTURE | \ + NINE_STATE_SAMPLER | \ + NINE_STATE_VS_CONST | \ + NINE_STATE_PS_CONST) + +#define NINE_STATE_COMMON \ + (NINE_STATE_FB | \ + NINE_STATE_BLEND | \ + NINE_STATE_DSA | \ + NINE_STATE_VIEWPORT | \ + NINE_STATE_VDECL | \ + NINE_STATE_IDXBUF) + +#define NINE_STATE_RARE \ + (NINE_STATE_SCISSOR | \ + NINE_STATE_BLEND_COLOR | \ + NINE_STATE_STENCIL_REF | \ NINE_STATE_SAMPLE_MASK) -#define NINE_STATE_FREQ_GROUP_1 ~NINE_STATE_FREQ_GROUP_0 -#define NINE_STATE_SHADER_VARIANT_GROUP \ - (NINE_STATE_TEXTURE | \ - NINE_STATE_VS | \ - NINE_STATE_PS) +/* TODO: only go through dirty textures */ +static void +validate_textures(struct NineDevice9 *device) +{ + struct NineBaseTexture9 *tex, *ptr; + LIST_FOR_EACH_ENTRY_SAFE(tex, ptr, &device->update_textures, list) { + list_delinit(&tex->list); + NineBaseTexture9_Validate(tex); + } +} + +void +nine_update_state_framebuffer(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + + validate_textures(device); + + if (state->changed.group & NINE_STATE_FB) + update_framebuffer(device); + + state->changed.group &= ~NINE_STATE_FB; +} boolean -nine_update_state(struct NineDevice9 *device, uint32_t mask) +nine_update_state(struct NineDevice9 *device) { struct pipe_context *pipe = device->pipe; struct nine_state *state = &device->state; uint32_t group; - DBG("changed state groups: %x | %x\n", - state->changed.group & NINE_STATE_FREQ_GROUP_0, - state->changed.group & NINE_STATE_FREQ_GROUP_1); + DBG("changed state groups: %x\n", state->changed.group); /* NOTE: We may want to use the cso cache for everything, or let * NineDevice9.RestoreNonCSOState actually set the states, then we wouldn't @@ -896,35 +962,79 @@ nine_update_state(struct NineDevice9 *device, uint32_t mask) validate_textures(device); /* may clobber state */ /* ff_update may change VS/PS dirty bits */ - if ((mask & NINE_STATE_FF) && unlikely(!state->vs || !state->ps)) + if (unlikely(!state->vs || !state->ps)) nine_ff_update(device); - group = state->changed.group & mask; + group = state->changed.group; - if (group & NINE_STATE_SHADER_VARIANT_GROUP) - group |= update_shader_variant_keys(device); + if (group & (NINE_STATE_SHADER_CHANGE_VS | NINE_STATE_SHADER_CHANGE_PS)) { + if (group & NINE_STATE_SHADER_CHANGE_VS) + group |= prepare_vs(device, (group & NINE_STATE_VS) != 0); /* may set NINE_STATE_RASTERIZER and NINE_STATE_SAMPLER*/ + if (group & NINE_STATE_SHADER_CHANGE_PS) + group |= prepare_ps(device, (group & NINE_STATE_PS) != 0); + } - if (group & NINE_STATE_FREQ_GROUP_0) { + if (group & (NINE_STATE_COMMON | NINE_STATE_VS)) { if (group & NINE_STATE_FB) - group = update_framebuffer(device) & mask; + group |= update_framebuffer(device); /* may set NINE_STATE_RASTERIZER */ + if (group & NINE_STATE_BLEND) + prepare_blend(device); + if (group & NINE_STATE_DSA) + prepare_dsa(device); if (group & NINE_STATE_VIEWPORT) update_viewport(device); - if (group & NINE_STATE_SCISSOR) - update_scissor(device); - - if (group & NINE_STATE_DSA) - update_dsa(device); - if (group & NINE_STATE_BLEND) - update_blend(device); - - if (group & NINE_STATE_VS) - group |= update_vs(device); + if ((group & (NINE_STATE_VDECL | NINE_STATE_VS)) || + state->changed.stream_freq & ~1) + update_vertex_elements(device); + if (group & NINE_STATE_IDXBUF) + commit_index_buffer(device); + } + if (likely(group & (NINE_STATE_FREQUENT | NINE_STATE_VS | NINE_STATE_PS))) { if (group & NINE_STATE_RASTERIZER) - update_rasterizer(device); + prepare_rasterizer(device); + if (group & (NINE_STATE_TEXTURE | NINE_STATE_SAMPLER)) + update_textures_and_samplers(device); + if (device->prefer_user_constbuf) { + if ((group & (NINE_STATE_VS_CONST | NINE_STATE_VS)) && state->vs) + prepare_vs_constants_userbuf(device); + if ((group & (NINE_STATE_PS_CONST | NINE_STATE_PS)) && state->ps) + prepare_ps_constants_userbuf(device); + } else { + if ((group & NINE_STATE_VS_CONST) && state->vs) + upload_constants(device, PIPE_SHADER_VERTEX); + if ((group & NINE_STATE_PS_CONST) && state->ps) + upload_constants(device, PIPE_SHADER_FRAGMENT); + } + } - if (group & NINE_STATE_PS) - group |= update_ps(device); + if (state->changed.vtxbuf) + update_vertex_buffers(device); + + if (state->commit & NINE_STATE_COMMIT_BLEND) + commit_blend(device); + if (state->commit & NINE_STATE_COMMIT_DSA) + commit_dsa(device); + if (state->commit & NINE_STATE_COMMIT_RASTERIZER) + commit_rasterizer(device); + if (state->commit & NINE_STATE_COMMIT_CONST_VS) + commit_vs_constants(device); + if (state->commit & NINE_STATE_COMMIT_CONST_PS) + commit_ps_constants(device); + if (state->commit & NINE_STATE_COMMIT_VS) + commit_vs(device); + if (state->commit & NINE_STATE_COMMIT_PS) + commit_ps(device); + + state->commit = 0; + + if (unlikely(state->changed.ucp)) { + pipe->set_clip_state(pipe, &state->clip); + state->changed.ucp = 0; + } + if (unlikely(group & NINE_STATE_RARE)) { + if (group & NINE_STATE_SCISSOR) + commit_scissor(device); if (group & NINE_STATE_BLEND_COLOR) { struct pipe_blend_color color; d3dcolor_to_rgba(&color.color[0], state->rs[D3DRS_BLENDFACTOR]); @@ -941,38 +1051,7 @@ nine_update_state(struct NineDevice9 *device, uint32_t mask) } } - if (state->changed.ucp) { - pipe->set_clip_state(pipe, &state->clip); - state->changed.ucp = 0; - } - - if (group & (NINE_STATE_FREQ_GROUP_1 | NINE_STATE_VS)) { - if (group & (NINE_STATE_TEXTURE | NINE_STATE_SAMPLER)) - update_textures_and_samplers(device); - - if (group & NINE_STATE_IDXBUF) - update_index_buffer(device); - - if ((group & (NINE_STATE_VDECL | NINE_STATE_VS)) || - state->changed.stream_freq & ~1) - update_vertex_elements(device); - - if (device->prefer_user_constbuf) { - if ((group & (NINE_STATE_VS_CONST | NINE_STATE_VS)) && state->vs) - update_vs_constants_userbuf(device); - if ((group & (NINE_STATE_PS_CONST | NINE_STATE_PS)) && state->ps) - update_ps_constants_userbuf(device); - } else { - if ((group & NINE_STATE_VS_CONST) && state->vs) - update_constants(device, PIPE_SHADER_VERTEX); - if ((group & NINE_STATE_PS_CONST) && state->ps) - update_constants(device, PIPE_SHADER_FRAGMENT); - } - } - if (state->changed.vtxbuf) - update_vertex_buffers(device); - - device->state.changed.group &= ~mask | + device->state.changed.group &= (NINE_STATE_FF | NINE_STATE_VS_CONST | NINE_STATE_PS_CONST); DBG("finished\n"); @@ -980,6 +1059,7 @@ nine_update_state(struct NineDevice9 *device, uint32_t mask) return TRUE; } +/* State defaults */ static const DWORD nine_render_state_defaults[NINED3DRS_LAST + 1] = { @@ -1134,6 +1214,18 @@ static const DWORD nine_samp_state_defaults[NINED3DSAMP_LAST + 1] = [NINED3DSAMP_MINLOD] = 0, [NINED3DSAMP_SHADOW] = 0 }; + +void nine_state_restore_non_cso(struct NineDevice9 *device) +{ + struct nine_state *state = &device->state; + + state->changed.group = NINE_STATE_ALL; + state->changed.vtxbuf = (1ULL << device->caps.MaxStreams) - 1; + state->changed.ucp = (1 << PIPE_MAX_CLIP_PLANES) - 1; + state->changed.texture = NINE_PS_SAMPLERS_MASK | NINE_VS_SAMPLERS_MASK; + state->commit |= NINE_STATE_COMMIT_CONST_VS | NINE_STATE_COMMIT_CONST_PS; +} + void nine_state_set_defaults(struct NineDevice9 *device, const D3DCAPS9 *caps, boolean is_reset) @@ -1152,6 +1244,7 @@ nine_state_set_defaults(struct NineDevice9 *device, const D3DCAPS9 *caps, } state->ff.tex_stage[0][D3DTSS_COLOROP] = D3DTOP_MODULATE; state->ff.tex_stage[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG1; + memset(&state->bumpmap_vars, 0, sizeof(state->bumpmap_vars)); for (s = 0; s < Elements(state->samp); ++s) { memcpy(&state->samp[s], nine_samp_state_defaults, @@ -1170,6 +1263,9 @@ nine_state_set_defaults(struct NineDevice9 *device, const D3DCAPS9 *caps, /* Set changed flags to initialize driver. */ state->changed.group = NINE_STATE_ALL; + state->changed.vtxbuf = (1ULL << device->caps.MaxStreams) - 1; + state->changed.ucp = (1 << PIPE_MAX_CLIP_PLANES) - 1; + state->changed.texture = NINE_PS_SAMPLERS_MASK | NINE_VS_SAMPLERS_MASK; state->ff.changed.transform[0] = ~0; state->ff.changed.transform[D3DTS_WORLD / 32] |= 1 << (D3DTS_WORLD % 32); @@ -1186,6 +1282,23 @@ nine_state_set_defaults(struct NineDevice9 *device, const D3DCAPS9 *caps, state->dummy_vbo_bound_at = -1; state->vbo_bound_done = FALSE; } + + if (!device->prefer_user_constbuf) { + /* fill cb_vs and cb_ps for the non user constbuf path */ + struct pipe_constant_buffer cb; + + cb.buffer_offset = 0; + cb.buffer_size = device->vs_const_size; + cb.buffer = device->constbuf_vs; + cb.user_buffer = NULL; + state->pipe.cb_vs = cb; + + cb.buffer_size = device->ps_const_size; + cb.buffer = device->constbuf_ps; + state->pipe.cb_ps = cb; + + state->commit |= NINE_STATE_COMMIT_CONST_VS | NINE_STATE_COMMIT_CONST_PS; + } } void @@ -1353,15 +1466,15 @@ const uint32_t nine_render_state_group[NINED3DRS_LAST + 1] = [D3DRS_ZFUNC] = NINE_STATE_DSA, [D3DRS_ALPHAREF] = NINE_STATE_DSA, [D3DRS_ALPHAFUNC] = NINE_STATE_DSA, - [D3DRS_DITHERENABLE] = NINE_STATE_RASTERIZER, + [D3DRS_DITHERENABLE] = NINE_STATE_BLEND, [D3DRS_ALPHABLENDENABLE] = NINE_STATE_BLEND, - [D3DRS_FOGENABLE] = NINE_STATE_FF_OTHER, + [D3DRS_FOGENABLE] = NINE_STATE_FF_OTHER | NINE_STATE_FOG_SHADER | NINE_STATE_PS_CONST, [D3DRS_SPECULARENABLE] = NINE_STATE_FF_LIGHTING, - [D3DRS_FOGCOLOR] = NINE_STATE_FF_OTHER, - [D3DRS_FOGTABLEMODE] = NINE_STATE_FF_OTHER, - [D3DRS_FOGSTART] = NINE_STATE_FF_OTHER, - [D3DRS_FOGEND] = NINE_STATE_FF_OTHER, - [D3DRS_FOGDENSITY] = NINE_STATE_FF_OTHER, + [D3DRS_FOGCOLOR] = NINE_STATE_FF_OTHER | NINE_STATE_PS_CONST, + [D3DRS_FOGTABLEMODE] = NINE_STATE_FF_OTHER | NINE_STATE_FOG_SHADER | NINE_STATE_PS_CONST, + [D3DRS_FOGSTART] = NINE_STATE_FF_OTHER | NINE_STATE_PS_CONST, + [D3DRS_FOGEND] = NINE_STATE_FF_OTHER | NINE_STATE_PS_CONST, + [D3DRS_FOGDENSITY] = NINE_STATE_FF_OTHER | NINE_STATE_PS_CONST, [D3DRS_RANGEFOGENABLE] = NINE_STATE_FF_OTHER, [D3DRS_STENCILENABLE] = NINE_STATE_DSA, [D3DRS_STENCILFAIL] = NINE_STATE_DSA, @@ -1394,7 +1507,7 @@ const uint32_t nine_render_state_group[NINED3DRS_LAST + 1] = [D3DRS_VERTEXBLEND] = NINE_STATE_FF_OTHER, [D3DRS_CLIPPLANEENABLE] = NINE_STATE_RASTERIZER, [D3DRS_POINTSIZE] = NINE_STATE_RASTERIZER, - [D3DRS_POINTSIZE_MIN] = NINE_STATE_MISC_CONST, + [D3DRS_POINTSIZE_MIN] = NINE_STATE_RASTERIZER, [D3DRS_POINTSPRITEENABLE] = NINE_STATE_RASTERIZER, [D3DRS_POINTSCALEENABLE] = NINE_STATE_FF_OTHER, [D3DRS_POINTSCALE_A] = NINE_STATE_FF_OTHER, @@ -1404,7 +1517,7 @@ const uint32_t nine_render_state_group[NINED3DRS_LAST + 1] = [D3DRS_MULTISAMPLEMASK] = NINE_STATE_SAMPLE_MASK, [D3DRS_PATCHEDGESTYLE] = NINE_STATE_UNHANDLED, [D3DRS_DEBUGMONITORTOKEN] = NINE_STATE_UNHANDLED, - [D3DRS_POINTSIZE_MAX] = NINE_STATE_MISC_CONST, + [D3DRS_POINTSIZE_MAX] = NINE_STATE_RASTERIZER, [D3DRS_INDEXEDVERTEXBLENDENABLE] = NINE_STATE_FF_OTHER, [D3DRS_COLORWRITEENABLE] = NINE_STATE_BLEND, [D3DRS_TWEENFACTOR] = NINE_STATE_FF_OTHER, @@ -1446,6 +1559,8 @@ const uint32_t nine_render_state_group[NINED3DRS_LAST + 1] = [D3DRS_BLENDOPALPHA] = NINE_STATE_BLEND }; +/* Misc */ + D3DMATRIX * nine_state_access_transform(struct nine_state *state, D3DTRANSFORMSTATETYPE t, boolean alloc) @@ -1601,4 +1716,3 @@ const char *nine_d3drs_to_string(DWORD State) return "(invalid)"; } } - diff --git a/src/gallium/state_trackers/nine/nine_state.h b/src/gallium/state_trackers/nine/nine_state.h index 2bf3f637f93..b34da70ef48 100644 --- a/src/gallium/state_trackers/nine/nine_state.h +++ b/src/gallium/state_trackers/nine/nine_state.h @@ -33,8 +33,7 @@ #define NINED3DRS_VSPOINTSIZE (D3DRS_BLENDOPALPHA + 1) #define NINED3DRS_RTMASK (D3DRS_BLENDOPALPHA + 2) -#define NINED3DRS_ZBIASSCALE (D3DRS_BLENDOPALPHA + 3) -#define NINED3DRS_ALPHACOVERAGE (D3DRS_BLENDOPALPHA + 4) +#define NINED3DRS_ALPHACOVERAGE (D3DRS_BLENDOPALPHA + 3) #define D3DRS_LAST D3DRS_BLENDOPALPHA #define NINED3DRS_LAST NINED3DRS_ALPHACOVERAGE /* 213 */ @@ -67,17 +66,26 @@ #define NINE_STATE_BLEND_COLOR (1 << 16) #define NINE_STATE_STENCIL_REF (1 << 17) #define NINE_STATE_SAMPLE_MASK (1 << 18) -#define NINE_STATE_MISC_CONST (1 << 19) -#define NINE_STATE_FF (0x1f << 20) -#define NINE_STATE_FF_VS (0x17 << 20) -#define NINE_STATE_FF_PS (0x18 << 20) -#define NINE_STATE_FF_LIGHTING (1 << 20) -#define NINE_STATE_FF_MATERIAL (1 << 21) -#define NINE_STATE_FF_VSTRANSF (1 << 22) -#define NINE_STATE_FF_PSSTAGES (1 << 23) -#define NINE_STATE_FF_OTHER (1 << 24) -#define NINE_STATE_ALL 0x1ffffff -#define NINE_STATE_UNHANDLED (1 << 25) +#define NINE_STATE_FF (0x1f << 19) +#define NINE_STATE_FF_VS (0x17 << 19) +#define NINE_STATE_FF_PS (0x18 << 19) +#define NINE_STATE_FF_LIGHTING (1 << 19) +#define NINE_STATE_FF_MATERIAL (1 << 20) +#define NINE_STATE_FF_VSTRANSF (1 << 21) +#define NINE_STATE_FF_PSSTAGES (1 << 22) +#define NINE_STATE_FF_OTHER (1 << 23) +#define NINE_STATE_FOG_SHADER (1 << 24) +#define NINE_STATE_PS1X_SHADER (1 << 25) +#define NINE_STATE_ALL 0x3ffffff +#define NINE_STATE_UNHANDLED (1 << 26) + +#define NINE_STATE_COMMIT_DSA (1 << 0) +#define NINE_STATE_COMMIT_RASTERIZER (1 << 1) +#define NINE_STATE_COMMIT_BLEND (1 << 2) +#define NINE_STATE_COMMIT_CONST_VS (1 << 3) +#define NINE_STATE_COMMIT_CONST_PS (1 << 4) +#define NINE_STATE_COMMIT_VS (1 << 5) +#define NINE_STATE_COMMIT_PS (1 << 6) #define NINE_MAX_SIMULTANEOUS_RENDERTARGETS 4 @@ -94,6 +102,8 @@ NINE_MAX_CONST_I * 4 * sizeof(int)) +#define NINE_MAX_TEXTURE_STAGES 8 + #define NINE_MAX_LIGHTS 65536 #define NINE_MAX_LIGHTS_ACTIVE 8 @@ -124,7 +134,6 @@ struct nine_state uint16_t vs_const_b; /* NINE_MAX_CONST_B == 16 */ uint16_t ps_const_b; uint8_t ucp; - boolean srgb; } changed; struct NineSurface9 *rt[NINE_MAX_SIMULTANEOUS_RENDERTARGETS]; @@ -143,13 +152,13 @@ struct nine_state int vs_const_i[NINE_MAX_CONST_I][4]; BOOL vs_const_b[NINE_MAX_CONST_B]; float *vs_lconstf_temp; - uint32_t vs_key; struct NinePixelShader9 *ps; float *ps_const_f; int ps_const_i[NINE_MAX_CONST_I][4]; BOOL ps_const_b[NINE_MAX_CONST_B]; - uint32_t ps_key; + float *ps_lconstf_temp; + uint32_t bumpmap_vars[6 * NINE_MAX_TEXTURE_STAGES]; struct { void *vs; @@ -184,13 +193,9 @@ struct nine_state struct { struct { uint32_t group; - uint32_t tex_stage[NINE_MAX_SAMPLERS][(NINED3DTSS_COUNT + 31) / 32]; + uint32_t tex_stage[NINE_MAX_TEXTURE_STAGES][(NINED3DTSS_COUNT + 31) / 32]; uint32_t transform[(NINED3DTS_COUNT + 31) / 32]; } changed; - struct { - boolean vs_const; - boolean ps_const; - } clobber; D3DMATRIX *transform; /* access only via nine_state_access_transform */ unsigned num_transforms; @@ -205,8 +210,19 @@ struct nine_state D3DMATERIAL9 material; - DWORD tex_stage[NINE_MAX_SAMPLERS][NINED3DTSS_COUNT]; + DWORD tex_stage[NINE_MAX_TEXTURE_STAGES][NINED3DTSS_COUNT]; } ff; + + uint32_t commit; + struct { + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_rasterizer_state rast; + struct pipe_blend_state blend; + struct pipe_constant_buffer cb_vs; + struct pipe_constant_buffer cb_ps; + struct pipe_constant_buffer cb_vs_ff; + struct pipe_constant_buffer cb_ps_ff; + } pipe; }; /* map D3DRS -> NINE_STATE_x @@ -220,8 +236,10 @@ extern const uint32_t nine_render_states_vertex[(NINED3DRS_COUNT + 31) / 32]; struct NineDevice9; -boolean nine_update_state(struct NineDevice9 *, uint32_t group_mask); +void nine_update_state_framebuffer(struct NineDevice9 *); +boolean nine_update_state(struct NineDevice9 *); +void nine_state_restore_non_cso(struct NineDevice9 *device); void nine_state_set_defaults(struct NineDevice9 *, const D3DCAPS9 *, boolean is_reset); void nine_state_clear(struct nine_state *, const boolean device); diff --git a/src/gallium/state_trackers/nine/pixelshader9.c b/src/gallium/state_trackers/nine/pixelshader9.c index 3f176a312bf..42bc349c2cc 100644 --- a/src/gallium/state_trackers/nine/pixelshader9.c +++ b/src/gallium/state_trackers/nine/pixelshader9.c @@ -46,7 +46,7 @@ NinePixelShader9_ctor( struct NinePixelShader9 *This, return hr; if (cso) { - This->variant.cso = cso; + This->ff_cso = cso; return D3D_OK; } device = This->base.device; @@ -57,6 +57,8 @@ NinePixelShader9_ctor( struct NinePixelShader9 *This, info.const_b_base = NINE_CONST_B_BASE(device->max_ps_const_f) / 16; info.sampler_mask_shadow = 0x0; info.sampler_ps1xtypes = 0x0; + info.fog_enable = 0; + info.projected = 0; hr = nine_translate_shader(device, &info); if (FAILED(hr)) @@ -69,9 +71,13 @@ NinePixelShader9_ctor( struct NinePixelShader9 *This, This->byte_code.size = info.byte_size; This->variant.cso = info.cso; + This->last_cso = info.cso; + This->last_key = 0; + This->sampler_mask = info.sampler_mask; This->rt_mask = info.rt_mask; This->const_used_size = info.const_used_size; + This->bumpenvmat_needed = info.bumpenvmat_needed; /* no constant relative addressing for ps */ assert(info.lconstf.data == NULL); assert(info.lconstf.ranges == NULL); @@ -82,11 +88,12 @@ NinePixelShader9_ctor( struct NinePixelShader9 *This, void NinePixelShader9_dtor( struct NinePixelShader9 *This ) { - DBG("This=%p cso=%p\n", This, This->variant.cso); + DBG("This=%p\n", This); if (This->base.device) { struct pipe_context *pipe = This->base.device->pipe; - struct nine_shader_variant *var = &This->variant; + struct nine_shader_variant64 *var = &This->variant; + do { if (var->cso) { if (This->base.device->state.cso.ps == var->cso) @@ -95,8 +102,14 @@ NinePixelShader9_dtor( struct NinePixelShader9 *This ) } var = var->next; } while (var); + + if (This->ff_cso) { + if (This->ff_cso == This->base.device->state.cso.ps) + pipe->bind_fs_state(pipe, NULL); + pipe->delete_fs_state(pipe, This->ff_cso); + } } - nine_shader_variants_free(&This->variant); + nine_shader_variants_free64(&This->variant); FREE((void *)This->byte_code.tokens); /* const_cast */ @@ -124,10 +137,16 @@ NinePixelShader9_GetFunction( struct NinePixelShader9 *This, } void * -NinePixelShader9_GetVariant( struct NinePixelShader9 *This, - uint32_t key ) +NinePixelShader9_GetVariant( struct NinePixelShader9 *This ) { - void *cso = nine_shader_variant_get(&This->variant, key); + void *cso; + uint64_t key; + + key = This->next_key; + if (key == This->last_key) + return This->last_cso; + + cso = nine_shader_variant_get64(&This->variant, key); if (!cso) { struct NineDevice9 *device = This->base.device; struct nine_shader_info info; @@ -139,13 +158,20 @@ NinePixelShader9_GetVariant( struct NinePixelShader9 *This, info.byte_code = This->byte_code.tokens; info.sampler_mask_shadow = key & 0xffff; info.sampler_ps1xtypes = key; + info.fog_enable = device->state.rs[D3DRS_FOGENABLE]; + info.fog_mode = device->state.rs[D3DRS_FOGTABLEMODE]; + info.projected = (key >> 48) & 0xffff; hr = nine_translate_shader(This->base.device, &info); if (FAILED(hr)) return NULL; - nine_shader_variant_add(&This->variant, key, info.cso); + nine_shader_variant_add64(&This->variant, key, info.cso); cso = info.cso; } + + This->last_key = key; + This->last_cso = cso; + return cso; } diff --git a/src/gallium/state_trackers/nine/pixelshader9.h b/src/gallium/state_trackers/nine/pixelshader9.h index 6dad1d1ee76..e09009f6621 100644 --- a/src/gallium/state_trackers/nine/pixelshader9.h +++ b/src/gallium/state_trackers/nine/pixelshader9.h @@ -25,13 +25,16 @@ #include "iunknown.h" #include "nine_shader.h" +#include "nine_state.h" +#include "basetexture9.h" +#include "nine_ff.h" struct nine_lconstf; struct NinePixelShader9 { struct NineUnknown base; - struct nine_shader_variant variant; + struct nine_shader_variant64 variant; struct { const DWORD *tokens; @@ -41,11 +44,17 @@ struct NinePixelShader9 unsigned const_used_size; /* in bytes */ + uint8_t bumpenvmat_needed; uint16_t sampler_mask; - uint16_t sampler_mask_shadow; uint8_t rt_mask; uint64_t ff_key[6]; + void *ff_cso; + + uint64_t last_key; + void *last_cso; + + uint64_t next_key; }; static inline struct NinePixelShader9 * NinePixelShader9( void *data ) @@ -53,9 +62,49 @@ NinePixelShader9( void *data ) return (struct NinePixelShader9 *)data; } +static inline BOOL +NinePixelShader9_UpdateKey( struct NinePixelShader9 *ps, + struct nine_state *state ) +{ + uint16_t samplers_shadow; + uint32_t samplers_ps1_types; + uint16_t projected; + uint64_t key; + BOOL res; + + if (unlikely(ps->byte_code.version < 0x20)) { + /* no depth textures, but variable targets */ + uint32_t m = ps->sampler_mask; + samplers_ps1_types = 0; + while (m) { + int s = ffs(m) - 1; + m &= ~(1 << s); + samplers_ps1_types |= (state->texture[s] ? state->texture[s]->pstype : 1) << (s * 2); + } + key = samplers_ps1_types; + } else { + samplers_shadow = (uint16_t)((state->samplers_shadow & NINE_PS_SAMPLERS_MASK) >> NINE_SAMPLER_PS(0)); + key = samplers_shadow & ps->sampler_mask; + } + + if (ps->byte_code.version < 0x30) { + key |= ((uint64_t)state->rs[D3DRS_FOGENABLE]) << 32; + key |= ((uint64_t)state->rs[D3DRS_FOGTABLEMODE]) << 33; + } + + if (unlikely(ps->byte_code.version < 0x14)) { + projected = nine_ff_get_projected_key(state); + key |= ((uint64_t) projected) << 48; + } + + res = ps->last_key != key; + if (res) + ps->next_key = key; + return res; +} + void * -NinePixelShader9_GetVariant( struct NinePixelShader9 *vs, - uint32_t key ); +NinePixelShader9_GetVariant( struct NinePixelShader9 *ps ); /*** public ***/ diff --git a/src/gallium/state_trackers/nine/resource9.c b/src/gallium/state_trackers/nine/resource9.c index bbc8320071b..6d915338b24 100644 --- a/src/gallium/state_trackers/nine/resource9.c +++ b/src/gallium/state_trackers/nine/resource9.c @@ -161,20 +161,22 @@ NineResource9_GetPrivateData( struct NineResource9 *This, DWORD *pSizeOfData ) { struct pheader *header; + DWORD sizeofdata; DBG("This=%p refguid=%p pData=%p pSizeOfData=%p\n", This, refguid, pData, pSizeOfData); - user_assert(pSizeOfData, E_POINTER); - header = util_hash_table_get(This->pdata, refguid); if (!header) { return D3DERR_NOTFOUND; } + user_assert(pSizeOfData, E_POINTER); + sizeofdata = *pSizeOfData; + *pSizeOfData = header->size; + if (!pData) { - *pSizeOfData = header->size; return D3D_OK; } - if (*pSizeOfData < header->size) { + if (sizeofdata < header->size) { return D3DERR_MOREDATA; } @@ -206,10 +208,13 @@ DWORD WINAPI NineResource9_SetPriority( struct NineResource9 *This, DWORD PriorityNew ) { - DWORD prev = This->priority; - + DWORD prev; DBG("This=%p, PriorityNew=%d\n", This, PriorityNew); + if (This->pool != D3DPOOL_MANAGED || This->type == D3DRTYPE_SURFACE) + return 0; + + prev = This->priority; This->priority = PriorityNew; return prev; } @@ -217,6 +222,9 @@ NineResource9_SetPriority( struct NineResource9 *This, DWORD WINAPI NineResource9_GetPriority( struct NineResource9 *This ) { + if (This->pool != D3DPOOL_MANAGED || This->type == D3DRTYPE_SURFACE) + return 0; + return This->priority; } diff --git a/src/gallium/state_trackers/nine/stateblock9.c b/src/gallium/state_trackers/nine/stateblock9.c index 032b9ffcbf0..6d6e1be0b7f 100644 --- a/src/gallium/state_trackers/nine/stateblock9.c +++ b/src/gallium/state_trackers/nine/stateblock9.c @@ -251,7 +251,7 @@ nine_state_copy_common(struct nine_state *dst, dst->ff.material = src->ff.material; if (mask->changed.group & NINE_STATE_FF_PSSTAGES) { - for (s = 0; s < NINE_MAX_SAMPLERS; ++s) { + for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++s) { for (i = 0; i < NINED3DTSS_COUNT; ++i) if (mask->ff.changed.tex_stage[s][i / 32] & (1 << (i % 32))) dst->ff.tex_stage[s][i] = src->ff.tex_stage[s][i]; diff --git a/src/gallium/state_trackers/nine/surface9.c b/src/gallium/state_trackers/nine/surface9.c index 7533cb3a454..14c1ce927ad 100644 --- a/src/gallium/state_trackers/nine/surface9.c +++ b/src/gallium/state_trackers/nine/surface9.c @@ -104,11 +104,11 @@ NineSurface9_ctor( struct NineSurface9 *This, /* Ram buffer with no parent. Has to allocate the resource itself */ if (!pResource && !pContainer) { assert(!user_buffer); - This->data = MALLOC( + This->data = align_malloc( nine_format_get_level_alloc_size(This->base.info.format, pDesc->Width, pDesc->Height, - 0)); + 0), 32); if (!This->data) return E_OUTOFMEMORY; } @@ -273,7 +273,7 @@ NineSurface9_AddDirtyRect( struct NineSurface9 *This, This->texture == D3DRTYPE_CUBETEXTURE || This->texture == D3DRTYPE_TEXTURE); - if (This->base.pool != D3DPOOL_MANAGED) + if (This->base.pool == D3DPOOL_DEFAULT) return; /* Add a dirty rect to level 0 of the parent texture */ @@ -287,7 +287,7 @@ NineSurface9_AddDirtyRect( struct NineSurface9 *This, NineTexture9(This->base.base.container); NineTexture9_AddDirtyRect(tex, &dirty_rect); - } else { /* This->texture == D3DRTYPE_CUBETEXTURE */ + } else if (This->texture == D3DRTYPE_CUBETEXTURE) { struct NineCubeTexture9 *ctex = NineCubeTexture9(This->base.base.container); @@ -323,6 +323,13 @@ NineSurface9_LockRect( struct NineSurface9 *This, nine_D3DLOCK_to_str(Flags)); NineSurface9_Dump(This); + /* check if it's already locked */ + user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); + + /* set pBits to NULL after lock_count check */ + user_assert(pLockedRect, E_POINTER); + pLockedRect->pBits = NULL; + #ifdef NINE_STRICT user_assert(This->base.pool != D3DPOOL_DEFAULT || (resource && (resource->flags & NINE_RESOURCE_FLAG_LOCKABLE)), @@ -337,19 +344,17 @@ NineSurface9_LockRect( struct NineSurface9 *This, user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)), D3DERR_INVALIDCALL); - /* check if it's already locked */ - user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); - user_assert(pLockedRect, E_POINTER); - user_assert(This->desc.MultiSampleType == D3DMULTISAMPLE_NONE, D3DERR_INVALIDCALL); - if (pRect && This->base.pool == D3DPOOL_DEFAULT && - util_format_is_compressed(This->base.info.format)) { + if (pRect && This->desc.Pool == D3DPOOL_DEFAULT && + compressed_format (This->desc.Format)) { const unsigned w = util_format_get_blockwidth(This->base.info.format); const unsigned h = util_format_get_blockheight(This->base.info.format); - user_assert(!(pRect->left % w) && !(pRect->right % w) && - !(pRect->top % h) && !(pRect->bottom % h), + user_assert((pRect->left == 0 && pRect->right == This->desc.Width && + pRect->top == 0 && pRect->bottom == This->desc.Height) || + (!(pRect->left % w) && !(pRect->right % w) && + !(pRect->top % h) && !(pRect->bottom % h)), D3DERR_INVALIDCALL); } @@ -363,13 +368,9 @@ NineSurface9_LockRect( struct NineSurface9 *This, usage |= PIPE_TRANSFER_DONTBLOCK; if (pRect) { + /* Windows XP accepts invalid locking rectangles, Windows 7 rejects + * them. Use Windows XP behaviour for now. */ rect_to_pipe_box(&box, pRect); - if (u_box_clip_2d(&box, &box, This->desc.Width, - This->desc.Height) < 0) { - DBG("pRect clipped by Width=%u Height=%u\n", - This->desc.Width, This->desc.Height); - return D3DERR_INVALIDCALL; - } } else { u_box_origin_2d(This->desc.Width, This->desc.Height, &box); } @@ -463,140 +464,92 @@ IDirect3DSurface9Vtbl NineSurface9_vtable = { (void *)NineSurface9_ReleaseDC }; -HRESULT -NineSurface9_CopySurface( struct NineSurface9 *This, - struct NineSurface9 *From, - const POINT *pDestPoint, - const RECT *pSourceRect ) +/* When this function is called, we have already checked + * The copy regions fit the surfaces */ +void +NineSurface9_CopyMemToDefault( struct NineSurface9 *This, + struct NineSurface9 *From, + const POINT *pDestPoint, + const RECT *pSourceRect ) { struct pipe_context *pipe = This->pipe; struct pipe_resource *r_dst = This->base.resource; - struct pipe_resource *r_src = From->base.resource; - struct pipe_transfer *transfer; - struct pipe_box src_box; struct pipe_box dst_box; - uint8_t *p_dst; const uint8_t *p_src; + int src_x, src_y, dst_x, dst_y, copy_width, copy_height; - DBG("This=%p From=%p pDestPoint=%p pSourceRect=%p\n", - This, From, pDestPoint, pSourceRect); - - assert(This->base.pool != D3DPOOL_MANAGED && - From->base.pool != D3DPOOL_MANAGED); + assert(This->base.pool == D3DPOOL_DEFAULT && + From->base.pool == D3DPOOL_SYSTEMMEM); - user_assert(This->desc.Format == From->desc.Format, D3DERR_INVALIDCALL); + if (pDestPoint) { + dst_x = pDestPoint->x; + dst_y = pDestPoint->y; + } else { + dst_x = 0; + dst_y = 0; + } - dst_box.x = pDestPoint ? pDestPoint->x : 0; - dst_box.y = pDestPoint ? pDestPoint->y : 0; + if (pSourceRect) { + src_x = pSourceRect->left; + src_y = pSourceRect->top; + copy_width = pSourceRect->right - pSourceRect->left; + copy_height = pSourceRect->bottom - pSourceRect->top; + } else { + src_x = 0; + src_y = 0; + copy_width = From->desc.Width; + copy_height = From->desc.Height; + } - user_assert(dst_box.x >= 0 && - dst_box.y >= 0, D3DERR_INVALIDCALL); + u_box_2d_zslice(dst_x, dst_y, This->layer, + copy_width, copy_height, &dst_box); - dst_box.z = This->layer; - src_box.z = From->layer; + p_src = NineSurface9_GetSystemMemPointer(From, src_x, src_y); - dst_box.depth = 1; - src_box.depth = 1; + pipe->transfer_inline_write(pipe, r_dst, This->level, + 0, /* WRITE|DISCARD are implicit */ + &dst_box, p_src, From->stride, 0); - if (pSourceRect) { - /* make sure it doesn't range outside the source surface */ - user_assert(pSourceRect->left >= 0 && - pSourceRect->right <= From->desc.Width && - pSourceRect->top >= 0 && - pSourceRect->bottom <= From->desc.Height, - D3DERR_INVALIDCALL); - if (rect_to_pipe_box_xy_only_clamp(&src_box, pSourceRect)) - return D3D_OK; - } else { - src_box.x = 0; - src_box.y = 0; - src_box.width = From->desc.Width; - src_box.height = From->desc.Height; - } + NineSurface9_MarkContainerDirty(This); +} - /* limits */ - dst_box.width = This->desc.Width - dst_box.x; - dst_box.height = This->desc.Height - dst_box.y; +void +NineSurface9_CopyDefaultToMem( struct NineSurface9 *This, + struct NineSurface9 *From ) +{ + struct pipe_context *pipe = This->pipe; + struct pipe_resource *r_src = From->base.resource; + struct pipe_transfer *transfer; + struct pipe_box src_box; + uint8_t *p_dst; + const uint8_t *p_src; - user_assert(src_box.width <= dst_box.width && - src_box.height <= dst_box.height, D3DERR_INVALIDCALL); + assert(This->base.pool == D3DPOOL_SYSTEMMEM && + From->base.pool == D3DPOOL_DEFAULT); - dst_box.width = src_box.width; - dst_box.height = src_box.height; + assert(This->desc.Width == From->desc.Width); + assert(This->desc.Height == From->desc.Height); - /* check source block align for compressed textures */ - if (util_format_is_compressed(From->base.info.format) && - ((src_box.width != From->desc.Width) || - (src_box.height != From->desc.Height))) { - const unsigned w = util_format_get_blockwidth(From->base.info.format); - const unsigned h = util_format_get_blockheight(From->base.info.format); - user_assert(!(src_box.width % w) && - !(src_box.height % h), - D3DERR_INVALIDCALL); - } + u_box_origin_2d(This->desc.Width, This->desc.Height, &src_box); + src_box.z = From->layer; - /* check destination block align for compressed textures */ - if (util_format_is_compressed(This->base.info.format) && - ((dst_box.width != This->desc.Width) || - (dst_box.height != This->desc.Height) || - dst_box.x != 0 || - dst_box.y != 0)) { - const unsigned w = util_format_get_blockwidth(This->base.info.format); - const unsigned h = util_format_get_blockheight(This->base.info.format); - user_assert(!(dst_box.x % w) && !(dst_box.width % w) && - !(dst_box.y % h) && !(dst_box.height % h), - D3DERR_INVALIDCALL); - } + p_src = pipe->transfer_map(pipe, r_src, From->level, + PIPE_TRANSFER_READ, + &src_box, &transfer); + p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0); - if (r_dst && r_src) { - pipe->resource_copy_region(pipe, - r_dst, This->level, - dst_box.x, dst_box.y, dst_box.z, - r_src, From->level, - &src_box); - } else - if (r_dst) { - p_src = NineSurface9_GetSystemMemPointer(From, src_box.x, src_box.y); - - pipe->transfer_inline_write(pipe, r_dst, This->level, - 0, /* WRITE|DISCARD are implicit */ - &dst_box, p_src, From->stride, 0); - } else - if (r_src) { - p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0); - - p_src = pipe->transfer_map(pipe, r_src, From->level, - PIPE_TRANSFER_READ, - &src_box, &transfer); - if (!p_src) - return D3DERR_DRIVERINTERNALERROR; - - util_copy_rect(p_dst, This->base.info.format, - This->stride, dst_box.x, dst_box.y, - dst_box.width, dst_box.height, - p_src, - transfer->stride, src_box.x, src_box.y); - - pipe->transfer_unmap(pipe, transfer); - } else { - p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0); - p_src = NineSurface9_GetSystemMemPointer(From, 0, 0); - - util_copy_rect(p_dst, This->base.info.format, - This->stride, dst_box.x, dst_box.y, - dst_box.width, dst_box.height, - p_src, - From->stride, src_box.x, src_box.y); - } + assert (p_src && p_dst); - if (This->base.pool == D3DPOOL_DEFAULT) - NineSurface9_MarkContainerDirty(This); - if (!r_dst && This->base.resource) - NineSurface9_AddDirtyRect(This, &dst_box); + util_copy_rect(p_dst, This->base.info.format, + This->stride, 0, 0, + This->desc.Width, This->desc.Height, + p_src, + transfer->stride, 0, 0); - return D3D_OK; + pipe->transfer_unmap(pipe, transfer); } + /* Gladly, rendering to a MANAGED surface is not permitted, so we will * never have to do the reverse, i.e. download the surface. */ diff --git a/src/gallium/state_trackers/nine/surface9.h b/src/gallium/state_trackers/nine/surface9.h index 73092ab8cf5..76156ae699c 100644 --- a/src/gallium/state_trackers/nine/surface9.h +++ b/src/gallium/state_trackers/nine/surface9.h @@ -125,11 +125,15 @@ HRESULT NineSurface9_UploadSelf( struct NineSurface9 *This, const struct pipe_box *damaged ); -HRESULT -NineSurface9_CopySurface( struct NineSurface9 *This, - struct NineSurface9 *From, - const POINT *pDestPoint, - const RECT *pSourceRect ); +void +NineSurface9_CopyMemToDefault( struct NineSurface9 *This, + struct NineSurface9 *From, + const POINT *pDestPoint, + const RECT *pSourceRect ); + +void +NineSurface9_CopyDefaultToMem( struct NineSurface9 *This, + struct NineSurface9 *From ); static inline boolean NineSurface9_IsOffscreenPlain (struct NineSurface9 *This ) diff --git a/src/gallium/state_trackers/nine/swapchain9.c b/src/gallium/state_trackers/nine/swapchain9.c index a62e6ad99d8..3f5be26fed7 100644 --- a/src/gallium/state_trackers/nine/swapchain9.c +++ b/src/gallium/state_trackers/nine/swapchain9.c @@ -184,7 +184,9 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This, /* Note: It is the role of the backend to fill if necessary * BackBufferWidth and BackBufferHeight */ - ID3DPresent_SetPresentParameters(This->present, pParams, This->mode); + hr = ID3DPresent_SetPresentParameters(This->present, pParams, This->mode); + if (hr != D3D_OK) + return hr; /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip. * Here we don't get back the initial content of the screen. To emulate the behaviour @@ -575,9 +577,10 @@ handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *r blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; - ID3DPresent_GetCursorPos(This->present, &device->cursor.pos); - - /* NOTE: blit messes up when box.x + box.width < 0, fix driver */ + /* NOTE: blit messes up when box.x + box.width < 0, fix driver + * NOTE2: device->cursor.pos contains coordinates relative to the screen. + * This happens to be also the position of the cursor when we are fullscreen. + * We don't use sw cursor for Windowed mode */ blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x; blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y; blit.dst.box.width = blit.src.box.width; @@ -587,13 +590,14 @@ handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *r blit.src.box.width, blit.src.box.height, blit.dst.box.x, blit.dst.box.y); + blit.alpha_blend = TRUE; This->pipe->blit(This->pipe, &blit); } if (device->hud && resource) { hud_draw(device->hud, resource); /* XXX: no offset */ /* HUD doesn't clobber stipple */ - NineDevice9_RestoreNonCSOState(device, ~0x2); + nine_state_restore_non_cso(device); } } @@ -704,6 +708,7 @@ present( struct NineSwapChain9 *This, blit.mask = PIPE_MASK_RGBA; blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; + blit.alpha_blend = FALSE; This->pipe->blit(This->pipe, &blit); } @@ -835,7 +840,7 @@ NineSwapChain9_Present( struct NineSwapChain9 *This, ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]); This->base.device->state.changed.group |= NINE_STATE_FB; - nine_update_state(This->base.device, NINE_STATE_FB); + nine_update_state_framebuffer(This->base.device); return hr; } @@ -856,6 +861,8 @@ NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, DBG("GetFrontBufferData: This=%p pDestSurface=%p\n", This, pDestSurface); + user_assert(dest_surface->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL); + width = dest_surface->desc.Width; height = dest_surface->desc.Height; @@ -870,7 +877,7 @@ NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, desc.MultiSampleQuality = 0; desc.Width = width; desc.Height = height; - /* NineSurface9_CopySurface needs same format. */ + /* NineSurface9_CopyDefaultToMem needs same format. */ desc.Format = dest_surface->desc.Format; desc.Usage = D3DUSAGE_RENDERTARGET; hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, NULL, 0, @@ -883,7 +890,7 @@ NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, ID3DPresent_FrontBufferCopy(This->present, temp_handle); - NineSurface9_CopySurface(dest_surface, temp_surface, NULL, NULL); + NineSurface9_CopyDefaultToMem(dest_surface, temp_surface); ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle); NineUnknown_Destroy(NineUnknown(temp_surface)); diff --git a/src/gallium/state_trackers/nine/texture9.c b/src/gallium/state_trackers/nine/texture9.c index 5900e76e52c..bc325c1335e 100644 --- a/src/gallium/state_trackers/nine/texture9.c +++ b/src/gallium/state_trackers/nine/texture9.c @@ -101,6 +101,13 @@ NineTexture9_ctor( struct NineTexture9 *This, if (Format != D3DFMT_NULL && pf == PIPE_FORMAT_NONE) return D3DERR_INVALIDCALL; + if (compressed_format(Format)) { + const unsigned w = util_format_get_blockwidth(pf); + const unsigned h = util_format_get_blockheight(pf); + + user_assert(!(Width % w) && !(Height % h), D3DERR_INVALIDCALL); + } + info->screen = screen; info->target = PIPE_TEXTURE_2D; info->format = pf; @@ -152,10 +159,10 @@ NineTexture9_ctor( struct NineTexture9 *This, * apps access sublevels of texture even if they locked only first * level) */ level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1)); - user_buffer = MALLOC( + user_buffer = align_malloc( nine_format_get_size_and_offsets(pf, level_offsets, Width, Height, - info->last_level)); + info->last_level), 32); This->managed_buffer = user_buffer; if (!This->managed_buffer) return E_OUTOFMEMORY; @@ -202,6 +209,9 @@ NineTexture9_ctor( struct NineTexture9 *This, return hr; } + /* Textures start initially dirty */ + This->dirty_rect.width = Width; + This->dirty_rect.height = Height; This->dirty_rect.depth = 1; /* widht == 0 means empty, depth stays 1 */ if (pSharedHandle && !*pSharedHandle) {/* Pool == D3DPOOL_SYSTEMMEM */ @@ -219,7 +229,8 @@ NineTexture9_dtor( struct NineTexture9 *This ) if (This->surfaces) { /* The surfaces should have 0 references and be unbound now. */ for (l = 0; l <= This->base.base.info.last_level; ++l) - NineUnknown_Destroy(&This->surfaces[l]->base.base); + if (This->surfaces[l]) + NineUnknown_Destroy(&This->surfaces[l]->base.base); FREE(This->surfaces); } @@ -295,18 +306,22 @@ NineTexture9_AddDirtyRect( struct NineTexture9 *This, pDirtyRect ? pDirtyRect->left : 0, pDirtyRect ? pDirtyRect->top : 0, pDirtyRect ? pDirtyRect->right : 0, pDirtyRect ? pDirtyRect->bottom : 0); - /* Tracking dirty regions on DEFAULT or SYSTEMMEM resources is pointless, + /* Tracking dirty regions on DEFAULT resources is pointless, * because we always write to the final storage. Just marked it dirty in * case we need to generate mip maps. */ - if (This->base.base.pool != D3DPOOL_MANAGED) { - if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) + if (This->base.base.pool == D3DPOOL_DEFAULT) { + if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) { This->base.dirty_mip = TRUE; + BASETEX_REGISTER_UPDATE(&This->base); + } return D3D_OK; } - This->base.managed.dirty = TRUE; - BASETEX_REGISTER_UPDATE(&This->base); + if (This->base.base.pool == D3DPOOL_MANAGED) { + This->base.managed.dirty = TRUE; + BASETEX_REGISTER_UPDATE(&This->base); + } if (!pDirtyRect) { u_box_origin_2d(This->base.base.info.width0, diff --git a/src/gallium/state_trackers/nine/vertexshader9.c b/src/gallium/state_trackers/nine/vertexshader9.c index bbd5ce99d9a..fdfb79a138e 100644 --- a/src/gallium/state_trackers/nine/vertexshader9.c +++ b/src/gallium/state_trackers/nine/vertexshader9.c @@ -48,9 +48,10 @@ NineVertexShader9_ctor( struct NineVertexShader9 *This, return hr; if (cso) { - This->variant.cso = cso; + This->ff_cso = cso; return D3D_OK; } + device = This->base.device; info.type = PIPE_SHADER_VERTEX; @@ -59,6 +60,7 @@ NineVertexShader9_ctor( struct NineVertexShader9 *This, info.const_b_base = NINE_CONST_B_BASE(device->max_vs_const_f) / 16; info.sampler_mask_shadow = 0x0; info.sampler_ps1xtypes = 0x0; + info.fog_enable = 0; hr = nine_translate_shader(device, &info); if (FAILED(hr)) @@ -71,6 +73,9 @@ NineVertexShader9_ctor( struct NineVertexShader9 *This, This->byte_code.size = info.byte_size; This->variant.cso = info.cso; + This->last_cso = info.cso; + This->last_key = 0; + This->const_used_size = info.const_used_size; This->lconstf = info.lconstf; This->sampler_mask = info.sampler_mask; @@ -87,11 +92,12 @@ NineVertexShader9_ctor( struct NineVertexShader9 *This, void NineVertexShader9_dtor( struct NineVertexShader9 *This ) { - DBG("This=%p cso=%p\n", This, This->variant.cso); + DBG("This=%p\n", This); if (This->base.device) { struct pipe_context *pipe = This->base.device->pipe; struct nine_shader_variant *var = &This->variant; + do { if (var->cso) { if (This->base.device->state.cso.vs == var->cso) @@ -100,6 +106,12 @@ NineVertexShader9_dtor( struct NineVertexShader9 *This ) } var = var->next; } while (var); + + if (This->ff_cso) { + if (This->ff_cso == This->base.device->state.cso.vs) + pipe->bind_vs_state(pipe, NULL); + pipe->delete_vs_state(pipe, This->ff_cso); + } } nine_shader_variants_free(&This->variant); @@ -130,10 +142,16 @@ NineVertexShader9_GetFunction( struct NineVertexShader9 *This, } void * -NineVertexShader9_GetVariant( struct NineVertexShader9 *This, - uint32_t key ) +NineVertexShader9_GetVariant( struct NineVertexShader9 *This ) { - void *cso = nine_shader_variant_get(&This->variant, key); + void *cso; + uint32_t key; + + key = This->next_key; + if (key == This->last_key) + return This->last_cso; + + cso = nine_shader_variant_get(&This->variant, key); if (!cso) { struct NineDevice9 *device = This->base.device; struct nine_shader_info info; @@ -144,6 +162,7 @@ NineVertexShader9_GetVariant( struct NineVertexShader9 *This, info.const_b_base = NINE_CONST_B_BASE(device->max_vs_const_f) / 16; info.byte_code = This->byte_code.tokens; info.sampler_mask_shadow = key & 0xf; + info.fog_enable = device->state.rs[D3DRS_FOGENABLE]; hr = nine_translate_shader(This->base.device, &info); if (FAILED(hr)) @@ -151,6 +170,10 @@ NineVertexShader9_GetVariant( struct NineVertexShader9 *This, nine_shader_variant_add(&This->variant, key, info.cso); cso = info.cso; } + + This->last_key = key; + This->last_cso = cso; + return cso; } diff --git a/src/gallium/state_trackers/nine/vertexshader9.h b/src/gallium/state_trackers/nine/vertexshader9.h index 66c602c7b3c..15c3f4ff041 100644 --- a/src/gallium/state_trackers/nine/vertexshader9.h +++ b/src/gallium/state_trackers/nine/vertexshader9.h @@ -25,6 +25,7 @@ #include "iunknown.h" #include "nine_shader.h" +#include "nine_state.h" struct NineVertexShader9 { @@ -43,7 +44,6 @@ struct NineVertexShader9 } byte_code; uint8_t sampler_mask; - uint8_t sampler_mask_shadow; boolean position_t; /* if true, disable vport transform */ boolean point_size; /* if true, set rasterizer.point_size_per_vertex to 1 */ @@ -54,7 +54,13 @@ struct NineVertexShader9 const struct pipe_stream_output_info *so; - uint64_t ff_key[2]; + uint64_t ff_key[3]; + void *ff_cso; + + uint32_t last_key; + void *last_cso; + + uint32_t next_key; }; static inline struct NineVertexShader9 * NineVertexShader9( void *data ) @@ -62,9 +68,29 @@ NineVertexShader9( void *data ) return (struct NineVertexShader9 *)data; } +static inline BOOL +NineVertexShader9_UpdateKey( struct NineVertexShader9 *vs, + struct nine_state *state ) +{ + uint8_t samplers_shadow; + uint32_t key; + BOOL res; + + samplers_shadow = (uint8_t)((state->samplers_shadow & NINE_VS_SAMPLERS_MASK) >> NINE_SAMPLER_VS(0)); + samplers_shadow &= vs->sampler_mask; + key = samplers_shadow; + + if (vs->byte_code.version < 0x30) + key |= state->rs[D3DRS_FOGENABLE] << 8; + + res = vs->last_key != key; + if (res) + vs->next_key = key; + return res; +} + void * -NineVertexShader9_GetVariant( struct NineVertexShader9 *vs, - uint32_t key ); +NineVertexShader9_GetVariant( struct NineVertexShader9 *vs ); /*** public ***/ diff --git a/src/gallium/state_trackers/nine/volume9.c b/src/gallium/state_trackers/nine/volume9.c index 4dfc5599a8e..0b9005685a9 100644 --- a/src/gallium/state_trackers/nine/volume9.c +++ b/src/gallium/state_trackers/nine/volume9.c @@ -23,6 +23,7 @@ #include "device9.h" #include "volume9.h" #include "basetexture9.h" /* for marking dirty */ +#include "volumetexture9.h" #include "nine_helpers.h" #include "nine_pipe.h" #include "nine_dump.h" @@ -43,7 +44,7 @@ NineVolume9_AllocateData( struct NineVolume9 *This ) DBG("(%p(This=%p),level=%u) Allocating 0x%x bytes of system memory.\n", This->base.container, This, This->level, size); - This->data = (uint8_t *)MALLOC(size); + This->data = (uint8_t *)align_malloc(size, 32); if (!This->data) return E_OUTOFMEMORY; return D3D_OK; @@ -182,47 +183,23 @@ NineVolume9_GetDesc( struct NineVolume9 *This, return D3D_OK; } -static inline boolean -NineVolume9_IsDirty(struct NineVolume9 *This) -{ - return This->dirty_box[0].width != 0; -} - inline void NineVolume9_AddDirtyRegion( struct NineVolume9 *This, const struct pipe_box *box ) { - struct pipe_box cover_a, cover_b; - float vol[2]; + D3DBOX dirty_region; + struct NineVolumeTexture9 *tex = NineVolumeTexture9(This->base.container); if (!box) { - u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, - This->desc.Depth, &This->dirty_box[0]); - memset(&This->dirty_box[1], 0, sizeof(This->dirty_box[1])); - return; - } - if (!This->dirty_box[0].width) { - This->dirty_box[0] = *box; - return; - } - - u_box_union_3d(&cover_a, &This->dirty_box[0], box); - vol[0] = u_box_volume_3d(&cover_a); - - if (This->dirty_box[1].width == 0) { - vol[1] = u_box_volume_3d(&This->dirty_box[0]); - if (vol[0] > (vol[1] * 1.5f)) - This->dirty_box[1] = *box; - else - This->dirty_box[0] = cover_a; + NineVolumeTexture9_AddDirtyBox(tex, NULL); } else { - u_box_union_3d(&cover_b, &This->dirty_box[1], box); - vol[1] = u_box_volume_3d(&cover_b); - - if (vol[0] > vol[1]) - This->dirty_box[1] = cover_b; - else - This->dirty_box[0] = cover_a; + dirty_region.Left = box->x << This->level_actual; + dirty_region.Top = box->y << This->level_actual; + dirty_region.Front = box->z << This->level_actual; + dirty_region.Right = dirty_region.Left + (box->width << This->level_actual); + dirty_region.Bottom = dirty_region.Top + (box->height << This->level_actual); + dirty_region.Back = dirty_region.Front + (box->depth << This->level_actual); + NineVolumeTexture9_AddDirtyBox(tex, &dirty_region); } } @@ -254,21 +231,26 @@ NineVolume9_LockBox( struct NineVolume9 *This, pBox ? pBox->Front : 0, pBox ? pBox->Back : 0, nine_D3DLOCK_to_str(Flags)); + /* check if it's already locked */ + user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); + + /* set pBits to NULL after lock_count check */ + user_assert(pLockedVolume, E_POINTER); + pLockedVolume->pBits = NULL; + user_assert(This->desc.Pool != D3DPOOL_DEFAULT || (This->desc.Usage & D3DUSAGE_DYNAMIC), D3DERR_INVALIDCALL); user_assert(!((Flags & D3DLOCK_DISCARD) && (Flags & D3DLOCK_READONLY)), D3DERR_INVALIDCALL); - user_assert(This->lock_count == 0, D3DERR_INVALIDCALL); - user_assert(pLockedVolume, E_POINTER); - - if (pBox && This->desc.Pool == D3DPOOL_DEFAULT && - util_format_is_compressed(This->info.format)) { + if (pBox && compressed_format (This->desc.Format)) { /* For volume all pools are checked */ const unsigned w = util_format_get_blockwidth(This->info.format); const unsigned h = util_format_get_blockheight(This->info.format); - user_assert(!(pBox->Left % w) && !(pBox->Right % w) && - !(pBox->Top % h) && !(pBox->Bottom % h), + user_assert((pBox->Left == 0 && pBox->Right == This->desc.Width && + pBox->Top == 0 && pBox->Bottom == This->desc.Height) || + (!(pBox->Left % w) && !(pBox->Right % w) && + !(pBox->Top % h) && !(pBox->Bottom % h)), D3DERR_INVALIDCALL); } @@ -312,8 +294,7 @@ NineVolume9_LockBox( struct NineVolume9 *This, if (!(Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY))) { NineVolume9_MarkContainerDirty(This); - if (This->desc.Pool == D3DPOOL_MANAGED) - NineVolume9_AddDirtyRegion(This, &box); + NineVolume9_AddDirtyRegion(This, &box); } ++This->lock_count; @@ -333,42 +314,31 @@ NineVolume9_UnlockBox( struct NineVolume9 *This ) return D3D_OK; } - +/* When this function is called, we have already checked + * The copy regions fit the volumes */ HRESULT -NineVolume9_CopyVolume( struct NineVolume9 *This, - struct NineVolume9 *From, - unsigned dstx, unsigned dsty, unsigned dstz, - struct pipe_box *pSrcBox ) +NineVolume9_CopyMemToDefault( struct NineVolume9 *This, + struct NineVolume9 *From, + unsigned dstx, unsigned dsty, unsigned dstz, + struct pipe_box *pSrcBox ) { struct pipe_context *pipe = This->pipe; struct pipe_resource *r_dst = This->resource; - struct pipe_resource *r_src = From->resource; - struct pipe_transfer *transfer; struct pipe_box src_box; struct pipe_box dst_box; - uint8_t *p_dst; const uint8_t *p_src; DBG("This=%p From=%p dstx=%u dsty=%u dstz=%u pSrcBox=%p\n", This, From, dstx, dsty, dstz, pSrcBox); - assert(This->desc.Pool != D3DPOOL_MANAGED && - From->desc.Pool != D3DPOOL_MANAGED); - user_assert(This->desc.Format == From->desc.Format, D3DERR_INVALIDCALL); + assert(This->desc.Pool == D3DPOOL_DEFAULT && + From->desc.Pool == D3DPOOL_SYSTEMMEM); dst_box.x = dstx; dst_box.y = dsty; dst_box.z = dstz; if (pSrcBox) { - /* make sure it doesn't range outside the source volume */ - user_assert(pSrcBox->x >= 0 && - (pSrcBox->width - pSrcBox->x) <= From->desc.Width && - pSrcBox->y >= 0 && - (pSrcBox->height - pSrcBox->y) <= From->desc.Height && - pSrcBox->z >= 0 && - (pSrcBox->depth - pSrcBox->z) <= From->desc.Depth, - D3DERR_INVALIDCALL); src_box = *pSrcBox; } else { src_box.x = 0; @@ -378,101 +348,54 @@ NineVolume9_CopyVolume( struct NineVolume9 *This, src_box.height = From->desc.Height; src_box.depth = From->desc.Depth; } - /* limits */ - dst_box.width = This->desc.Width - dst_box.x; - dst_box.height = This->desc.Height - dst_box.y; - dst_box.depth = This->desc.Depth - dst_box.z; - - user_assert(src_box.width <= dst_box.width && - src_box.height <= dst_box.height && - src_box.depth <= dst_box.depth, D3DERR_INVALIDCALL); dst_box.width = src_box.width; dst_box.height = src_box.height; dst_box.depth = src_box.depth; - if (r_dst && r_src) { - pipe->resource_copy_region(pipe, - r_dst, This->level, - dst_box.x, dst_box.y, dst_box.z, - r_src, From->level, - &src_box); - } else - if (r_dst) { - p_src = NineVolume9_GetSystemMemPointer(From, - src_box.x, src_box.y, src_box.z); - - pipe->transfer_inline_write(pipe, r_dst, This->level, - 0, /* WRITE|DISCARD are implicit */ - &dst_box, p_src, - From->stride, From->layer_stride); - } else - if (r_src) { - p_dst = NineVolume9_GetSystemMemPointer(This, 0, 0, 0); - p_src = pipe->transfer_map(pipe, r_src, From->level, - PIPE_TRANSFER_READ, - &src_box, &transfer); - if (!p_src) - return D3DERR_DRIVERINTERNALERROR; - - util_copy_box(p_dst, This->info.format, - This->stride, This->layer_stride, - dst_box.x, dst_box.y, dst_box.z, - dst_box.width, dst_box.height, dst_box.depth, - p_src, - transfer->stride, transfer->layer_stride, - src_box.x, src_box.y, src_box.z); + p_src = NineVolume9_GetSystemMemPointer(From, + src_box.x, src_box.y, src_box.z); - pipe->transfer_unmap(pipe, transfer); - } else { - p_dst = NineVolume9_GetSystemMemPointer(This, 0, 0, 0); - p_src = NineVolume9_GetSystemMemPointer(From, 0, 0, 0); - - util_copy_box(p_dst, This->info.format, - This->stride, This->layer_stride, - dst_box.x, dst_box.y, dst_box.z, - dst_box.width, dst_box.height, dst_box.depth, - p_src, - From->stride, From->layer_stride, - src_box.x, src_box.y, src_box.z); - } + pipe->transfer_inline_write(pipe, r_dst, This->level, + 0, /* WRITE|DISCARD are implicit */ + &dst_box, p_src, + From->stride, From->layer_stride); - if (This->desc.Pool == D3DPOOL_DEFAULT) - NineVolume9_MarkContainerDirty(This); - if (!r_dst && This->resource) - NineVolume9_AddDirtyRegion(This, &dst_box); + NineVolume9_MarkContainerDirty(This); return D3D_OK; } HRESULT -NineVolume9_UploadSelf( struct NineVolume9 *This ) +NineVolume9_UploadSelf( struct NineVolume9 *This, + const struct pipe_box *damaged ) { struct pipe_context *pipe = This->pipe; struct pipe_resource *res = This->resource; + struct pipe_box box; uint8_t *ptr; - unsigned i; - DBG("This=%p dirty=%i data=%p res=%p\n", This, NineVolume9_IsDirty(This), + DBG("This=%p damaged=%p data=%p res=%p\n", This, damaged, This->data, res); assert(This->desc.Pool == D3DPOOL_MANAGED); - - if (!NineVolume9_IsDirty(This)) - return D3D_OK; assert(res); - for (i = 0; i < Elements(This->dirty_box); ++i) { - const struct pipe_box *box = &This->dirty_box[i]; - if (box->width == 0) - break; - ptr = NineVolume9_GetSystemMemPointer(This, box->x, box->y, box->z); - - pipe->transfer_inline_write(pipe, res, This->level, - 0, - box, ptr, This->stride, This->layer_stride); + if (damaged) { + box = *damaged; + } else { + box.x = 0; + box.y = 0; + box.z = 0; + box.width = This->desc.Width; + box.height = This->desc.Height; + box.depth = This->desc.Depth; } - NineVolume9_ClearDirtyRegion(This); + + ptr = NineVolume9_GetSystemMemPointer(This, box.x, box.y, box.z); + + pipe->transfer_inline_write(pipe, res, This->level, 0, &box, + ptr, This->stride, This->layer_stride); return D3D_OK; } diff --git a/src/gallium/state_trackers/nine/volume9.h b/src/gallium/state_trackers/nine/volume9.h index fae24310a50..26ca8a32605 100644 --- a/src/gallium/state_trackers/nine/volume9.h +++ b/src/gallium/state_trackers/nine/volume9.h @@ -50,8 +50,6 @@ struct NineVolume9 struct pipe_transfer *transfer; unsigned lock_count; - struct pipe_box dirty_box[2]; - struct pipe_context *pipe; /* for [GS]etPrivateData/FreePrivateData */ @@ -85,20 +83,15 @@ void NineVolume9_AddDirtyRegion( struct NineVolume9 *This, const struct pipe_box *box ); -static inline void -NineVolume9_ClearDirtyRegion( struct NineVolume9 *This ) -{ - memset(&This->dirty_box, 0, sizeof(This->dirty_box)); -} - HRESULT -NineVolume9_CopyVolume( struct NineVolume9 *This, - struct NineVolume9 *From, - unsigned dstx, unsigned dsty, unsigned dstz, - struct pipe_box *pSrcBox ); +NineVolume9_CopyMemToDefault( struct NineVolume9 *This, + struct NineVolume9 *From, + unsigned dstx, unsigned dsty, unsigned dstz, + struct pipe_box *pSrcBox ); HRESULT -NineVolume9_UploadSelf( struct NineVolume9 *This ); +NineVolume9_UploadSelf( struct NineVolume9 *This, + const struct pipe_box *damaged ); /*** Direct3D public ***/ diff --git a/src/gallium/state_trackers/nine/volumetexture9.c b/src/gallium/state_trackers/nine/volumetexture9.c index 1193e12f34c..e5b2b53148d 100644 --- a/src/gallium/state_trackers/nine/volumetexture9.c +++ b/src/gallium/state_trackers/nine/volumetexture9.c @@ -64,6 +64,13 @@ NineVolumeTexture9_ctor( struct NineVolumeTexture9 *This, if (Format == D3DFMT_ATI1 || Format == D3DFMT_ATI2) return D3DERR_INVALIDCALL; + if (compressed_format(Format)) { + const unsigned w = util_format_get_blockwidth(pf); + const unsigned h = util_format_get_blockheight(pf); + /* Compressed formats are not compressed on depth component */ + user_assert(!(Width % w) && !(Height % h), D3DERR_INVALIDCALL); + } + info->screen = pParams->device->screen; info->target = PIPE_TEXTURE_3D; info->format = pf; @@ -116,6 +123,9 @@ NineVolumeTexture9_ctor( struct NineVolumeTexture9 *This, return hr; } + /* Textures start initially dirty */ + NineVolumeTexture9_AddDirtyBox(This, NULL); + return D3D_OK; } @@ -193,12 +203,14 @@ NineVolumeTexture9_AddDirtyBox( struct NineVolumeTexture9 *This, { DBG("This=%p pDirtybox=%p\n", This, pDirtyBox); - if (This->base.base.pool != D3DPOOL_MANAGED) { + if (This->base.base.pool == D3DPOOL_DEFAULT) { return D3D_OK; } - This->base.managed.dirty = TRUE; - BASETEX_REGISTER_UPDATE(&This->base); + if (This->base.base.pool == D3DPOOL_MANAGED) { + This->base.managed.dirty = TRUE; + BASETEX_REGISTER_UPDATE(&This->base); + } if (!pDirtyBox) { This->dirty_box.x = 0; diff --git a/src/gallium/targets/d3dadapter9/Makefile.am b/src/gallium/targets/d3dadapter9/Makefile.am index fe5b0b11679..e26ca33a521 100644 --- a/src/gallium/targets/d3dadapter9/Makefile.am +++ b/src/gallium/targets/d3dadapter9/Makefile.am @@ -54,6 +54,7 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = d3d.pc d3dadapter9_la_SOURCES = \ + description.c \ getproc.c \ drm.c diff --git a/src/gallium/targets/d3dadapter9/description.c b/src/gallium/targets/d3dadapter9/description.c new file mode 100644 index 00000000000..c0a86782f8e --- /dev/null +++ b/src/gallium/targets/d3dadapter9/description.c @@ -0,0 +1,324 @@ +/* + * Copyright 2015 Patrick Rudolph <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include <string.h> +#include "adapter9.h" + +#define DBG_CHANNEL DBG_ADAPTER + +/* prototypes */ +void +d3d_match_vendor_id( D3DADAPTER_IDENTIFIER9* drvid, + unsigned fallback_ven, + unsigned fallback_dev, + const char* fallback_name ); +void d3d_fill_driver_version(D3DADAPTER_IDENTIFIER9* drvid); +void d3d_fill_cardname(D3DADAPTER_IDENTIFIER9* drvid); + +enum d3d_vendor_id +{ + HW_VENDOR_SOFTWARE = 0x0000, + HW_VENDOR_AMD = 0x1002, + HW_VENDOR_NVIDIA = 0x10de, + HW_VENDOR_VMWARE = 0x15ad, + HW_VENDOR_INTEL = 0x8086, +}; + +struct card_lookup_table { + const char *mesaname; + const char *d3d9name; +} +cards_amd[] = { + {"HAWAII", "AMD Radeon R9 290"}, + {"KAVERI", "AMD Radeon(TM) R7 Graphics"}, + {"KABINI", "AMD Radeon HD 8400 / R3 Series"}, + {"BONAIRE", "AMD Radeon HD 8770"}, + {"OLAND", "AMD Radeon HD 8670"}, + {"HAINAN", "AMD Radeon HD 8600M Series"}, + {"TAHITI", "AMD Radeon HD 7900 Series"}, + {"PITCAIRN", "AMD Radeon HD 7800 Series"}, + {"CAPE VERDE", "AMD Radeon HD 7700 Series"}, + {"ARUBA", "AMD Radeon HD 7660D"}, + {"CAYMAN", "AMD Radeon HD 6900 Series"}, + {"BARTS", "AMD Radeon HD 6800 Series"}, + {"TURKS", "AMD Radeon HD 6600 Series"}, + {"SUMO2", "AMD Radeon HD 6410D"}, + {"SUMO", "AMD Radeon HD 6550D"}, + {"CAICOS", "AMD Radeon HD 6400 Series"}, + {"PALM", "AMD Radeon HD 6300 series Graphics"}, + {"HEMLOCK", "ATI Radeon HD 5900 Series"}, + {"CYPRESS", "ATI Radeon HD 5800 Series"}, + {"JUNIPER", "ATI Radeon HD 5700 Series"}, + {"REDWOOD", "ATI Radeon HD 5600 Series"}, + {"CEDAR", "ATI Radeon HD 5500 Series"}, + {"R700", "ATI Radeon HD 4800 Series"}, + {"RV790", "ATI Radeon HD 4800 Series"}, + {"RV770", "ATI Radeon HD 4800 Series"}, + {"RV740", "ATI Radeon HD 4700 Series"}, + {"RV730", "ATI Radeon HD 4600 Series"}, + {"RV710", "ATI Radeon HD 4350"}, + {"RS880", "ATI Mobility Radeon HD 4200"}, + {"RS780", "ATI Radeon HD 3200 Graphics"}, + {"R680", "ATI Radeon HD 2900 XT"}, + {"R600", "ATI Radeon HD 2900 XT"}, + {"RV670", "ATI Radeon HD 2900 XT"}, + {"RV635", "ATI Mobility Radeon HD 2600"}, + {"RV630", "ATI Mobility Radeon HD 2600"}, + {"RV620", "ATI Mobility Radeon HD 2350"}, + {"RV610", "ATI Mobility Radeon HD 2350"}, + {"R580", "ATI Radeon X1600 Series"}, + {"R520", "ATI Radeon X1600 Series"}, + {"RV570", "ATI Radeon X1600 Series"}, + {"RV560", "ATI Radeon X1600 Series"}, + {"RV535", "ATI Radeon X1600 Series"}, + {"RV530", "ATI Radeon X1600 Series"}, + {"RV516", "ATI Radeon X700 SE"}, + {"RV515", "ATI Radeon X700 SE"}, + {"R481", "ATI Radeon X700 SE"}, + {"R480", "ATI Radeon X700 SE"}, + {"R430", "ATI Radeon X700 SE"}, + {"R423", "ATI Radeon X700 SE"}, + {"R420", "ATI Radeon X700 SE"}, + {"R410", "ATI Radeon X700 SE"}, + {"RV410", "ATI Radeon X700 SE"}, + {"RS740", "ATI RADEON XPRESS 200M Series"}, + {"RS690", "ATI RADEON XPRESS 200M Series"}, + {"RS600", "ATI RADEON XPRESS 200M Series"}, + {"RS485", "ATI RADEON XPRESS 200M Series"}, + {"RS482", "ATI RADEON XPRESS 200M Series"}, + {"RS480", "ATI RADEON XPRESS 200M Series"}, + {"RS400", "ATI RADEON XPRESS 200M Series"}, + {"R360", "ATI Radeon 9500"}, + {"R350", "ATI Radeon 9500"}, + {"R300", "ATI Radeon 9500"}, + {"RV370", "ATI Radeon 9500"}, + {"RV360", "ATI Radeon 9500"}, + {"RV351", "ATI Radeon 9500"}, + {"RV350", "ATI Radeon 9500"}, +}, +cards_nvidia[] = +{ + {"NV124", "NVIDIA GeForce GTX 970"}, + {"NV117", "NVIDIA GeForce GTX 750"}, + {"NVF1", "NVIDIA GeForce GTX 780 Ti"}, + {"NVF0", "NVIDIA GeForce GTX 780"}, + {"NVE6", "NVIDIA GeForce GTX 770M"}, + {"NVE4", "NVIDIA GeForce GTX 680"}, + {"NVD9", "NVIDIA GeForce GT 520"}, + {"NVCF", "NVIDIA GeForce GTX 550 Ti"}, + {"NVCE", "NVIDIA GeForce GTX 560"}, + {"NVC8", "NVIDIA GeForce GTX 570"}, + {"NVC4", "NVIDIA GeForce GTX 460"}, + {"NVC3", "NVIDIA GeForce GT 440"}, + {"NVC1", "NVIDIA GeForce GT 420"}, + {"NVC0", "NVIDIA GeForce GTX 480"}, + {"NVAF", "NVIDIA GeForce GT 320M"}, + {"NVAC", "NVIDIA GeForce 8200"}, + {"NVAA", "NVIDIA GeForce 8200"}, + {"NVA8", "NVIDIA GeForce 210"}, + {"NVA5", "NVIDIA GeForce GT 220"}, + {"NVA3", "NVIDIA GeForce GT 240"}, + {"NVA0", "NVIDIA GeForce GTX 280"}, + {"NV98", "NVIDIA GeForce 9200"}, + {"NV96", "NVIDIA GeForce 9400 GT"}, + {"NV94", "NVIDIA GeForce 9600 GT"}, + {"NV92", "NVIDIA GeForce 9800 GT"}, + {"NV86", "NVIDIA GeForce 8500 GT"}, + {"NV84", "NVIDIA GeForce 8600 GT"}, + {"NV50", "NVIDIA GeForce 8800 GTX"}, + {"NV68", "NVIDIA GeForce 6200"}, + {"NV67", "NVIDIA GeForce 6200"}, + {"NV63", "NVIDIA GeForce 6200"}, + {"NV4E", "NVIDIA GeForce 6200"}, + {"NV4C", "NVIDIA GeForce 6200"}, + {"NV4B", "NVIDIA GeForce 7600 GT"}, + {"NV4A", "NVIDIA GeForce 6200"}, + {"NV49", "NVIDIA GeForce 7800 GT"}, + {"NV47", "NVIDIA GeForce 7800 GT"}, + {"NV46", "NVIDIA GeForce Go 7400",}, + {"NV45", "NVIDIA GeForce 6800"}, + {"NV44", "NVIDIA GeForce 6200"}, + {"NV43", "NVIDIA GeForce 6600 GT"}, + {"NV42", "NVIDIA GeForce 6800"}, + {"NV41", "NVIDIA GeForce 6800"}, + {"NV40", "NVIDIA GeForce 6800"}, + {"NV38", "NVIDIA GeForce FX 5800"}, + {"NV36", "NVIDIA GeForce FX 5800"}, + {"NV35", "NVIDIA GeForce FX 5800"}, + {"NV34", "NVIDIA GeForce FX 5200"}, + {"NV31", "NVIDIA GeForce FX 5600"}, + {"NV30", "NVIDIA GeForce FX 5800"}, + {"nv28", "NVIDIA GeForce4 Ti 4200"}, + {"nv25", "NVIDIA GeForce4 Ti 4200"}, + {"nv20", "NVIDIA GeForce3"}, + {"nv1F", "NVIDIA GeForce4 MX 460"}, + {"nv1A", "NVIDIA GeForce2 GTS/GeForce2 Pro"}, + {"nv18", "NVIDIA GeForce4 MX 460"}, + {"nv17", "NVIDIA GeForce4 MX 460"}, + {"nv16", "NVIDIA GeForce2 GTS/GeForce2 Pro"}, + {"nv15", "NVIDIA GeForce2 GTS/GeForce2 Pro"}, + {"nv11", "NVIDIA GeForce2 MX/MX 400"}, + {"nv10", "NVIDIA GeForce 256"}, +}, +cards_vmware[] = +{ + {"SVGA3D", "VMware SVGA 3D (Microsoft Corporation - WDDM)"}, +}, +cards_intel[] = +{ + {"Haswell Mobile", "Intel(R) Haswell Mobile"}, + {"Ivybridge Server", "Intel(R) Ivybridge Server"}, + {"Ivybridge Mobile", "Intel(R) Ivybridge Mobile"}, + {"Ivybridge Desktop", "Intel(R) Ivybridge Desktop"}, + {"Sandybridge Server", "Intel(R) Sandybridge Server"}, + {"Sandybridge Mobile", "Intel(R) Sandybridge Mobile"}, + {"Sandybridge Desktop", "Intel(R) Sandybridge Desktop"}, + {"Ironlake Mobile", "Intel(R) Ironlake Mobile"}, + {"Ironlake Desktop", "Intel(R) Ironlake Desktop"}, + {"B43", "Intel(R) B43"}, + {"G41", "Intel(R) G41"}, + {"G45", "Intel(R) G45/G43"}, + {"Q45", "Intel(R) Q45/Q43"}, + {"Integrated Graphics Device", "Intel(R) Integrated Graphics Device"}, + {"GM45", "Mobile Intel(R) GM45 Express Chipset Family"}, + {"965GME", "Intel(R) 965GME"}, + {"965GM", "Mobile Intel(R) 965 Express Chipset Family"}, + {"946GZ", "Intel(R) 946GZ"}, + {"965G", "Intel(R) 965G"}, + {"965Q", "Intel(R) 965Q"}, + {"Pineview M", "Intel(R) IGD"}, + {"Pineview G", "Intel(R) IGD"}, + {"IGD", "Intel(R) IGD"}, + {"Q33", "Intel(R) Q33"}, + {"G33", "Intel(R) G33"}, + {"Q35", "Intel(R) Q35"}, + {"945GME", "Intel(R) 945GME"}, + {"945GM", "Mobile Intel(R) 945GM Express Chipset Family"}, + {"945G", "Intel(R) 945G"}, + {"915GM", "Mobile Intel(R) 915GM/GMS,910GML Express Chipset Family"}, + {"E7221G", "Intel(R) E7221G"}, + {"915G", "Intel(R) 82915G/GV/910GL Express Chipset Family"}, + {"865G", "Intel(R) 82865G Graphics Controller"}, + {"845G", "Intel(R) 845G"}, + {"855GM", "Intel(R) 82852/82855 GM/GME Graphics Controller"}, + {"830M", "Intel(R) 82830M Graphics Controller"}, +}; + +/* override VendorId, DeviceId and Description for unknown vendors */ +void +d3d_match_vendor_id( D3DADAPTER_IDENTIFIER9* drvid, + unsigned fallback_ven, + unsigned fallback_dev, + const char* fallback_name ) +{ + if (drvid->VendorId == HW_VENDOR_INTEL || + drvid->VendorId == HW_VENDOR_VMWARE || + drvid->VendorId == HW_VENDOR_AMD || + drvid->VendorId == HW_VENDOR_NVIDIA) + return; + + DBG("unknown vendor 0x4%x, emulating 0x4%x\n", drvid->VendorId, fallback_ven); + drvid->VendorId = fallback_ven; + drvid->DeviceId = fallback_dev; + strncpy(drvid->Description, fallback_name, sizeof(drvid->Description)); +} + +/* fill in driver name and version */ +void d3d_fill_driver_version(D3DADAPTER_IDENTIFIER9* drvid) { + switch (drvid->VendorId) { + case HW_VENDOR_INTEL: + drvid->DriverVersionLowPart = 0x000A0682; + drvid->DriverVersionHighPart = 0x0006000F; + strncpy(drvid->Driver, "igdumd32.dll", sizeof(drvid->Driver)); + break; + case HW_VENDOR_VMWARE: + drvid->DriverVersionLowPart = 0x0001046E; + drvid->DriverVersionHighPart = 0x0006000E; + strncpy(drvid->Driver, "vm3dum.dll", sizeof(drvid->Driver)); + break; + case HW_VENDOR_AMD: + drvid->DriverVersionLowPart = 0x000A0500; + drvid->DriverVersionHighPart = 0x00060011; + strncpy(drvid->Driver, "atiumdag.dll", sizeof(drvid->Driver)); + break; + case HW_VENDOR_NVIDIA: + drvid->DriverVersionLowPart = 0x000D0FD4; + drvid->DriverVersionHighPart = 0x00060012; + strncpy(drvid->Driver, "nvd3dum.dll", sizeof(drvid->Driver)); + break; + default: + break; + } +} + +/* try to match the device name and override it with Windows like device names */ +void d3d_fill_cardname(D3DADAPTER_IDENTIFIER9* drvid) { + unsigned i; + switch (drvid->VendorId) { + case HW_VENDOR_INTEL: + for (i = 0; i < sizeof(cards_intel) / sizeof(cards_intel[0]); i++) { + if (strstr(drvid->Description, cards_intel[i].mesaname)) { + strncpy(drvid->Description, cards_intel[i].d3d9name, sizeof(drvid->Description)); + return; + } + } + /* use a fall-back if nothing matches */ + DBG("Unknown card name %s!\n", drvid->DeviceName); + strncpy(drvid->Description, cards_intel[0].d3d9name, sizeof(drvid->Description)); + break; + case HW_VENDOR_VMWARE: + for (i = 0; i < sizeof(cards_vmware) / sizeof(cards_vmware[0]); i++) { + if (strstr(drvid->Description, cards_vmware[i].mesaname)) { + strncpy(drvid->Description, cards_vmware[i].d3d9name, sizeof(drvid->Description)); + return; + } + } + /* use a fall-back if nothing matches */ + DBG("Unknown card name %s!\n", drvid->DeviceName); + strncpy(drvid->Description, cards_vmware[0].d3d9name, sizeof(drvid->Description)); + break; + case HW_VENDOR_AMD: + for (i = 0; i < sizeof(cards_amd) / sizeof(cards_amd[0]); i++) { + if (strstr(drvid->Description, cards_amd[i].mesaname)) { + strncpy(drvid->Description, cards_amd[i].d3d9name, sizeof(drvid->Description)); + return; + } + } + /* use a fall-back if nothing matches */ + DBG("Unknown card name %s!\n", drvid->DeviceName); + strncpy(drvid->Description, cards_amd[0].d3d9name, sizeof(drvid->Description)); + break; + case HW_VENDOR_NVIDIA: + for (i = 0; i < sizeof(cards_nvidia) / sizeof(cards_nvidia[0]); i++) { + if (strstr(drvid->Description, cards_nvidia[i].mesaname)) { + strncpy(drvid->Description, cards_nvidia[i].d3d9name, sizeof(drvid->Description)); + return; + } + } + /* use a fall-back if nothing matches */ + DBG("Unknown card name %s!\n", drvid->DeviceName); + strncpy(drvid->Description, cards_nvidia[0].d3d9name, sizeof(drvid->Description)); + break; + default: + break; + } +} diff --git a/src/gallium/targets/d3dadapter9/drm.c b/src/gallium/targets/d3dadapter9/drm.c index 680f5164e60..fabc820f268 100644 --- a/src/gallium/targets/d3dadapter9/drm.c +++ b/src/gallium/targets/d3dadapter9/drm.c @@ -46,12 +46,6 @@ #define DBG_CHANNEL DBG_ADAPTER -#define VERSION_DWORD(hi, lo) \ - ((DWORD)( \ - ((DWORD)((hi) & 0xFFFF) << 16) | \ - (DWORD)((lo) & 0xFFFF) \ - )) - const char __driConfigOptionsNine[] = DRI_CONF_BEGIN DRI_CONF_SECTION_PERFORMANCE @@ -63,12 +57,21 @@ DRI_CONF_BEGIN DRI_CONF_SECTION_END DRI_CONF_END; -/* Regarding os versions, we should not define our own as that would simply be - * weird. Defaulting to Win2k/XP seems sane considering the origin of D3D9. The - * driver also defaults to being a generic D3D9 driver, which of course only - * matters if you're actually using the DDI. */ -#define VERSION_HIGH VERSION_DWORD(0x0006, 0x000E) /* winxp, d3d9 */ -#define VERSION_LOW VERSION_DWORD(0x0000, 0x0001) /* version, build */ +/* define fallback value here: NVIDIA GeForce GTX 970 */ +#define FALLBACK_NAME "NV124" +#define FALLBACK_DEVID 0x13C2 +#define FALLBACK_VENID 0x10de + +/* prototypes */ +void +d3d_match_vendor_id( D3DADAPTER_IDENTIFIER9* drvid, + unsigned fallback_ven, + unsigned fallback_dev, + const char* fallback_name ); + +void d3d_fill_driver_version(D3DADAPTER_IDENTIFIER9* drvid); + +void d3d_fill_cardname(D3DADAPTER_IDENTIFIER9* drvid); struct d3dadapter9drm_context { @@ -152,9 +155,9 @@ get_bus_info( int fd, *subsysid = 0; *revision = 0; } else { - DBG("Unable to detect card. Fake GTX 680.\n"); - *vendorid = 0x10de; /* NV GTX 680 */ - *deviceid = 0x1180; + DBG("Unable to detect card. Faking %s\n", FALLBACK_NAME); + *vendorid = FALLBACK_VENID; + *deviceid = FALLBACK_DEVID; *subsysid = 0; *revision = 0; } @@ -169,33 +172,23 @@ read_descriptor( struct d3dadapter9_context *ctx, memset(drvid, 0, sizeof(*drvid)); get_bus_info(fd, &drvid->VendorId, &drvid->DeviceId, &drvid->SubSysId, &drvid->Revision); + snprintf(drvid->DeviceName, sizeof(drvid->DeviceName), + "Gallium 0.4 with %s", ctx->hal->get_vendor(ctx->hal)); + strncpy(drvid->Description, ctx->hal->get_name(ctx->hal), + sizeof(drvid->Description)); + + /* choose fall-back vendor if necessary to allow + * the following functions to return sane results */ + d3d_match_vendor_id(drvid, FALLBACK_VENID, FALLBACK_DEVID, FALLBACK_NAME); + /* fill in driver name and version info */ + d3d_fill_driver_version(drvid); + /* override Description field with Windows like names */ + d3d_fill_cardname(drvid); + + /* this driver isn't WHQL certified */ + drvid->WHQLLevel = 0; - strncpy(drvid->Driver, "libd3dadapter9.so", sizeof(drvid->Driver)); - strncpy(drvid->DeviceName, ctx->hal->get_name(ctx->hal), 32); - snprintf(drvid->Description, sizeof(drvid->Description), - "Gallium 0.4 with %s", ctx->hal->get_vendor(ctx->hal)); - - drvid->DriverVersionLowPart = VERSION_LOW; - drvid->DriverVersionHighPart = VERSION_HIGH; - - /* To make a pseudo-real GUID we use the PCI bus data and some string */ - drvid->DeviceIdentifier.Data1 = drvid->VendorId; - drvid->DeviceIdentifier.Data2 = drvid->DeviceId; - drvid->DeviceIdentifier.Data3 = drvid->SubSysId; - memcpy(drvid->DeviceIdentifier.Data4, "Gallium3D", 8); - - drvid->WHQLLevel = 1; /* This fakes WHQL validaion */ - - /* XXX Fake NVIDIA binary driver on Windows. - * - * OS version: 4=95/98/NT4, 5=2000, 6=2000/XP, 7=Vista, 8=Win7 - */ - strncpy(drvid->Driver, "nvd3dum.dll", sizeof(drvid->Driver)); - strncpy(drvid->Description, "NVIDIA GeForce GTX 680", sizeof(drvid->Description)); - drvid->DriverVersionLowPart = VERSION_DWORD(12, 6658); /* minor, build */ - drvid->DriverVersionHighPart = VERSION_DWORD(6, 15); /* OS, major */ - drvid->SubSysId = 0; - drvid->Revision = 0; + /* this value is fixed */ drvid->DeviceIdentifier.Data1 = 0xaeb2cdd4; drvid->DeviceIdentifier.Data2 = 0x6e41; drvid->DeviceIdentifier.Data3 = 0x43ea; @@ -207,7 +200,6 @@ read_descriptor( struct d3dadapter9_context *ctx, drvid->DeviceIdentifier.Data4[5] = 0x76; drvid->DeviceIdentifier.Data4[6] = 0x07; drvid->DeviceIdentifier.Data4[7] = 0x81; - drvid->WHQLLevel = 0; } static HRESULT WINAPI diff --git a/src/gallium/targets/dri/Android.mk b/src/gallium/targets/dri/Android.mk index 7168e1dbfb3..a33d7f83671 100644 --- a/src/gallium/targets/dri/Android.mk +++ b/src/gallium/targets/dri/Android.mk @@ -77,8 +77,8 @@ gallium_DRIVERS += libmesa_pipe_r600 LOCAL_CFLAGS += -DGALLIUM_R600 endif ifneq ($(filter radeonsi,$(MESA_GPU_DRIVERS)),) -gallium_DRIVERS += libmesa_pipe_radeonsi -LOCAL_SHARED_LIBRARIES += libLLVM +gallium_DRIVERS += libmesa_pipe_radeonsi libmesa_winsys_amdgpu +LOCAL_SHARED_LIBRARIES += libLLVM libdrm_amdgpu LOCAL_CFLAGS += -DGALLIUM_RADEONSI endif gallium_DRIVERS += libmesa_winsys_radeon libmesa_pipe_radeon diff --git a/src/gallium/winsys/amdgpu/drm/Android.mk b/src/gallium/winsys/amdgpu/drm/Android.mk index 7d507aa79c6..57732347eea 100644 --- a/src/gallium/winsys/amdgpu/drm/Android.mk +++ b/src/gallium/winsys/amdgpu/drm/Android.mk @@ -30,6 +30,16 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(C_SOURCES) +LOCAL_CFLAGS := \ + $(AMDGPU_CFLAGS) \ + -DBRAHMA_BUILD=1 + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/addrlib \ + $(LOCAL_PATH)/addrlib/core \ + $(LOCAL_PATH)/addrlib/inc/chip/r800 \ + $(LOCAL_PATH)/addrlib/r800/chip + LOCAL_SHARED_LIBRARIES := libdrm libdrm_amdgpu LOCAL_MODULE := libmesa_winsys_amdgpu diff --git a/src/gallium/winsys/amdgpu/drm/Makefile.sources b/src/gallium/winsys/amdgpu/drm/Makefile.sources index 6b33841b204..23630044ab3 100644 --- a/src/gallium/winsys/amdgpu/drm/Makefile.sources +++ b/src/gallium/winsys/amdgpu/drm/Makefile.sources @@ -11,9 +11,7 @@ C_SOURCES := \ addrlib/core/addrobject.h \ addrlib/inc/chip/r800/si_gb_reg.h \ addrlib/inc/lnx_common_defs.h \ - addrlib/r800/chip/si_ci_merged_enum.h \ addrlib/r800/chip/si_ci_vi_merged_enum.h \ - addrlib/r800/chip/si_enum.h \ addrlib/r800/ciaddrlib.cpp \ addrlib/r800/ciaddrlib.h \ addrlib/r800/egbaddrlib.cpp \ diff --git a/src/gallium/winsys/amdgpu/drm/amdgpu_cs.h b/src/gallium/winsys/amdgpu/drm/amdgpu_cs.h index 0842259044b..12c6b624b03 100644 --- a/src/gallium/winsys/amdgpu/drm/amdgpu_cs.h +++ b/src/gallium/winsys/amdgpu/drm/amdgpu_cs.h @@ -77,8 +77,8 @@ struct amdgpu_cs { int buffer_indices_hashlist[512]; - unsigned used_vram; - unsigned used_gart; + uint64_t used_vram; + uint64_t used_gart; unsigned max_dependencies; }; diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_cs.c b/src/gallium/winsys/radeon/drm/radeon_drm_cs.c index 7a267f9acbf..f04a696988a 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_cs.c +++ b/src/gallium/winsys/radeon/drm/radeon_drm_cs.c @@ -97,22 +97,17 @@ static boolean radeon_init_cs_context(struct radeon_cs_context *csc, { int i; - csc->buf = MALLOC(ws->ib_max_size); - if (!csc->buf) - return FALSE; csc->fd = ws->fd; csc->nrelocs = 512; csc->relocs_bo = (struct radeon_bo**) CALLOC(1, csc->nrelocs * sizeof(struct radeon_bo*)); if (!csc->relocs_bo) { - FREE(csc->buf); return FALSE; } csc->relocs = (struct drm_radeon_cs_reloc*) CALLOC(1, csc->nrelocs * sizeof(struct drm_radeon_cs_reloc)); if (!csc->relocs) { - FREE(csc->buf); FREE(csc->relocs_bo); return FALSE; } @@ -165,7 +160,6 @@ static void radeon_destroy_cs_context(struct radeon_cs_context *csc) radeon_cs_context_cleanup(csc); FREE(csc->relocs_bo); FREE(csc->relocs); - FREE(csc->buf); } @@ -206,7 +200,7 @@ radeon_drm_cs_create(struct radeon_winsys_ctx *ctx, cs->cst = &cs->csc2; cs->base.buf = cs->csc->buf; cs->base.ring_type = ring_type; - cs->base.max_dw = ws->ib_max_size / 4; + cs->base.max_dw = ARRAY_SIZE(cs->csc->buf); p_atomic_inc(&ws->num_cs); return &cs->base; diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_cs.h b/src/gallium/winsys/radeon/drm/radeon_drm_cs.h index ab154945880..6ceb8e98ee7 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_cs.h +++ b/src/gallium/winsys/radeon/drm/radeon_drm_cs.h @@ -30,7 +30,7 @@ #include "radeon_drm_bo.h" struct radeon_cs_context { - uint32_t *buf; + uint32_t buf[16 * 1024]; int fd; struct drm_radeon_cs cs; diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c index b70bbaa54a3..f7784fb795e 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c +++ b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.c @@ -395,20 +395,16 @@ static boolean do_winsys_init(struct radeon_drm_winsys *ws) } ws->info.r600_virtual_address = FALSE; - ws->ib_max_size = 64 * 1024; - if (ws->info.drm_minor >= 13) { + uint32_t ib_vm_max_size; + ws->info.r600_virtual_address = TRUE; if (!radeon_get_drm_value(ws->fd, RADEON_INFO_VA_START, NULL, &ws->va_start)) ws->info.r600_virtual_address = FALSE; - - if (radeon_get_drm_value(ws->fd, RADEON_INFO_IB_VM_MAX_SIZE, NULL, - &ws->ib_max_size)) - ws->ib_max_size *= 4; /* the kernel returns the size in dwords */ - else + if (!radeon_get_drm_value(ws->fd, RADEON_INFO_IB_VM_MAX_SIZE, NULL, + &ib_vm_max_size)) ws->info.r600_virtual_address = FALSE; - radeon_get_drm_value(ws->fd, RADEON_INFO_VA_UNMAP_WORKING, NULL, &ws->va_unmap_working); } diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h index c1a8d6ae564..308b5bd976d 100644 --- a/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h +++ b/src/gallium/winsys/radeon/drm/radeon_drm_winsys.h @@ -73,7 +73,6 @@ struct radeon_drm_winsys { enum radeon_generation gen; struct radeon_info info; - uint32_t ib_max_size; uint32_t va_start; uint32_t va_unmap_working; uint32_t accel_working2; diff --git a/src/gallium/winsys/sw/kms-dri/Makefile.am b/src/gallium/winsys/sw/kms-dri/Makefile.am index 7f26b1b2f19..8162553289d 100644 --- a/src/gallium/winsys/sw/kms-dri/Makefile.am +++ b/src/gallium/winsys/sw/kms-dri/Makefile.am @@ -31,5 +31,3 @@ AM_CFLAGS = \ noinst_LTLIBRARIES = libswkmsdri.la libswkmsdri_la_SOURCES = $(C_SOURCES) - -EXTRA_DIST = SConscript |