summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;