diff options
-rw-r--r-- | src/gallium/state_trackers/nine/device9.c | 37 | ||||
-rw-r--r-- | src/gallium/state_trackers/nine/device9.h | 4 | ||||
-rw-r--r-- | src/gallium/state_trackers/nine/nine_state.c | 93 | ||||
-rw-r--r-- | src/gallium/state_trackers/nine/nine_state.h | 3 |
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; |