diff --git a/src/mesa/state_tracker/st_atom_constbuf.c b/src/mesa/state_tracker/st_atom_constbuf.c index 5612bb5f796..f67772d33c4 100644 --- a/src/mesa/state_tracker/st_atom_constbuf.c +++ b/src/mesa/state_tracker/st_atom_constbuf.c @@ -94,21 +94,8 @@ st_upload_constants(struct st_context *st, struct gl_program *prog) struct pipe_constant_buffer cb; const uint paramBytes = params->NumParameterValues * sizeof(GLfloat); - /* Update the constants which come from fixed-function state, such as - * transformation matrices, fog factors, etc. The rest of the values in - * the parameters list are explicitly set by the user with glUniform, - * glProgramParameter(), etc. - */ - if (params->StateFlags) - _mesa_load_state_parameters(st->ctx, params); - _mesa_shader_write_subroutine_indices(st->ctx, stage); - cb.buffer = NULL; - cb.user_buffer = params->ParameterValues; - cb.buffer_offset = 0; - cb.buffer_size = paramBytes; - if (ST_DEBUG & DEBUG_CONSTANTS) { debug_printf("%s(shader=%d, numParams=%d, stateFlags=0x%x)\n", __func__, shader_type, params->NumParameters, @@ -116,22 +103,86 @@ st_upload_constants(struct st_context *st, struct gl_program *prog) _mesa_print_parameter_list(params); } - cso_set_constant_buffer(st->cso_context, shader_type, 0, &cb); - pipe_resource_reference(&cb.buffer, NULL); + cb.buffer = NULL; + cb.user_buffer = NULL; + cb.buffer_offset = 0; + cb.buffer_size = paramBytes; - /* Set inlinable constants. */ - unsigned num_inlinable_uniforms = prog->info.num_inlinable_uniforms; - if (num_inlinable_uniforms) { - struct pipe_context *pipe = st->pipe; - uint32_t values[MAX_INLINABLE_UNIFORMS]; - gl_constant_value *constbuf = params->ParameterValues; + if (st->prefer_real_buffer_in_constbuf0) { + uint32_t *ptr; + /* fetch_state always stores 4 components (16 bytes) per matrix row, + * but matrix rows are sometimes allocated partially, so add 12 + * to compensate for the fetch_state defect. + */ + u_upload_alloc(st->pipe->const_uploader, 0, paramBytes + 12, 64, + &cb.buffer_offset, &cb.buffer, (void**)&ptr); - for (unsigned i = 0; i < num_inlinable_uniforms; i++) - values[i] = constbuf[prog->info.inlinable_uniform_dw_offsets[i]].u; + int uniform_bytes = params->UniformBytes; + if (uniform_bytes) + memcpy(ptr, params->ParameterValues, uniform_bytes); - pipe->set_inlinable_constants(pipe, shader_type, - prog->info.num_inlinable_uniforms, - values); + /* Upload the constants which come from fixed-function state, such as + * transformation matrices, fog factors, etc. + */ + if (params->StateFlags) + _mesa_upload_state_parameters(st->ctx, params, ptr); + + u_upload_unmap(st->pipe->const_uploader); + cso_set_constant_buffer(st->cso_context, shader_type, 0, &cb); + pipe_resource_reference(&cb.buffer, NULL); + + /* Set inlinable constants. This is more involved because state + * parameters are uploaded directly above instead of being loaded + * into gl_program_parameter_list. The easiest way to get their values + * is to load them. + */ + unsigned num_inlinable_uniforms = prog->info.num_inlinable_uniforms; + if (num_inlinable_uniforms) { + struct pipe_context *pipe = st->pipe; + uint32_t values[MAX_INLINABLE_UNIFORMS]; + gl_constant_value *constbuf = params->ParameterValues; + bool loaded_state_vars = false; + + for (unsigned i = 0; i < num_inlinable_uniforms; i++) { + unsigned dw_offset = prog->info.inlinable_uniform_dw_offsets[i]; + + if (dw_offset * 4 >= uniform_bytes && !loaded_state_vars) { + _mesa_load_state_parameters(st->ctx, params); + loaded_state_vars = true; + } + + values[i] = constbuf[prog->info.inlinable_uniform_dw_offsets[i]].u; + } + + pipe->set_inlinable_constants(pipe, shader_type, + prog->info.num_inlinable_uniforms, + values); + } + } else { + cb.user_buffer = params->ParameterValues; + + /* Update the constants which come from fixed-function state, such as + * transformation matrices, fog factors, etc. + */ + if (params->StateFlags) + _mesa_load_state_parameters(st->ctx, params); + + cso_set_constant_buffer(st->cso_context, shader_type, 0, &cb); + + /* Set inlinable constants. */ + unsigned num_inlinable_uniforms = prog->info.num_inlinable_uniforms; + if (num_inlinable_uniforms) { + struct pipe_context *pipe = st->pipe; + uint32_t values[MAX_INLINABLE_UNIFORMS]; + gl_constant_value *constbuf = params->ParameterValues; + + for (unsigned i = 0; i < num_inlinable_uniforms; i++) + values[i] = constbuf[prog->info.inlinable_uniform_dw_offsets[i]].u; + + pipe->set_inlinable_constants(pipe, shader_type, + prog->info.num_inlinable_uniforms, + values); + } } st->state.constants[shader_type].ptr = params->ParameterValues; diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c index 1605e4682e8..bd5581a19aa 100644 --- a/src/mesa/state_tracker/st_context.c +++ b/src/mesa/state_tracker/st_context.c @@ -700,6 +700,8 @@ st_create_context_priv(struct gl_context *ctx, struct pipe_context *pipe, !screen->get_param(screen, PIPE_CAP_TWO_SIDED_COLOR); st->lower_ucp = !screen->get_param(screen, PIPE_CAP_CLIP_PLANES); + st->prefer_real_buffer_in_constbuf0 = + screen->get_param(screen, PIPE_CAP_PREFER_REAL_BUFFER_IN_CONSTBUF0); st->allow_st_finalize_nir_twice = screen->finalize_nir != NULL; st->has_hw_atomics = diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h index d467dee50e8..8f2a109ab09 100644 --- a/src/mesa/state_tracker/st_context.h +++ b/src/mesa/state_tracker/st_context.h @@ -153,6 +153,7 @@ struct st_context boolean lower_point_size; boolean lower_two_sided_color; boolean lower_ucp; + boolean prefer_real_buffer_in_constbuf0; /* There are consequences for drivers wanting to call st_finalize_nir * twice, once before shader caching and once after lowering for shader diff --git a/src/mesa/state_tracker/st_draw_feedback.c b/src/mesa/state_tracker/st_draw_feedback.c index 174a0f77e98..adfdffb39bd 100644 --- a/src/mesa/state_tracker/st_draw_feedback.c +++ b/src/mesa/state_tracker/st_draw_feedback.c @@ -223,11 +223,24 @@ st_feedback_draw_vbo(struct gl_context *ctx, info.has_user_indices = false; } - /* set constant buffers */ + /* set constant buffer 0 */ + struct gl_program_parameter_list *params = st->vp->Base.Parameters; + + /* Update the constants which come from fixed-function state, such as + * transformation matrices, fog factors, etc. + * + * It must be done here if the state tracker doesn't update state vars + * in gl_program_parameter_list because allow_constbuf0_as_real_buffer + * is set. + */ + if (st->prefer_real_buffer_in_constbuf0 && params->StateFlags) + _mesa_load_state_parameters(st->ctx, params); + draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, st->state.constants[PIPE_SHADER_VERTEX].ptr, st->state.constants[PIPE_SHADER_VERTEX].size); + /* set uniform buffers */ const struct gl_program *prog = &vp->Base.Base; struct pipe_transfer *ubo_transfer[PIPE_MAX_CONSTANT_BUFFERS] = {0}; assert(prog->info.num_ubos <= ARRAY_SIZE(ubo_transfer));