summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTiziano Bacocco <[email protected]>2015-01-30 13:51:44 +0100
committerAxel Davy <[email protected]>2015-02-06 00:07:20 +0100
commit17abefa12be1d5e7d436bfbb082c3eba19adf26c (patch)
tree74543bf82c0b26cd1a1756d0da880ca14fe010cd
parent90585cbc9aef27904efc86dbfbd8743d27a6f599 (diff)
st/nine: Implement dummy vbo behaviour when vs is missing inputs
Use a dummy vertex buffer object when vs inputs have no corresponding entries in the vertex declaration. This dummy buffer will give to the shader float4(0,0,0,0). This fixes several artifacts on some games. Signed-off-by: Axel Davy <[email protected]> Signed-off-by: Tiziano Bacocco <[email protected]>
-rw-r--r--src/gallium/state_trackers/nine/device9.c37
-rw-r--r--src/gallium/state_trackers/nine/device9.h4
-rw-r--r--src/gallium/state_trackers/nine/nine_state.c93
-rw-r--r--src/gallium/state_trackers/nine/nine_state.h3
4 files changed, 119 insertions, 18 deletions
diff --git a/src/gallium/state_trackers/nine/device9.c b/src/gallium/state_trackers/nine/device9.c
index e0524644f8a..78e148bca77 100644
--- a/src/gallium/state_trackers/nine/device9.c
+++ b/src/gallium/state_trackers/nine/device9.c
@@ -221,6 +221,42 @@ NineDevice9_ctor( struct NineDevice9 *This,
NineUnknown_ConvertRefToBind(NineUnknown(This->state.rt[i]));
}
+ /* Initialize a dummy VBO to be used when a a vertex declaration does not
+ * specify all the inputs needed by vertex shader, on win default behavior
+ * is to pass 0,0,0,0 to the shader */
+ {
+ struct pipe_transfer *transfer;
+ struct pipe_resource tmpl;
+ struct pipe_box box;
+ unsigned char *data;
+
+ tmpl.target = PIPE_BUFFER;
+ tmpl.format = PIPE_FORMAT_R8_UNORM;
+ tmpl.width0 = 16; /* 4 floats */
+ tmpl.height0 = 1;
+ tmpl.depth0 = 1;
+ tmpl.array_size = 1;
+ tmpl.last_level = 0;
+ tmpl.nr_samples = 0;
+ tmpl.usage = PIPE_USAGE_DEFAULT;
+ tmpl.bind = PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_TRANSFER_WRITE;
+ tmpl.flags = 0;
+ This->dummy_vbo = pScreen->resource_create(pScreen, &tmpl);
+
+ if (!This->dummy_vbo)
+ return D3DERR_OUTOFVIDEOMEMORY;
+
+ u_box_1d(0, 16, &box);
+ data = This->pipe->transfer_map(This->pipe, This->dummy_vbo, 0,
+ PIPE_TRANSFER_WRITE |
+ PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE,
+ &box, &transfer);
+ assert(data);
+ assert(transfer);
+ memset(data, 0, 16);
+ This->pipe->transfer_unmap(This->pipe, transfer);
+ }
+
This->cursor.software = FALSE;
This->cursor.hotspot.x = -1;
This->cursor.hotspot.y = -1;
@@ -387,6 +423,7 @@ NineDevice9_dtor( struct NineDevice9 *This )
pipe_resource_reference(&This->dummy_texture, NULL);
pipe_resource_reference(&This->constbuf_vs, NULL);
pipe_resource_reference(&This->constbuf_ps, NULL);
+ pipe_resource_reference(&This->dummy_vbo, NULL);
FREE(This->state.vs_const_f);
FREE(This->state.ps_const_f);
FREE(This->state.vs_lconstf_temp);
diff --git a/src/gallium/state_trackers/nine/device9.h b/src/gallium/state_trackers/nine/device9.h
index 54da9e3a624..f412088ca08 100644
--- a/src/gallium/state_trackers/nine/device9.h
+++ b/src/gallium/state_trackers/nine/device9.h
@@ -123,6 +123,10 @@ struct NineDevice9
struct nine_range_pool range_pool;
struct hud_context *hud; /* NULL if hud is disabled */
+
+ /* dummy vbo (containing 0 0 0 0) to bind if vertex shader input
+ * is not bound to anything by the vertex declaration */
+ struct pipe_resource *dummy_vbo;
};
static INLINE struct NineDevice9 *
NineDevice9( void *data )
diff --git a/src/gallium/state_trackers/nine/nine_state.c b/src/gallium/state_trackers/nine/nine_state.c
index ba758176f49..495cc862b2a 100644
--- a/src/gallium/state_trackers/nine/nine_state.c
+++ b/src/gallium/state_trackers/nine/nine_state.c
@@ -191,26 +191,55 @@ update_vertex_elements(struct NineDevice9 *device)
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) /* no inputs */
return;
- 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);
- index = -1;
- for (i = 0; i < vdecl->nelems; i++) {
- if (vdecl->usage_map[i] == vs->input_map[n].ndecl) {
- index = i;
+ 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;
@@ -219,18 +248,27 @@ update_vertex_elements(struct NineDevice9 *device)
if (state->stream_freq[b] & D3DSTREAMSOURCE_INSTANCEDATA)
ve[n].instance_divisor = state->stream_freq[b] & 0x7FFFFF;
} else {
- /* TODO: msdn doesn't specify what should happen when the vertex
- * declaration doesn't match the vertex shader inputs.
- * Some websites say the code will pass but nothing will get rendered.
- * We should check and implement the correct behaviour. */
- /* Put PIPE_FORMAT_NONE.
- * Some drivers (r300) are very unhappy with that */
- ve[n].src_format = PIPE_FORMAT_NONE;
+ /* 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;
- ve[n].vertex_buffer_index = 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;
@@ -566,6 +604,7 @@ update_vertex_buffers(struct NineDevice9 *device)
{
struct pipe_context *pipe = device->pipe;
struct nine_state *state = &device->state;
+ struct pipe_vertex_buffer dummy_vtxbuf;
uint32_t mask = state->changed.vtxbuf;
unsigned i;
unsigned start;
@@ -573,6 +612,19 @@ update_vertex_buffers(struct NineDevice9 *device)
DBG("mask=%x\n", mask);
+ if (state->dummy_vbo_bound_at >= 0) {
+ if (!state->vbo_bound_done) {
+ dummy_vtxbuf.buffer = device->dummy_vbo;
+ dummy_vtxbuf.stride = 0;
+ dummy_vtxbuf.user_buffer = NULL;
+ dummy_vtxbuf.buffer_offset = 0;
+ pipe->set_vertex_buffers(pipe, state->dummy_vbo_bound_at,
+ 1, &dummy_vtxbuf);
+ state->vbo_bound_done = TRUE;
+ }
+ mask &= ~(1 << state->dummy_vbo_bound_at);
+ }
+
for (i = 0; mask; mask >>= 1, ++i) {
if (mask & 1) {
if (!count)
@@ -580,8 +632,8 @@ update_vertex_buffers(struct NineDevice9 *device)
++count;
} else {
if (count)
- pipe->set_vertex_buffers(pipe,
- start, count, &state->vtxbuf[start]);
+ pipe->set_vertex_buffers(pipe, start, count,
+ &state->vtxbuf[start]);
count = 0;
}
}
@@ -1116,6 +1168,11 @@ nine_state_set_defaults(struct NineDevice9 *device, const D3DCAPS9 *caps,
for (s = 0; s < Elements(state->changed.sampler); ++s)
state->changed.sampler[s] = ~0;
+
+ if (!is_reset) {
+ state->dummy_vbo_bound_at = -1;
+ state->vbo_bound_done = FALSE;
+ }
}
void
diff --git a/src/gallium/state_trackers/nine/nine_state.h b/src/gallium/state_trackers/nine/nine_state.h
index 25ca3dba305..19169595338 100644
--- a/src/gallium/state_trackers/nine/nine_state.h
+++ b/src/gallium/state_trackers/nine/nine_state.h
@@ -178,6 +178,9 @@ struct nine_state
uint8_t bound_samplers_mask_vs;
uint16_t bound_samplers_mask_ps;
+ int dummy_vbo_bound_at; /* -1 = not bound , >= 0 = bound index */
+ boolean vbo_bound_done;
+
struct {
struct {
uint32_t group;