st/nine: Dummy sampler should have a=1
authorAxel Davy <axel.davy@ens.fr>
Sat, 24 Jan 2015 11:02:04 +0000 (12:02 +0100)
committerAxel Davy <axel.davy@ens.fr>
Thu, 5 Feb 2015 23:07:19 +0000 (00:07 +0100)
Reviewed-by: Tiziano Bacocco <tizbac2@gmail.com>
Signed-off-by: Axel Davy <axel.davy@ens.fr>
src/gallium/state_trackers/nine/device9.c
src/gallium/state_trackers/nine/device9.h
src/gallium/state_trackers/nine/nine_ff.c
src/gallium/state_trackers/nine/nine_state.c
src/gallium/state_trackers/nine/nine_state.h

index 25e1444f6b4e57cdb51e55c4dcf64546210f0725..e0524644f8ade6c9d14afe3358a3dbc9a81c51d2 100644 (file)
@@ -298,6 +298,43 @@ NineDevice9_ctor( struct NineDevice9 *This,
             return E_OUTOFMEMORY;
     }
 
+    /* allocate dummy texture/sampler for when there are missing ones bound */
+    {
+        struct pipe_resource tmplt;
+        struct pipe_sampler_view templ;
+
+        tmplt.target = PIPE_TEXTURE_2D;
+        tmplt.width0 = 1;
+        tmplt.height0 = 1;
+        tmplt.depth0 = 1;
+        tmplt.last_level = 0;
+        tmplt.array_size = 1;
+        tmplt.usage = PIPE_USAGE_DEFAULT;
+        tmplt.flags = 0;
+        tmplt.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+        tmplt.bind = PIPE_BIND_SAMPLER_VIEW;
+        tmplt.nr_samples = 0;
+
+        This->dummy_texture = This->screen->resource_create(This->screen, &tmplt);
+        if (!This->dummy_texture)
+            return D3DERR_DRIVERINTERNALERROR;
+
+        templ.format = PIPE_FORMAT_B8G8R8A8_UNORM;
+        templ.u.tex.first_layer = 0;
+        templ.u.tex.last_layer = 0;
+        templ.u.tex.first_level = 0;
+        templ.u.tex.last_level = 0;
+        templ.swizzle_r = PIPE_SWIZZLE_ZERO;
+        templ.swizzle_g = PIPE_SWIZZLE_ZERO;
+        templ.swizzle_b = PIPE_SWIZZLE_ZERO;
+        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)
+            return D3DERR_DRIVERINTERNALERROR;
+    }
+
     /* Allocate upload helper for drivers that suck (from st pov ;). */
     {
         unsigned bind = 0;
@@ -346,6 +383,8 @@ NineDevice9_dtor( struct NineDevice9 *This )
 
     nine_bind(&This->record, NULL);
 
+    pipe_sampler_view_reference(&This->dummy_sampler, NULL);
+    pipe_resource_reference(&This->dummy_texture, NULL);
     pipe_resource_reference(&This->constbuf_vs, NULL);
     pipe_resource_reference(&This->constbuf_ps, NULL);
     FREE(This->state.vs_const_f);
index dc97ae7161de61cd619ae0e23c920b3556441798..54da9e3a6246eb8ad8207c341c955e2039f3acd5 100644 (file)
@@ -82,6 +82,9 @@ struct NineDevice9
     uint16_t max_vs_const_f;
     uint16_t max_ps_const_f;
 
+    struct pipe_resource *dummy_texture;
+    struct pipe_sampler_view *dummy_sampler;
+
     struct gen_mipmap_state *gen_mipmap;
 
     struct {
index 2e3470f92ef8c58787eff8698cb91aac0fa92db0..e6f2b21dd4d2494439701dea069f561abf5c8b08 100644 (file)
@@ -1493,6 +1493,7 @@ nine_ff_get_ps(struct NineDevice9 *device)
     enum pipe_error err;
     struct nine_ff_ps_key key;
     unsigned s;
+    uint8_t sampler_mask = 0;
 
     assert(sizeof(key) <= sizeof(key.value32));
 
@@ -1506,12 +1507,17 @@ nine_ff_get_ps(struct NineDevice9 *device)
             key.ts[s].alphaop = D3DTOP_DISABLE; /* DISABLE == 1, avoid degenerate keys */
             break;
         }
+
         if (!state->texture[s] &&
             state->ff.tex_stage[s][D3DTSS_COLORARG1] == D3DTA_TEXTURE) {
             /* This should also disable the stage. */
             key.ts[s].colorop = key.ts[s].alphaop = D3DTOP_DISABLE;
             break;
         }
+
+        if (state->ff.tex_stage[s][D3DTSS_COLORARG1] == D3DTA_TEXTURE)
+            sampler_mask |= (1 << s);
+
         if (key.ts[s].colorop != D3DTOP_DISABLE) {
             uint8_t used_c = ps_d3dtop_args_mask(key.ts[s].colorop);
             if (used_c & 0x1) key.ts[s].colorarg0 = state->ff.tex_stage[s][D3DTSS_COLORARG0];
@@ -1570,6 +1576,7 @@ nine_ff_get_ps(struct NineDevice9 *device)
         NineUnknown_ConvertRefToBind(NineUnknown(ps));
 
         ps->rt_mask = 0x1;
+        ps->sampler_mask = sampler_mask;
     }
     return ps;
 }
index 86a6ca8ee40fa3af4d76263ef5e6c893965eaf4b..ba758176f494f6155af76b02e7876fff27addb9f 100644 (file)
@@ -279,6 +279,7 @@ 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)) {
@@ -291,17 +292,13 @@ update_vs(struct NineDevice9 *device)
 
     if (state->rs[NINED3DRS_VSPOINTSIZE] != vs->point_size) {
         state->rs[NINED3DRS_VSPOINTSIZE] = vs->point_size;
-        return NINE_STATE_RASTERIZER;
+        changed_group |= NINE_STATE_RASTERIZER;
     }
-#ifdef DEBUG
-    {
-        unsigned s, mask = vs->sampler_mask;
-        for (s = 0; mask; ++s, mask >>= 1)
-            if ((mask & 1) && !(device->state.texture[NINE_SAMPLER_VS(s)]))
-                WARN_ONCE("FIXME: unbound sampler should return alpha=1\n");
-    }
-#endif
-    return 0;
+
+    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
@@ -309,6 +306,7 @@ 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);
@@ -318,15 +316,10 @@ update_ps(struct NineDevice9 *device)
     }
     device->pipe->bind_fs_state(device->pipe, state->cso.ps);
 
-#ifdef DEBUG
-    {
-        unsigned s, mask = ps->sampler_mask;
-        for (s = 0; mask; ++s, mask >>= 1)
-            if ((mask & 1) && !(device->state.texture[NINE_SAMPLER_PS(s)]))
-                WARN_ONCE("FIXME: unbound sampler should return alpha=1\n");
-    }
-#endif
-    return 0;
+    if ((state->bound_samplers_mask_ps & ps->sampler_mask) != ps->sampler_mask)
+        /* Bound dummy sampler. */
+        changed_group |= NINE_STATE_SAMPLER;
+    return changed_group;
 }
 
 #define DO_UPLOAD_CONST_F(buf,p,c,d) \
@@ -651,66 +644,142 @@ 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) {
         const unsigned s = NINE_SAMPLER_PS(i);
         int sRGB;
-        if (!state->texture[s]) {
+
+        if (!state->texture[s] && !(sampler_mask & (1 << i))) {
             view[i] = NULL;
-#ifdef DEBUG
-            if (state->ps && state->ps->sampler_mask & (1 << i))
-                WARN_ONCE("FIXME: unbound sampler should return alpha=1\n");
-#endif
             continue;
         }
-        sRGB = state->samp[s][D3DSAMP_SRGBTEXTURE] ? 1 : 0;
 
-        view[i] = NineBaseTexture9_GetSamplerView(state->texture[s], sRGB);
-        num_textures = i + 1;
+        if (state->texture[s]) {
+            sRGB = state->samp[s][D3DSAMP_SRGBTEXTURE] ? 1 : 0;
 
-        if (update_sampler_derived(state, s) || (state->changed.sampler[s] & 0x05fe)) {
-            state->changed.sampler[s] = 0;
+            view[i] = NineBaseTexture9_GetSamplerView(state->texture[s], sRGB);
+            num_textures = i + 1;
+
+            if (update_sampler_derived(state, s) || (state->changed.sampler[s] & 0x05fe)) {
+                state->changed.sampler[s] = 0;
+                commit_samplers = TRUE;
+                nine_convert_sampler_state(device->cso, s, state->samp[s]);
+            }
+        } else {
+            /* Bind dummy sampler. We do not bind dummy sampler when
+             * it is not needed because it could add overhead. The
+             * dummy sampler should have r=g=b=0 and a=1. We do not
+             * 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;
+            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);
+
+            commit_views = TRUE;
             commit_samplers = TRUE;
-            nine_convert_sampler_state(device->cso, s, state->samp[s]);
+            state->changed.sampler[s] = ~0;
         }
+
+        state->bound_samplers_mask_ps |= (1 << s);
     }
-    if (state->changed.texture & NINE_PS_SAMPLERS_MASK || state->changed.srgb)
+
+    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);
 
     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;
     for (num_textures = 0, i = 0; i < NINE_MAX_SAMPLERS_VS; ++i) {
         const unsigned s = NINE_SAMPLER_VS(i);
         int sRGB;
-        if (!state->texture[s]) {
+
+        if (!state->texture[s] && !(sampler_mask & (1 << i))) {
             view[i] = NULL;
-#ifdef DEBUG
-            if (state->vs && state->vs->sampler_mask & (1 << i))
-                WARN_ONCE("FIXME: unbound sampler should return alpha=1\n");
-#endif
             continue;
         }
-        sRGB = state->samp[s][D3DSAMP_SRGBTEXTURE] ? 1 : 0;
 
-        view[i] = NineBaseTexture9_GetSamplerView(state->texture[s], sRGB);
-        num_textures = i + 1;
+        if (state->texture[s]) {
+            sRGB = state->samp[s][D3DSAMP_SRGBTEXTURE] ? 1 : 0;
+
+            view[i] = NineBaseTexture9_GetSamplerView(state->texture[s], sRGB);
+            num_textures = i + 1;
 
-        if (update_sampler_derived(state, s) || (state->changed.sampler[s] & 0x05fe)) {
-            state->changed.sampler[s] = 0;
+            if (update_sampler_derived(state, s) || (state->changed.sampler[s] & 0x05fe)) {
+                state->changed.sampler[s] = 0;
+                commit_samplers = TRUE;
+                nine_convert_sampler_state(device->cso, s, state->samp[s]);
+            }
+        } else {
+            /* Bind dummy sampler. We do not bind dummy sampler when
+             * it is not needed because it could add overhead. The
+             * dummy sampler should have r=g=b=0 and a=1. We do not
+             * 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;
+            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);
+
+            commit_views = TRUE;
             commit_samplers = TRUE;
-            nine_convert_sampler_state(device->cso, s, state->samp[s]);
+            state->changed.sampler[s] = ~0;
         }
+
+        state->bound_samplers_mask_vs |= (1 << s);
     }
-    if (state->changed.texture & NINE_VS_SAMPLERS_MASK || state->changed.srgb)
+    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);
 
index 0cb293396d69680e0dadaf73957c6cd36a9ac30f..25ca3dba3051eb3cd1f0f4aea2ef5a532cb4ca5e 100644 (file)
@@ -175,6 +175,8 @@ struct nine_state
 
     DWORD samp[NINE_MAX_SAMPLERS][NINED3DSAMP_COUNT];
     uint32_t samplers_shadow;
+    uint8_t bound_samplers_mask_vs;
+    uint16_t bound_samplers_mask_ps;
 
     struct {
         struct {