st/nine: Finish Fog implementation
authorAxel Davy <axel.davy@ens.fr>
Tue, 12 May 2015 19:56:04 +0000 (21:56 +0200)
committerAxel Davy <axel.davy@ens.fr>
Fri, 21 Aug 2015 20:21:47 +0000 (22:21 +0200)
Signed-off-by: Axel Davy <axel.davy@ens.fr>
src/gallium/state_trackers/nine/nine_shader.c
src/gallium/state_trackers/nine/nine_shader.h
src/gallium/state_trackers/nine/nine_state.c
src/gallium/state_trackers/nine/nine_state.h
src/gallium/state_trackers/nine/pixelshader9.c
src/gallium/state_trackers/nine/pixelshader9.h
src/gallium/state_trackers/nine/vertexshader9.c
src/gallium/state_trackers/nine/vertexshader9.h

index d9a20a58f8fbed5b681dd8092da4158388636db7..2e35edecaf7bea4f8d7f03d1bec163f6f5cfc95e 100644 (file)
@@ -3199,9 +3199,50 @@ 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;
 
-    /* TODO: fog computation */
-    ureg_MOV(ureg, oCol0, src_col);
+    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( \
@@ -3285,7 +3326,7 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info)
         }
     }
 
-    if (IS_VS && tx->version.major < 3 && ureg_dst_is_undef(tx->regs.oFog)) {
+    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));
     }
index f2b1e8bf6e2badf5e16415bbf487d61ba434581d..3ba79af47c74a12d0d920e378d43204891d763c9 100644 (file)
@@ -59,6 +59,9 @@ 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;
+
     unsigned const_i_base; /* in vec4 (16 byte) units */
     unsigned const_b_base; /* in vec4 (16 byte) units */
     unsigned const_used_size;
@@ -138,4 +141,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_ */
index 610798a3be7874ae03541caae438c9f3444e5a28..53efa56d081680b35ee999635e429a69074e1eec 100644 (file)
@@ -280,9 +280,6 @@ prepare_ps_constants_userbuf(struct NineDevice9 *device)
     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));
@@ -303,6 +300,27 @@ prepare_ps_constants_userbuf(struct NineDevice9 *device)
         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,
@@ -931,7 +949,8 @@ commit_ps(struct NineDevice9 *device)
     NINE_STATE_PS |             \
     NINE_STATE_BLEND_COLOR |    \
     NINE_STATE_STENCIL_REF |    \
-    NINE_STATE_SAMPLE_MASK)
+    NINE_STATE_SAMPLE_MASK |    \
+    NINE_STATE_FOG_SHADER)
 
 #define NINE_STATE_FREQ_GROUP_1 ~NINE_STATE_FREQ_GROUP_0
 
@@ -996,13 +1015,13 @@ nine_update_state(struct NineDevice9 *device)
         if (group & NINE_STATE_BLEND)
             prepare_blend(device);
 
-        if (group & (NINE_STATE_VS | NINE_STATE_TEXTURE))
+        if (group & (NINE_STATE_VS | NINE_STATE_TEXTURE | NINE_STATE_FOG_SHADER))
             group |= prepare_vs(device, (group & NINE_STATE_VS) != 0);
 
         if (group & NINE_STATE_RASTERIZER)
             prepare_rasterizer(device);
 
-        if (group & (NINE_STATE_PS | NINE_STATE_TEXTURE))
+        if (group & (NINE_STATE_PS | NINE_STATE_TEXTURE | NINE_STATE_FOG_SHADER))
             group |= prepare_ps(device, (group & NINE_STATE_PS) != 0);
 
         if (group & NINE_STATE_BLEND_COLOR) {
@@ -1486,13 +1505,13 @@ const uint32_t nine_render_state_group[NINED3DRS_LAST + 1] =
     [D3DRS_ALPHAFUNC] = NINE_STATE_DSA,
     [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,
index efaee1ee95e1127fda0829755de848f934beff89..f1af49fa137b63a5ff6faf2b2cbed68a643869b3 100644 (file)
@@ -75,8 +75,9 @@
 #define NINE_STATE_FF_VSTRANSF (1 << 21)
 #define NINE_STATE_FF_PSSTAGES (1 << 22)
 #define NINE_STATE_FF_OTHER    (1 << 23)
-#define NINE_STATE_ALL          0x0ffffff
-#define NINE_STATE_UNHANDLED   (1 << 24)
+#define NINE_STATE_FOG_SHADER  (1 << 24)
+#define NINE_STATE_ALL          0x1ffffff
+#define NINE_STATE_UNHANDLED   (1 << 25)
 
 #define NINE_STATE_COMMIT_DSA  (1 << 0)
 #define NINE_STATE_COMMIT_RASTERIZER (1 << 1)
index 5399afd369842c77e0f6ffca3a72b1cfe1a8c2aa..6173b0eea05fd8f20072f9bb457980bf072f8505 100644 (file)
@@ -57,6 +57,7 @@ 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;
 
     hr = nine_translate_shader(device, &info);
     if (FAILED(hr))
@@ -90,7 +91,7 @@ NinePixelShader9_dtor( struct NinePixelShader9 *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) {
@@ -107,7 +108,7 @@ NinePixelShader9_dtor( struct NinePixelShader9 *This )
             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 */
 
@@ -138,13 +139,13 @@ void *
 NinePixelShader9_GetVariant( struct NinePixelShader9 *This )
 {
     void *cso;
-    uint32_t key;
+    uint64_t key;
 
     key = This->next_key;
     if (key == This->last_key)
         return This->last_cso;
 
-    cso = nine_shader_variant_get(&This->variant, key);
+    cso = nine_shader_variant_get64(&This->variant, key);
     if (!cso) {
         struct NineDevice9 *device = This->base.device;
         struct nine_shader_info info;
@@ -156,11 +157,13 @@ 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];
 
         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;
     }
 
index 69eb87b2e27d9b38f98d03675244dd408bbeb344..5d1f5041c474d702a2bf7e3a98429b9a4a6d0d90 100644 (file)
@@ -33,7 +33,7 @@ struct nine_lconstf;
 struct NinePixelShader9
 {
     struct NineUnknown base;
-    struct nine_shader_variant variant;
+    struct nine_shader_variant64 variant;
 
     struct {
         const DWORD *tokens;
@@ -50,10 +50,10 @@ struct NinePixelShader9
     uint64_t ff_key[6];
     void *ff_cso;
 
-    uint32_t last_key;
+    uint64_t last_key;
     void *last_cso;
 
-    uint32_t next_key;
+    uint64_t next_key;
 };
 static inline struct NinePixelShader9 *
 NinePixelShader9( void *data )
@@ -67,7 +67,7 @@ NinePixelShader9_UpdateKey( struct NinePixelShader9 *ps,
 {
     uint16_t samplers_shadow;
     uint32_t samplers_ps1_types;
-    uint32_t key;
+    uint64_t key;
     BOOL res;
 
     if (unlikely(ps->byte_code.version < 0x20)) {
@@ -85,6 +85,11 @@ NinePixelShader9_UpdateKey( struct NinePixelShader9 *ps,
         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;
+    }
+
     res = ps->last_key != key;
     if (res)
         ps->next_key = key;
index 956f0234b258c1cc121c01a1f77efc27fe8f2087..fdfb79a138e52794817c9d25b7bbddbb915b8100 100644 (file)
@@ -60,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))
@@ -161,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))
index 6cf7749e0acfb90c46c5f89d31cfe7551588d192..d5720157cc0cc59ee1d3aa5e390d6ef1ae4651f9 100644 (file)
@@ -80,6 +80,9 @@ NineVertexShader9_UpdateKey( struct NineVertexShader9 *vs,
     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;