From: Tiziano Bacocco Date: Fri, 30 Jan 2015 12:51:44 +0000 (+0100) Subject: st/nine: Implement dummy vbo behaviour when vs is missing inputs X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=17abefa12be1d5e7d436bfbb082c3eba19adf26c;p=mesa.git 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 Signed-off-by: Tiziano Bacocco --- 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;