mirror of https://github.com/xemu-project/xemu.git
nv2a: Simplify shader uniform declaration and update
This patch moves uniform declaration into {vsh, psh}.h headers, using macros to generate accessory definitions. Mapping of PGRAPH state to uniform values is factored out of parallel paths in GL/Vk renderers into common renderer-agnostic helper functions, with renderer-specific uniform value update paths being automated.
This commit is contained in:
parent
18872f2eb9
commit
c88bac1706
|
@ -34,6 +34,8 @@
|
|||
#include "hw/xbox/nv2a/pgraph/surface.h"
|
||||
#include "hw/xbox/nv2a/pgraph/texture.h"
|
||||
#include "hw/xbox/nv2a/pgraph/shaders.h"
|
||||
#include "hw/xbox/nv2a/pgraph/glsl/vsh.h"
|
||||
#include "hw/xbox/nv2a/pgraph/glsl/psh.h"
|
||||
|
||||
#include "gloffscreen.h"
|
||||
#include "constants.h"
|
||||
|
@ -96,39 +98,9 @@ typedef struct ShaderBinding {
|
|||
GLuint gl_program;
|
||||
GLenum gl_primitive_mode;
|
||||
|
||||
uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4];
|
||||
|
||||
struct {
|
||||
struct {
|
||||
GLint alpha_ref;
|
||||
GLint bump_mat[NV2A_MAX_TEXTURES];
|
||||
GLint bump_offset[NV2A_MAX_TEXTURES];
|
||||
GLint bump_scale[NV2A_MAX_TEXTURES];
|
||||
GLint clip_range;
|
||||
GLint clip_region[8];
|
||||
GLint color_key[4];
|
||||
GLint color_key_mask[4];
|
||||
GLint depth_offset;
|
||||
GLint fog_color;
|
||||
GLint psh_constant[9][2];
|
||||
GLint surface_size;
|
||||
GLint tex_scale[NV2A_MAX_TEXTURES];
|
||||
} psh;
|
||||
|
||||
struct {
|
||||
GLint fog_param;
|
||||
GLint light_infinite_direction[NV2A_MAX_LIGHTS];
|
||||
GLint light_infinite_half_vector[NV2A_MAX_LIGHTS];
|
||||
GLint light_local_attenuation[NV2A_MAX_LIGHTS];
|
||||
GLint light_local_position[NV2A_MAX_LIGHTS];
|
||||
GLint ltc1[NV2A_LTC1_COUNT];
|
||||
GLint ltctxa[NV2A_LTCTXA_COUNT];
|
||||
GLint ltctxb[NV2A_LTCTXB_COUNT];
|
||||
GLint material_alpha;
|
||||
GLint point_params[8];
|
||||
GLint vsh_constant[NV2A_VERTEXSHADER_CONSTANTS];
|
||||
int specular_power;
|
||||
} vsh;
|
||||
PshUniformLocs psh;
|
||||
VshUniformLocs vsh;
|
||||
} uniform_locs;
|
||||
} ShaderBinding;
|
||||
|
||||
|
|
|
@ -115,112 +115,22 @@ static void update_shader_constant_locations(ShaderBinding *binding)
|
|||
}
|
||||
}
|
||||
|
||||
/* lookup fragment shader uniforms */
|
||||
for (int i = 0; i < 9; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
snprintf(tmp, sizeof(tmp), "c%d_%d", j, i);
|
||||
binding->uniform_locs.psh.psh_constant[i][j] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
for (int i = 0; i < ARRAY_SIZE(binding->uniform_locs.vsh); i++) {
|
||||
const char *name = VshUniformInfo[i].name;
|
||||
if (VshUniformInfo[i].count > 1) {
|
||||
snprintf(tmp, sizeof(tmp), "%s[0]", name);
|
||||
name = tmp;
|
||||
}
|
||||
}
|
||||
binding->uniform_locs.psh.alpha_ref =
|
||||
glGetUniformLocation(binding->gl_program, "alphaRef");
|
||||
|
||||
for (int i = 1; i < NV2A_MAX_TEXTURES; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "bumpMat%d", i);
|
||||
binding->uniform_locs.psh.bump_mat[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "bumpScale%d", i);
|
||||
binding->uniform_locs.psh.bump_scale[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "bumpOffset%d", i);
|
||||
binding->uniform_locs.psh.bump_offset[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
binding->uniform_locs.vsh[i] = glGetUniformLocation(binding->gl_program, name);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NV2A_MAX_TEXTURES; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "texScale%d", i);
|
||||
binding->uniform_locs.psh.tex_scale[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
}
|
||||
|
||||
/* lookup vertex shader uniforms */
|
||||
for (int i = 0; i < NV2A_VERTEXSHADER_CONSTANTS; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "c[%d]", i);
|
||||
binding->uniform_locs.vsh.vsh_constant[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
}
|
||||
binding->uniform_locs.psh.surface_size =
|
||||
glGetUniformLocation(binding->gl_program, "surfaceSize");
|
||||
binding->uniform_locs.psh.clip_range =
|
||||
glGetUniformLocation(binding->gl_program, "clipRange");
|
||||
binding->uniform_locs.psh.depth_offset =
|
||||
glGetUniformLocation(binding->gl_program, "depthOffset");
|
||||
binding->uniform_locs.psh.fog_color =
|
||||
glGetUniformLocation(binding->gl_program, "fogColor");
|
||||
binding->uniform_locs.vsh.fog_param =
|
||||
glGetUniformLocation(binding->gl_program, "fogParam");
|
||||
|
||||
for (int i = 0; i < NV2A_LTCTXA_COUNT; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "ltctxa[%d]", i);
|
||||
binding->uniform_locs.vsh.ltctxa[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
}
|
||||
for (int i = 0; i < NV2A_LTCTXB_COUNT; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "ltctxb[%d]", i);
|
||||
binding->uniform_locs.vsh.ltctxb[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
}
|
||||
for (int i = 0; i < NV2A_LTC1_COUNT; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "ltc1[%d]", i);
|
||||
binding->uniform_locs.vsh.ltc1[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
}
|
||||
for (int i = 0; i < NV2A_MAX_LIGHTS; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "lightInfiniteHalfVector%d", i);
|
||||
binding->uniform_locs.vsh.light_infinite_half_vector[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "lightInfiniteDirection%d", i);
|
||||
binding->uniform_locs.vsh.light_infinite_direction[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "lightLocalPosition%d", i);
|
||||
binding->uniform_locs.vsh.light_local_position[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "lightLocalAttenuation%d", i);
|
||||
binding->uniform_locs.vsh.light_local_attenuation[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "clipRegion[%d]", i);
|
||||
binding->uniform_locs.psh.clip_region[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
snprintf(tmp, sizeof(tmp), "pointParams[%d]", i);
|
||||
binding->uniform_locs.vsh.point_params[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
}
|
||||
|
||||
if (binding->state.vsh.is_fixed_function) {
|
||||
binding->uniform_locs.vsh.material_alpha =
|
||||
glGetUniformLocation(binding->gl_program, "material_alpha");
|
||||
binding->uniform_locs.vsh.specular_power =
|
||||
glGetUniformLocation(binding->gl_program, "specularPower");
|
||||
} else {
|
||||
binding->uniform_locs.vsh.material_alpha = -1;
|
||||
binding->uniform_locs.vsh.specular_power = -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
snprintf(tmp, sizeof(tmp), "colorKey[%d]", i);
|
||||
binding->uniform_locs.psh.color_key[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "colorKeyMask[%d]", i);
|
||||
binding->uniform_locs.psh.color_key_mask[i] =
|
||||
glGetUniformLocation(binding->gl_program, tmp);
|
||||
for (int i = 0; i < ARRAY_SIZE(binding->uniform_locs.psh); i++) {
|
||||
const char *name = PshUniformInfo[i].name;
|
||||
if (PshUniformInfo[i].count > 1) {
|
||||
snprintf(tmp, sizeof(tmp), "%s[0]", name);
|
||||
name = tmp;
|
||||
}
|
||||
binding->uniform_locs.psh[i] = glGetUniformLocation(binding->gl_program, name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -723,270 +633,72 @@ void pgraph_gl_shader_cache_to_disk(ShaderBinding *binding)
|
|||
qemu_thread_create(binding->save_thread, name, shader_write_to_disk, binding, QEMU_THREAD_JOINABLE);
|
||||
}
|
||||
|
||||
static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
|
||||
bool binding_changed)
|
||||
static void apply_uniform_updates(const UniformInfo *info, int *locs,
|
||||
void *values, size_t count)
|
||||
{
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (locs[i] == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
void *value = (char*)values + info[i].val_offs;
|
||||
|
||||
switch (info[i].type) {
|
||||
case UniformElementType_uint:
|
||||
glUniform1uiv(locs[i], info[i].count, value);
|
||||
break;
|
||||
case UniformElementType_int:
|
||||
glUniform1iv(locs[i], info[i].count, value);
|
||||
break;
|
||||
case UniformElementType_ivec4:
|
||||
glUniform4iv(locs[i], info[i].count, value);
|
||||
break;
|
||||
case UniformElementType_float:
|
||||
glUniform1fv(locs[i], info[i].count, value);
|
||||
break;
|
||||
case UniformElementType_vec2:
|
||||
glUniform2fv(locs[i], info[i].count, value);
|
||||
break;
|
||||
case UniformElementType_vec3:
|
||||
glUniform3fv(locs[i], info[i].count, value);
|
||||
break;
|
||||
case UniformElementType_vec4:
|
||||
glUniform4fv(locs[i], info[i].count, value);
|
||||
break;
|
||||
case UniformElementType_mat2:
|
||||
glUniformMatrix2fv(locs[i], info[i].count, GL_FALSE, value);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
assert(glGetError() == GL_NO_ERROR);
|
||||
}
|
||||
|
||||
// FIXME: Dirty tracking
|
||||
// FIXME: Consider UBO to align with VK renderer
|
||||
static void update_shader_uniforms(PGRAPHState *pg, ShaderBinding *binding)
|
||||
{
|
||||
PGRAPHGLState *r = pg->gl_renderer_state;
|
||||
ShaderState *state = &binding->state;
|
||||
int i, j;
|
||||
|
||||
/* update combiner constants */
|
||||
for (i = 0; i < 9; i++) {
|
||||
uint32_t constant[2];
|
||||
if (i == 8) {
|
||||
/* final combiner */
|
||||
constant[0] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR0);
|
||||
constant[1] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR1);
|
||||
} else {
|
||||
constant[0] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR0 + i * 4);
|
||||
constant[1] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR1 + i * 4);
|
||||
}
|
||||
VshUniformValues vsh_values;
|
||||
pgraph_set_vsh_uniform_values(pg, &binding->state.vsh,
|
||||
binding->uniform_locs.vsh, &vsh_values);
|
||||
apply_uniform_updates(VshUniformInfo, binding->uniform_locs.vsh,
|
||||
&vsh_values, VshUniform__COUNT);
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
GLint loc = binding->uniform_locs.psh.psh_constant[i][j];
|
||||
if (loc != -1) {
|
||||
float value[4];
|
||||
pgraph_argb_pack32_to_rgba_float(constant[j], value);
|
||||
glUniform4fv(loc, 1, value);
|
||||
}
|
||||
PshUniformValues psh_values;
|
||||
pgraph_set_psh_uniform_values(pg, binding->uniform_locs.psh, &psh_values);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (r->texture_binding[i] != NULL) {
|
||||
float scale = r->texture_binding[i]->scale;
|
||||
psh_values.texScale[i] = scale;
|
||||
}
|
||||
}
|
||||
if (binding->uniform_locs.psh.alpha_ref != -1) {
|
||||
int alpha_ref = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0),
|
||||
NV_PGRAPH_CONTROL_0_ALPHAREF);
|
||||
glUniform1i(binding->uniform_locs.psh.alpha_ref, alpha_ref);
|
||||
}
|
||||
|
||||
/* For each texture stage */
|
||||
for (i = 0; i < NV2A_MAX_TEXTURES; i++) {
|
||||
GLint loc;
|
||||
|
||||
/* Bump luminance only during stages 1 - 3 */
|
||||
if (i > 0) {
|
||||
loc = binding->uniform_locs.psh.bump_mat[i];
|
||||
if (loc != -1) {
|
||||
uint32_t m_u32[4];
|
||||
m_u32[0] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT00 + 4 * (i - 1));
|
||||
m_u32[1] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT01 + 4 * (i - 1));
|
||||
m_u32[2] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT10 + 4 * (i - 1));
|
||||
m_u32[3] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT11 + 4 * (i - 1));
|
||||
float m[4];
|
||||
m[0] = *(float *)&m_u32[0];
|
||||
m[1] = *(float *)&m_u32[1];
|
||||
m[2] = *(float *)&m_u32[2];
|
||||
m[3] = *(float *)&m_u32[3];
|
||||
glUniformMatrix2fv(loc, 1, GL_FALSE, m);
|
||||
}
|
||||
loc = binding->uniform_locs.psh.bump_scale[i];
|
||||
if (loc != -1) {
|
||||
uint32_t v =
|
||||
pgraph_reg_r(pg, NV_PGRAPH_BUMPSCALE1 + (i - 1) * 4);
|
||||
glUniform1f(loc, *(float *)&v);
|
||||
}
|
||||
loc = binding->uniform_locs.psh.bump_offset[i];
|
||||
if (loc != -1) {
|
||||
uint32_t v =
|
||||
pgraph_reg_r(pg, NV_PGRAPH_BUMPOFFSET1 + (i - 1) * 4);
|
||||
glUniform1f(loc, *(float *)&v);
|
||||
}
|
||||
}
|
||||
|
||||
loc = r->shader_binding->uniform_locs.psh.tex_scale[i];
|
||||
if (loc != -1) {
|
||||
assert(r->texture_binding[i] != NULL);
|
||||
glUniform1f(loc, (float)r->texture_binding[i]->scale);
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.psh.color_key[i] != -1) {
|
||||
glUniform1ui(binding->uniform_locs.psh.color_key[i],
|
||||
pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR0 + i * 4));
|
||||
}
|
||||
if (binding->uniform_locs.psh.color_key_mask[i] != -1) {
|
||||
glUniform1ui(binding->uniform_locs.psh.color_key_mask[i],
|
||||
pgraph_get_color_key_mask_for_texture(pg, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.psh.fog_color != -1) {
|
||||
uint32_t fog_color = pgraph_reg_r(pg, NV_PGRAPH_FOGCOLOR);
|
||||
glUniform4f(binding->uniform_locs.psh.fog_color,
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_RED) / 255.0,
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_GREEN) / 255.0,
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_BLUE) / 255.0,
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_ALPHA) / 255.0);
|
||||
}
|
||||
if (binding->uniform_locs.vsh.fog_param != -1) {
|
||||
uint32_t v[2];
|
||||
v[0] = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM0);
|
||||
v[1] = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM1);
|
||||
glUniform2f(binding->uniform_locs.vsh.fog_param, *(float *)&v[0],
|
||||
*(float *)&v[1]);
|
||||
}
|
||||
|
||||
float zmax;
|
||||
switch (pg->surface_shape.zeta_format) {
|
||||
case NV097_SET_SURFACE_FORMAT_ZETA_Z16:
|
||||
zmax = pg->surface_shape.z_format ? f16_max : (float)0xFFFF;
|
||||
break;
|
||||
case NV097_SET_SURFACE_FORMAT_ZETA_Z24S8:
|
||||
zmax = pg->surface_shape.z_format ? f24_max : (float)0xFFFFFF;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (state->vsh.is_fixed_function) {
|
||||
/* update lighting constants */
|
||||
struct {
|
||||
uint32_t *v;
|
||||
bool *dirty;
|
||||
GLint *locs;
|
||||
size_t len;
|
||||
} lighting_arrays[] = {
|
||||
{ &pg->ltctxa[0][0], &pg->ltctxa_dirty[0],
|
||||
binding->uniform_locs.vsh.ltctxa, NV2A_LTCTXA_COUNT },
|
||||
{ &pg->ltctxb[0][0], &pg->ltctxb_dirty[0],
|
||||
binding->uniform_locs.vsh.ltctxb, NV2A_LTCTXB_COUNT },
|
||||
{ &pg->ltc1[0][0], &pg->ltc1_dirty[0],
|
||||
binding->uniform_locs.vsh.ltc1, NV2A_LTC1_COUNT },
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lighting_arrays); i++) {
|
||||
uint32_t *lighting_v = lighting_arrays[i].v;
|
||||
bool *lighting_dirty = lighting_arrays[i].dirty;
|
||||
GLint *lighting_locs = lighting_arrays[i].locs;
|
||||
size_t lighting_len = lighting_arrays[i].len;
|
||||
for (j = 0; j < lighting_len; j++) {
|
||||
if (!lighting_dirty[j] && !binding_changed)
|
||||
continue;
|
||||
GLint loc = lighting_locs[j];
|
||||
if (loc != -1) {
|
||||
glUniform4fv(loc, 1, (const GLfloat *)&lighting_v[j * 4]);
|
||||
}
|
||||
lighting_dirty[j] = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < NV2A_MAX_LIGHTS; i++) {
|
||||
GLint loc;
|
||||
loc = binding->uniform_locs.vsh.light_infinite_half_vector[i];
|
||||
if (loc != -1) {
|
||||
glUniform3fv(loc, 1, pg->light_infinite_half_vector[i]);
|
||||
}
|
||||
loc = binding->uniform_locs.vsh.light_infinite_direction[i];
|
||||
if (loc != -1) {
|
||||
glUniform3fv(loc, 1, pg->light_infinite_direction[i]);
|
||||
}
|
||||
|
||||
loc = binding->uniform_locs.vsh.light_local_position[i];
|
||||
if (loc != -1) {
|
||||
glUniform3fv(loc, 1, pg->light_local_position[i]);
|
||||
}
|
||||
loc = binding->uniform_locs.vsh.light_local_attenuation[i];
|
||||
if (loc != -1) {
|
||||
glUniform3fv(loc, 1, pg->light_local_attenuation[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.vsh.specular_power != -1) {
|
||||
glUniform1f(binding->uniform_locs.vsh.specular_power,
|
||||
pg->specular_power);
|
||||
}
|
||||
}
|
||||
|
||||
/* update vertex program constants */
|
||||
for (i = 0; i < NV2A_VERTEXSHADER_CONSTANTS; i++) {
|
||||
if (!pg->vsh_constants_dirty[i] && !binding_changed)
|
||||
continue;
|
||||
|
||||
GLint loc = binding->uniform_locs.vsh.vsh_constant[i];
|
||||
if ((loc != -1) &&
|
||||
memcmp(binding->vsh_constants[i], pg->vsh_constants[i],
|
||||
sizeof(pg->vsh_constants[1]))) {
|
||||
glUniform4fv(loc, 1, (const GLfloat *)pg->vsh_constants[i]);
|
||||
memcpy(binding->vsh_constants[i], pg->vsh_constants[i],
|
||||
sizeof(pg->vsh_constants[i]));
|
||||
}
|
||||
|
||||
pg->vsh_constants_dirty[i] = false;
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.psh.surface_size != -1) {
|
||||
unsigned int aa_width = 1, aa_height = 1;
|
||||
pgraph_apply_anti_aliasing_factor(pg, &aa_width, &aa_height);
|
||||
glUniform2f(binding->uniform_locs.psh.surface_size,
|
||||
pg->surface_binding_dim.width / aa_width,
|
||||
pg->surface_binding_dim.height / aa_height);
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.psh.clip_range != -1) {
|
||||
uint32_t v[2];
|
||||
v[0] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMIN);
|
||||
v[1] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMAX);
|
||||
float zclip_min = *(float *)&v[0];
|
||||
float zclip_max = *(float *)&v[1];
|
||||
glUniform4f(binding->uniform_locs.psh.clip_range, 0, zmax, zclip_min,
|
||||
zclip_max);
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.psh.depth_offset != -1) {
|
||||
float zbias = 0.0f;
|
||||
|
||||
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
|
||||
(NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) {
|
||||
uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS);
|
||||
zbias = *(float *)&zbias_u32;
|
||||
|
||||
if (pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR) != 0 &&
|
||||
(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
|
||||
NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE)) {
|
||||
/* TODO: emulate zfactor when z_perspective true, i.e.
|
||||
* w-buffering. Perhaps calculate an additional offset based on
|
||||
* triangle orientation in geometry shader and pass the result
|
||||
* to fragment shader and add it to gl_FragDepth as well.
|
||||
*/
|
||||
NV2A_UNIMPLEMENTED("NV_PGRAPH_ZOFFSETFACTOR for w-buffering");
|
||||
}
|
||||
}
|
||||
|
||||
glUniform1f(binding->uniform_locs.psh.depth_offset, zbias);
|
||||
}
|
||||
|
||||
/* Clipping regions */
|
||||
unsigned int max_gl_width = pg->surface_binding_dim.width;
|
||||
unsigned int max_gl_height = pg->surface_binding_dim.height;
|
||||
pgraph_apply_scaling_factor(pg, &max_gl_width, &max_gl_height);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
uint32_t x = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPX0 + i * 4);
|
||||
unsigned int x_min = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMIN);
|
||||
unsigned int x_max = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMAX) + 1;
|
||||
uint32_t y = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPY0 + i * 4);
|
||||
unsigned int y_min = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMIN);
|
||||
unsigned int y_max = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMAX) + 1;
|
||||
pgraph_apply_anti_aliasing_factor(pg, &x_min, &y_min);
|
||||
pgraph_apply_anti_aliasing_factor(pg, &x_max, &y_max);
|
||||
|
||||
pgraph_apply_scaling_factor(pg, &x_min, &y_min);
|
||||
pgraph_apply_scaling_factor(pg, &x_max, &y_max);
|
||||
|
||||
glUniform4i(r->shader_binding->uniform_locs.psh.clip_region[i], x_min,
|
||||
y_min, x_max, y_max);
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
GLint loc = binding->uniform_locs.vsh.point_params[i];
|
||||
if (loc != -1) {
|
||||
glUniform1f(loc, pg->point_params[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.vsh.material_alpha != -1) {
|
||||
glUniform1f(binding->uniform_locs.vsh.material_alpha,
|
||||
pg->material_alpha);
|
||||
}
|
||||
apply_uniform_updates(PshUniformInfo, binding->uniform_locs.psh,
|
||||
&psh_values, PshUniform__COUNT);
|
||||
}
|
||||
|
||||
static bool test_shaders_dirty(PGRAPHState *pg)
|
||||
|
@ -1071,7 +783,7 @@ void pgraph_gl_bind_shaders(PGRAPHState *pg)
|
|||
bool binding_changed = false;
|
||||
if (r->shader_binding && !test_shaders_dirty(pg) && !pg->program_data_dirty) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_SHADER_BIND_NOTDIRTY);
|
||||
goto update_constants;
|
||||
goto update_uniforms;
|
||||
}
|
||||
|
||||
ShaderBinding *old_binding = r->shader_binding;
|
||||
|
@ -1110,10 +822,10 @@ void pgraph_gl_bind_shaders(PGRAPHState *pg)
|
|||
|
||||
NV2A_GL_DGROUP_END();
|
||||
|
||||
update_constants:
|
||||
update_uniforms:
|
||||
assert(r->shader_binding);
|
||||
assert(r->shader_binding->initialized);
|
||||
shader_update_constants(pg, r->shader_binding, binding_changed);
|
||||
update_shader_uniforms(pg, r->shader_binding);
|
||||
}
|
||||
|
||||
GLuint pgraph_gl_compile_shader(const char *vs_src, const char *fs_src)
|
||||
|
|
|
@ -19,6 +19,11 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
#define DECL_UNIFORM_ELEMENT_NAME(type) #type,
|
||||
const char *uniform_element_type_to_str[] = {
|
||||
UNIFORM_ELEMENT_TYPE_X(DECL_UNIFORM_ELEMENT_NAME)
|
||||
};
|
||||
|
||||
MString *pgraph_get_glsl_vtx_header(MString *out, bool location, bool smooth, bool in, bool prefix, bool array)
|
||||
{
|
||||
const char *smooth_s = "";
|
||||
|
|
|
@ -22,8 +22,69 @@
|
|||
#ifndef HW_NV2A_SHADERS_COMMON_H
|
||||
#define HW_NV2A_SHADERS_COMMON_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/mstring.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef int ivec4[4];
|
||||
typedef float mat2[2 * 2];
|
||||
typedef unsigned int uint;
|
||||
typedef float vec2[2];
|
||||
typedef float vec3[3];
|
||||
typedef float vec4[4];
|
||||
|
||||
#define UNIFORM_ELEMENT_TYPE_X(DECL) \
|
||||
DECL(float) \
|
||||
DECL(int) \
|
||||
DECL(ivec4) \
|
||||
DECL(mat2) \
|
||||
DECL(uint) \
|
||||
DECL(vec2) \
|
||||
DECL(vec3) \
|
||||
DECL(vec4)
|
||||
|
||||
enum UniformElementType {
|
||||
#define DECL_UNIFORM_ELEMENT_TYPE(type) UniformElementType_##type,
|
||||
UNIFORM_ELEMENT_TYPE_X(DECL_UNIFORM_ELEMENT_TYPE)
|
||||
};
|
||||
|
||||
extern const char *uniform_element_type_to_str[];
|
||||
|
||||
#define DECL_UNIFORM_ENUM_VALUE(s, name, type, count) s##_##name,
|
||||
#define DECL_UNIFORM_ENUM_TYPE(name, decls) \
|
||||
enum name##Indices{ \
|
||||
decls(name, DECL_UNIFORM_ENUM_VALUE) name##__COUNT, \
|
||||
};
|
||||
|
||||
#define DECL_UNIFORM_LOC_STRUCT_TYPE(name, decls) \
|
||||
typedef int name##Locs[name##__COUNT];
|
||||
|
||||
#define DECL_UNIFORM_VAL_STRUCT_FIELD(s, name, type, count) type name[count];
|
||||
#define DECL_UNIFORM_VAL_STRUCT_TYPE(name, decls) \
|
||||
typedef struct name##Values { \
|
||||
decls(name, DECL_UNIFORM_VAL_STRUCT_FIELD) \
|
||||
} name##Values;
|
||||
|
||||
typedef struct UniformInfo {
|
||||
const char *name;
|
||||
enum UniformElementType type;
|
||||
size_t size;
|
||||
size_t count;
|
||||
size_t val_offs;
|
||||
} UniformInfo;
|
||||
|
||||
#define DECL_UNIFORM_INFO_ITEM(s, name, type, count) \
|
||||
{ #name, UniformElementType_##type, sizeof(type), count, \
|
||||
offsetof(s##Values, name) },
|
||||
#define DECL_UNIFORM_INFO_ARR(name, decls) \
|
||||
extern const UniformInfo name##Info[];
|
||||
#define DEF_UNIFORM_INFO_ARR(name, decls) \
|
||||
const UniformInfo name##Info[] = { decls(name, DECL_UNIFORM_INFO_ITEM) };
|
||||
|
||||
#define DECL_UNIFORM_TYPES(name, decls) \
|
||||
DECL_UNIFORM_ENUM_TYPE(name, decls) \
|
||||
DECL_UNIFORM_LOC_STRUCT_TYPE(name, decls) \
|
||||
DECL_UNIFORM_VAL_STRUCT_TYPE(name, decls) \
|
||||
DECL_UNIFORM_INFO_ARR(name, decls)
|
||||
|
||||
#define GLSL_C(idx) "c[" stringify(idx) "]"
|
||||
#define GLSL_LTCTXA(idx) "ltctxa[" stringify(idx) "]"
|
||||
|
|
|
@ -34,11 +34,12 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "hw/xbox/nv2a/debug.h"
|
||||
#include "hw/xbox/nv2a/pgraph/psh.h"
|
||||
#include "hw/xbox/nv2a/pgraph/pgraph.h"
|
||||
#include "psh.h"
|
||||
|
||||
DEF_UNIFORM_INFO_ARR(PshUniform, PSH_UNIFORM_DECL_X)
|
||||
|
||||
/*
|
||||
* This implements translation of register combiners into glsl
|
||||
* fragment shaders, but all terminology is in terms of Xbox DirectX
|
||||
|
@ -755,8 +756,6 @@ static void define_colorkey_comparator(MString *preflight)
|
|||
|
||||
static MString* psh_convert(struct PixelShader *ps)
|
||||
{
|
||||
const char *u = ps->opts.vulkan ? "" : "uniform "; // FIXME: Remove
|
||||
|
||||
MString *preflight = mstring_new();
|
||||
pgraph_get_glsl_vtx_header(preflight, ps->opts.vulkan,
|
||||
ps->state.smooth_shading, true, false, false);
|
||||
|
@ -772,25 +771,22 @@ static MString* psh_convert(struct PixelShader *ps)
|
|||
"layout(location = 0) out vec4 fragColor;\n");
|
||||
}
|
||||
|
||||
mstring_append_fmt(preflight,
|
||||
"%sint alphaRef;\n"
|
||||
"%svec4 fogColor;\n"
|
||||
"%sivec4 clipRegion[8];\n"
|
||||
"%svec4 clipRange;\n"
|
||||
"%sfloat depthOffset;\n"
|
||||
"%suint colorKey[4];\n"
|
||||
"%suint colorKeyMask[4];\n",
|
||||
u, u, u, u, u, u, u);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mstring_append_fmt(preflight, "%smat2 bumpMat%d;\n"
|
||||
"%sfloat bumpScale%d;\n"
|
||||
"%sfloat bumpOffset%d;\n"
|
||||
"%sfloat texScale%d;\n",
|
||||
u, i, u, i, u, i, u, i);
|
||||
const char *u = ps->opts.vulkan ? "" : "uniform ";
|
||||
for (int i = 0; i < ARRAY_SIZE(PshUniformInfo); i++) {
|
||||
const UniformInfo *info = &PshUniformInfo[i];
|
||||
const char *type_str = uniform_element_type_to_str[info->type];
|
||||
if (info->count == 1) {
|
||||
mstring_append_fmt(preflight, "%s%s %s;\n", u, type_str,
|
||||
info->name);
|
||||
} else {
|
||||
mstring_append_fmt(preflight, "%s%s %s[%zd];\n", u, type_str,
|
||||
info->name, info->count);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
mstring_append_fmt(preflight, "%svec4 c%d_%d;\n", u, j, i);
|
||||
mstring_append_fmt(preflight, "#define c%d_%d consts[%d]\n", j, i, i*2+j);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1044,7 +1040,7 @@ static MString* psh_convert(struct PixelShader *ps)
|
|||
i, ps->input_tex[i], ps->input_tex[i]);
|
||||
}
|
||||
|
||||
mstring_append_fmt(vars, "dsdt%d = bumpMat%d * dsdt%d;\n", i, i, i);
|
||||
mstring_append_fmt(vars, "dsdt%d = bumpMat[%d] * dsdt%d;\n", i, i, i);
|
||||
|
||||
if (ps->state.dim_tex[i] == 2) {
|
||||
mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, %s(pT%d.xy + dsdt%d));\n",
|
||||
|
@ -1070,7 +1066,7 @@ static MString* psh_convert(struct PixelShader *ps)
|
|||
i, ps->input_tex[i], ps->input_tex[i], ps->input_tex[i]);
|
||||
}
|
||||
|
||||
mstring_append_fmt(vars, "dsdtl%d.st = bumpMat%d * dsdtl%d.st;\n",
|
||||
mstring_append_fmt(vars, "dsdtl%d.st = bumpMat[%d] * dsdtl%d.st;\n",
|
||||
i, i, i);
|
||||
|
||||
if (ps->state.dim_tex[i] == 2) {
|
||||
|
@ -1084,7 +1080,7 @@ static MString* psh_convert(struct PixelShader *ps)
|
|||
assert(!"Unhandled texture dimensions");
|
||||
}
|
||||
|
||||
mstring_append_fmt(vars, "t%d = t%d * (bumpScale%d * dsdtl%d.p + bumpOffset%d);\n",
|
||||
mstring_append_fmt(vars, "t%d = t%d * (bumpScale[%d] * dsdtl%d.p + bumpOffset[%d]);\n",
|
||||
i, i, i, i, i);
|
||||
break;
|
||||
case PS_TEXTUREMODES_BRDF:
|
||||
|
@ -1250,7 +1246,7 @@ static MString* psh_convert(struct PixelShader *ps)
|
|||
if (ps->state.rect_tex[i]) {
|
||||
mstring_append_fmt(preflight,
|
||||
"vec2 norm%d(vec2 coord) {\n"
|
||||
" return coord / (textureSize(texSamp%d, 0) / texScale%d);\n"
|
||||
" return coord / (textureSize(texSamp%d, 0) / texScale[%d]);\n"
|
||||
"}\n",
|
||||
i, i, i);
|
||||
mstring_append_fmt(preflight,
|
||||
|
@ -1437,3 +1433,164 @@ MString *pgraph_gen_psh_glsl(const PshState state, GenPshGlslOptions opts)
|
|||
|
||||
return psh_convert(&ps);
|
||||
}
|
||||
|
||||
void pgraph_set_psh_uniform_values(PGRAPHState *pg, const PshUniformLocs locs,
|
||||
PshUniformValues *values)
|
||||
{
|
||||
/* update combiner constants */
|
||||
if (locs[PshUniform_consts] != -1) {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
uint32_t constant[2];
|
||||
if (i == 8) {
|
||||
/* final combiner */
|
||||
constant[0] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR0);
|
||||
constant[1] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR1);
|
||||
} else {
|
||||
constant[0] =
|
||||
pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR0 + i * 4);
|
||||
constant[1] =
|
||||
pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR1 + i * 4);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
int idx = i * 2 + j;
|
||||
pgraph_argb_pack32_to_rgba_float(constant[j],
|
||||
values->consts[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (locs[PshUniform_alphaRef] != -1) {
|
||||
int alpha_ref = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0),
|
||||
NV_PGRAPH_CONTROL_0_ALPHAREF);
|
||||
values->alphaRef[0] = alpha_ref;
|
||||
}
|
||||
if (locs[PshUniform_colorKey] != -1) {
|
||||
values->colorKey[0] = pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR0);
|
||||
values->colorKey[1] = pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR1);
|
||||
values->colorKey[2] = pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR2);
|
||||
values->colorKey[3] = pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR3);
|
||||
}
|
||||
if (locs[PshUniform_colorKeyMask] != -1) {
|
||||
for (int i = 0; i < NV2A_MAX_TEXTURES; i++) {
|
||||
values->colorKeyMask[i] =
|
||||
pgraph_get_color_key_mask_for_texture(pg, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* For each texture stage */
|
||||
for (int i = 0; i < NV2A_MAX_TEXTURES; i++) {
|
||||
/* Bump luminance only during stages 1 - 3 */
|
||||
if (i > 0) {
|
||||
if (locs[PshUniform_bumpMat] != -1) {
|
||||
uint32_t m_u32[4];
|
||||
m_u32[0] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT00 + 4 * (i - 1));
|
||||
m_u32[1] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT01 + 4 * (i - 1));
|
||||
m_u32[2] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT10 + 4 * (i - 1));
|
||||
m_u32[3] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT11 + 4 * (i - 1));
|
||||
values->bumpMat[i][0] = *(float *)&m_u32[0];
|
||||
values->bumpMat[i][1] = *(float *)&m_u32[1];
|
||||
values->bumpMat[i][2] = *(float *)&m_u32[2];
|
||||
values->bumpMat[i][3] = *(float *)&m_u32[3];
|
||||
}
|
||||
if (locs[PshUniform_bumpScale] != -1) {
|
||||
uint32_t v =
|
||||
pgraph_reg_r(pg, NV_PGRAPH_BUMPSCALE1 + (i - 1) * 4);
|
||||
values->bumpScale[i] = *(float *)&v;
|
||||
}
|
||||
if (locs[PshUniform_bumpOffset] != -1) {
|
||||
uint32_t v =
|
||||
pgraph_reg_r(pg, NV_PGRAPH_BUMPOFFSET1 + (i - 1) * 4);
|
||||
values->bumpOffset[i] = *(float *)&v;
|
||||
}
|
||||
}
|
||||
if (locs[PshUniform_texScale] != -1) {
|
||||
values->texScale[0] = 1.0; /* Renderer will override this */
|
||||
}
|
||||
}
|
||||
|
||||
if (locs[PshUniform_fogColor] != -1) {
|
||||
uint32_t fog_color = pgraph_reg_r(pg, NV_PGRAPH_FOGCOLOR);
|
||||
values->fogColor[0][0] =
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_RED) / 255.0;
|
||||
values->fogColor[0][1] =
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_GREEN) / 255.0;
|
||||
values->fogColor[0][2] =
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_BLUE) / 255.0;
|
||||
values->fogColor[0][3] =
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_ALPHA) / 255.0;
|
||||
}
|
||||
|
||||
|
||||
float zmax;
|
||||
switch (pg->surface_shape.zeta_format) {
|
||||
case NV097_SET_SURFACE_FORMAT_ZETA_Z16:
|
||||
zmax = pg->surface_shape.z_format ? f16_max : (float)0xFFFF;
|
||||
break;
|
||||
case NV097_SET_SURFACE_FORMAT_ZETA_Z24S8:
|
||||
zmax = pg->surface_shape.z_format ? f24_max : (float)0xFFFFFF;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (locs[PshUniform_clipRange] != -1) {
|
||||
uint32_t zclip_min = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMIN);
|
||||
uint32_t zclip_max = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMAX);
|
||||
|
||||
values->clipRange[0][0] = 0;
|
||||
values->clipRange[0][1] = zmax;
|
||||
values->clipRange[0][2] = *(float *)&zclip_min;
|
||||
values->clipRange[0][3] = *(float *)&zclip_max;
|
||||
}
|
||||
|
||||
if (locs[PshUniform_depthOffset] != -1) {
|
||||
float zbias = 0.0f;
|
||||
|
||||
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
|
||||
(NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) {
|
||||
uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS);
|
||||
zbias = *(float *)&zbias_u32;
|
||||
|
||||
if (pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR) != 0 &&
|
||||
(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
|
||||
NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE)) {
|
||||
/* TODO: emulate zfactor when z_perspective true, i.e.
|
||||
* w-buffering. Perhaps calculate an additional offset based on
|
||||
* triangle orientation in geometry shader and pass the result
|
||||
* to fragment shader and add it to gl_FragDepth as well.
|
||||
*/
|
||||
NV2A_UNIMPLEMENTED("NV_PGRAPH_ZOFFSETFACTOR for w-buffering");
|
||||
}
|
||||
}
|
||||
|
||||
values->depthOffset[0] = zbias;
|
||||
}
|
||||
|
||||
/* Clipping regions */
|
||||
unsigned int max_gl_width = pg->surface_binding_dim.width;
|
||||
unsigned int max_gl_height = pg->surface_binding_dim.height;
|
||||
pgraph_apply_scaling_factor(pg, &max_gl_width, &max_gl_height);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint32_t x = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPX0 + i * 4);
|
||||
unsigned int x_min = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMIN);
|
||||
unsigned int x_max = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMAX) + 1;
|
||||
|
||||
uint32_t y = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPY0 + i * 4);
|
||||
unsigned int y_min = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMIN);
|
||||
unsigned int y_max = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMAX) + 1;
|
||||
|
||||
pgraph_apply_anti_aliasing_factor(pg, &x_min, &y_min);
|
||||
pgraph_apply_anti_aliasing_factor(pg, &x_max, &y_max);
|
||||
|
||||
pgraph_apply_scaling_factor(pg, &x_min, &y_min);
|
||||
pgraph_apply_scaling_factor(pg, &x_max, &y_max);
|
||||
|
||||
values->clipRegion[i][0] = x_min;
|
||||
values->clipRegion[i][1] = y_min;
|
||||
values->clipRegion[i][2] = x_max;
|
||||
values->clipRegion[i][3] = y_max;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,23 @@
|
|||
|
||||
#include "qemu/mstring.h"
|
||||
#include "hw/xbox/nv2a/pgraph/psh.h"
|
||||
#include "common.h"
|
||||
|
||||
#define PSH_UNIFORM_DECL_X(S, DECL) \
|
||||
DECL(S, alphaRef, int, 1) \
|
||||
DECL(S, bumpMat, mat2, 4) \
|
||||
DECL(S, bumpOffset, float, 4) \
|
||||
DECL(S, bumpScale, float, 4) \
|
||||
DECL(S, clipRange, vec4, 1) \
|
||||
DECL(S, clipRegion, ivec4, 8) \
|
||||
DECL(S, colorKey, uint, 4) \
|
||||
DECL(S, colorKeyMask, uint, 4) \
|
||||
DECL(S, consts, vec4, 18) \
|
||||
DECL(S, depthOffset, float, 1) \
|
||||
DECL(S, fogColor, vec4, 1) \
|
||||
DECL(S, texScale, float, 4)
|
||||
|
||||
DECL_UNIFORM_TYPES(PshUniform, PSH_UNIFORM_DECL_X)
|
||||
|
||||
typedef struct GenPshGlslOptions {
|
||||
bool vulkan;
|
||||
|
@ -31,6 +48,12 @@ typedef struct GenPshGlslOptions {
|
|||
int tex_binding;
|
||||
} GenPshGlslOptions;
|
||||
|
||||
typedef struct PGRAPHState PGRAPHState;
|
||||
|
||||
MString *pgraph_gen_psh_glsl(const PshState state, GenPshGlslOptions opts);
|
||||
|
||||
void pgraph_set_psh_uniform_values(PGRAPHState *pg,
|
||||
const PshUniformLocs locs,
|
||||
PshUniformValues *values);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,11 +30,10 @@ static void append_skinning_code(MString* str, bool mix,
|
|||
const char* output, const char* input,
|
||||
const char* matrix, const char* swizzle);
|
||||
|
||||
void pgraph_gen_vsh_ff_glsl(GenVshGlslOptions opts, const VshState *state,
|
||||
MString *header, MString *body, MString *uniforms)
|
||||
void pgraph_gen_vsh_ff_glsl(const VshState *state, MString *header,
|
||||
MString *body)
|
||||
{
|
||||
int i, j;
|
||||
const char *u = opts.vulkan ? "" : "uniform "; // FIXME: Remove
|
||||
|
||||
/* generate vertex shader mimicking fixed function */
|
||||
mstring_append(header,
|
||||
|
@ -55,11 +54,6 @@ void pgraph_gen_vsh_ff_glsl(GenVshGlslOptions opts, const VshState *state,
|
|||
"#define reserved2 v14\n"
|
||||
"#define reserved3 v15\n"
|
||||
"\n");
|
||||
mstring_append_fmt(uniforms,
|
||||
"%svec4 ltctxa[" stringify(NV2A_LTCTXA_COUNT) "];\n"
|
||||
"%svec4 ltctxb[" stringify(NV2A_LTCTXB_COUNT) "];\n"
|
||||
"%svec4 ltc1[" stringify(NV2A_LTC1_COUNT) "];\n", u, u, u
|
||||
);
|
||||
mstring_append(header,
|
||||
"\n"
|
||||
GLSL_DEFINE(projectionMat, GLSL_C_MAT4(NV_IGRAPH_XF_XFCTX_PMAT0))
|
||||
|
@ -236,15 +230,11 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
mstring_append(body, " oB1 = backSpecular;\n");
|
||||
} else {
|
||||
//FIXME: Do 2 passes if we want 2 sided-lighting?
|
||||
|
||||
mstring_append_fmt(uniforms, "%sfloat specularPower;\n", u);
|
||||
|
||||
static char alpha_source_diffuse[] = "diffuse.a";
|
||||
static char alpha_source_specular[] = "specular.a";
|
||||
static char alpha_source_material[] = "material_alpha";
|
||||
const char *alpha_source = alpha_source_diffuse;
|
||||
if (state->fixed_function.diffuse_src == MATERIAL_COLOR_SRC_MATERIAL) {
|
||||
mstring_append_fmt(uniforms, "%sfloat material_alpha;\n", u);
|
||||
alpha_source = alpha_source_material;
|
||||
} else if (state->fixed_function.diffuse_src == MATERIAL_COLOR_SRC_SPECULAR) {
|
||||
alpha_source = alpha_source_specular;
|
||||
|
@ -285,19 +275,15 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
if (state->fixed_function.light[i] == LIGHT_LOCAL
|
||||
|| state->fixed_function.light[i] == LIGHT_SPOT) {
|
||||
|
||||
mstring_append_fmt(uniforms,
|
||||
"%svec3 lightLocalPosition%d;\n"
|
||||
"%svec3 lightLocalAttenuation%d;\n",
|
||||
u, i, u, i);
|
||||
mstring_append_fmt(body,
|
||||
" vec3 tPos = tPosition.xyz/tPosition.w;\n"
|
||||
" vec3 VP = lightLocalPosition%d - tPos;\n"
|
||||
" vec3 VP = lightLocalPosition[%d] - tPos;\n"
|
||||
" float d = length(VP);\n"
|
||||
" if (d <= lightLocalRange(%d)) {\n" /* FIXME: Double check that range is inclusive */
|
||||
" VP = normalize(VP);\n"
|
||||
" float attenuation = 1.0 / (lightLocalAttenuation%d.x\n"
|
||||
" + lightLocalAttenuation%d.y * d\n"
|
||||
" + lightLocalAttenuation%d.z * d * d);\n"
|
||||
" float attenuation = 1.0 / (lightLocalAttenuation[%d].x\n"
|
||||
" + lightLocalAttenuation[%d].y * d\n"
|
||||
" + lightLocalAttenuation[%d].z * d * d);\n"
|
||||
" vec3 halfVector = normalize(VP + %s);\n"
|
||||
" float nDotVP = max(0.0, dot(tNormal, VP));\n"
|
||||
" float nDotHV = max(0.0, dot(tNormal, halfVector));\n",
|
||||
|
@ -311,14 +297,10 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
|
||||
/* lightLocalRange will be 1e+30 here */
|
||||
|
||||
mstring_append_fmt(uniforms,
|
||||
"%svec3 lightInfiniteHalfVector%d;\n"
|
||||
"%svec3 lightInfiniteDirection%d;\n",
|
||||
u, i, u, i);
|
||||
mstring_append_fmt(body,
|
||||
" {\n"
|
||||
" float attenuation = 1.0;\n"
|
||||
" vec3 lightDirection = normalize(lightInfiniteDirection%d);\n"
|
||||
" vec3 lightDirection = normalize(lightInfiniteDirection[%d]);\n"
|
||||
" float nDotVP = max(0.0, dot(tNormal, lightDirection));\n",
|
||||
i);
|
||||
if (state->fixed_function.local_eye) {
|
||||
|
@ -327,7 +309,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
);
|
||||
} else {
|
||||
mstring_append_fmt(body,
|
||||
" float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector%d));\n",
|
||||
" float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector[%d]));\n",
|
||||
i
|
||||
);
|
||||
}
|
||||
|
@ -482,7 +464,6 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
|
||||
/* FIXME: Testing */
|
||||
if (state->point_params_enable) {
|
||||
mstring_append_fmt(uniforms, "%sfloat pointParams[8];\n", u);
|
||||
mstring_append(
|
||||
body,
|
||||
" float d_e = length(position * modelViewMat0);\n"
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "qemu/mstring.h"
|
||||
#include "vsh.h"
|
||||
|
||||
void pgraph_gen_vsh_ff_glsl(GenVshGlslOptions opts, const VshState *state,
|
||||
MString *header, MString *body, MString *uniforms);
|
||||
void pgraph_gen_vsh_ff_glsl(const VshState *state, MString *header,
|
||||
MString *body);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,32 +20,40 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/xbox/nv2a/pgraph/shaders.h"
|
||||
#include "hw/xbox/nv2a/pgraph/pgraph.h"
|
||||
#include "common.h"
|
||||
#include "vsh.h"
|
||||
#include "vsh-ff.h"
|
||||
#include "vsh-prog.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
DEF_UNIFORM_INFO_ARR(VshUniform, VSH_UNIFORM_DECL_X)
|
||||
|
||||
MString *pgraph_gen_vsh_glsl(const VshState *state,
|
||||
GenVshGlslOptions opts)
|
||||
{
|
||||
int i;
|
||||
MString *output = mstring_new();
|
||||
mstring_append_fmt(output, "#version %d\n\n", opts.vulkan ? 450 : 400);
|
||||
MString *output =
|
||||
mstring_from_fmt("#version %d\n\n", opts.vulkan ? 450 : 400);
|
||||
|
||||
MString *header = mstring_from_str("");
|
||||
|
||||
MString *uniforms = mstring_from_str("");
|
||||
|
||||
const char *u = opts.vulkan ? "" : "uniform "; // FIXME: Remove
|
||||
|
||||
mstring_append_fmt(uniforms,
|
||||
"%svec4 clipRange;\n"
|
||||
"%svec2 surfaceSize;\n"
|
||||
"%svec4 c[" stringify(NV2A_VERTEXSHADER_CONSTANTS) "];\n"
|
||||
"%svec2 fogParam;\n",
|
||||
u, u, u, u
|
||||
);
|
||||
const char *u = opts.vulkan ? "" : "uniform ";
|
||||
for (int i = 0; i < ARRAY_SIZE(VshUniformInfo); i++) {
|
||||
const UniformInfo *info = &VshUniformInfo[i];
|
||||
const char *type_str = uniform_element_type_to_str[info->type];
|
||||
if (i == VshUniform_inlineValue &&
|
||||
opts.use_push_constants_for_uniform_attrs) {
|
||||
continue;
|
||||
}
|
||||
if (info->count == 1) {
|
||||
mstring_append_fmt(uniforms, "%s%s %s;\n", u, type_str,
|
||||
info->name);
|
||||
} else {
|
||||
mstring_append_fmt(uniforms, "%s%s %s[%zd];\n", u, type_str,
|
||||
info->name, info->count);
|
||||
}
|
||||
}
|
||||
|
||||
mstring_append(header,
|
||||
GLSL_DEFINE(fogPlane, GLSL_C(NV_IGRAPH_XF_XFCTX_FOG))
|
||||
|
@ -117,7 +125,7 @@ MString *pgraph_gen_vsh_glsl(const VshState *state,
|
|||
|
||||
int num_uniform_attrs = 0;
|
||||
|
||||
for (i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
|
||||
for (int i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
|
||||
bool is_uniform = state->uniform_attrs & (1 << i);
|
||||
bool is_swizzled = state->swizzle_attrs & (1 << i);
|
||||
bool is_compressed = state->compressed_attrs & (1 << i);
|
||||
|
@ -147,7 +155,7 @@ MString *pgraph_gen_vsh_glsl(const VshState *state,
|
|||
|
||||
MString *body = mstring_from_str("void main() {\n");
|
||||
|
||||
for (i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
|
||||
for (int i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
|
||||
if (state->compressed_attrs & (1 << i)) {
|
||||
mstring_append_fmt(
|
||||
body, "vec4 v%d = decompress_11_11_10(v%d_cmp);\n", i, i);
|
||||
|
@ -160,7 +168,7 @@ MString *pgraph_gen_vsh_glsl(const VshState *state,
|
|||
}
|
||||
|
||||
if (state->is_fixed_function) {
|
||||
pgraph_gen_vsh_ff_glsl(opts, state, header, body, uniforms);
|
||||
pgraph_gen_vsh_ff_glsl(state, header, body);
|
||||
} else {
|
||||
pgraph_gen_vsh_prog_glsl(
|
||||
VSH_VERSION_XVS, (uint32_t *)state->programmable.program_data,
|
||||
|
@ -307,10 +315,10 @@ MString *pgraph_gen_vsh_glsl(const VshState *state,
|
|||
mstring_append_fmt(output,
|
||||
"layout(push_constant) uniform PushConstants {\n"
|
||||
" vec4 inlineValue[%d];\n"
|
||||
"};\n\n", num_uniform_attrs);
|
||||
"};\n\n", NV2A_VERTEXSHADER_ATTRIBUTES);
|
||||
} else {
|
||||
mstring_append_fmt(uniforms, " vec4 inlineValue[%d];\n",
|
||||
num_uniform_attrs);
|
||||
NV2A_VERTEXSHADER_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
mstring_append_fmt(
|
||||
|
@ -331,3 +339,126 @@ MString *pgraph_gen_vsh_glsl(const VshState *state,
|
|||
mstring_unref(body);
|
||||
return output;
|
||||
}
|
||||
|
||||
void pgraph_set_vsh_uniform_values(PGRAPHState *pg, const VshState *state,
|
||||
const VshUniformLocs locs,
|
||||
VshUniformValues *values)
|
||||
{
|
||||
if (locs[VshUniform_c] != -1) {
|
||||
QEMU_BUILD_BUG_MSG(sizeof(values->c) != sizeof(pg->vsh_constants),
|
||||
"Uniform value size inconsistency");
|
||||
memcpy(values->c, pg->vsh_constants, sizeof(pg->vsh_constants));
|
||||
}
|
||||
|
||||
if (locs[VshUniform_clipRange] != -1) {
|
||||
float zmax;
|
||||
switch (pg->surface_shape.zeta_format) {
|
||||
case NV097_SET_SURFACE_FORMAT_ZETA_Z16:
|
||||
zmax = pg->surface_shape.z_format ? f16_max : (float)0xFFFF;
|
||||
break;
|
||||
case NV097_SET_SURFACE_FORMAT_ZETA_Z24S8:
|
||||
zmax = pg->surface_shape.z_format ? f24_max : (float)0xFFFFFF;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
uint32_t zclip_min = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMIN);
|
||||
uint32_t zclip_max = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMAX);
|
||||
|
||||
values->clipRange[0][0] = 0;
|
||||
values->clipRange[0][1] = zmax;
|
||||
values->clipRange[0][2] = *(float *)&zclip_min;
|
||||
values->clipRange[0][3] = *(float *)&zclip_max;
|
||||
}
|
||||
|
||||
if (locs[VshUniform_fogParam] != -1) {
|
||||
uint32_t param_0 = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM0);
|
||||
uint32_t param_1 = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM1);
|
||||
values->fogParam[0][0] = *(float *)¶m_0;
|
||||
values->fogParam[0][1] = *(float *)¶m_1;
|
||||
}
|
||||
|
||||
if (locs[VshUniform_pointParams] != -1) {
|
||||
QEMU_BUILD_BUG_MSG(sizeof(values->pointParams) !=
|
||||
sizeof(pg->point_params),
|
||||
"Uniform value size inconsistency");
|
||||
memcpy(values->pointParams, pg->point_params, sizeof(pg->point_params));
|
||||
}
|
||||
|
||||
if (locs[VshUniform_material_alpha] != -1) {
|
||||
values->material_alpha[0] = pg->material_alpha;
|
||||
}
|
||||
|
||||
if (locs[VshUniform_inlineValue] != -1) {
|
||||
pgraph_get_inline_values(pg, state->uniform_attrs, values->inlineValue,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (locs[VshUniform_surfaceSize] != -1) {
|
||||
unsigned int aa_width = 1, aa_height = 1;
|
||||
pgraph_apply_anti_aliasing_factor(pg, &aa_width, &aa_height);
|
||||
float width = (float)pg->surface_binding_dim.width / aa_width;
|
||||
float height = (float)pg->surface_binding_dim.height / aa_height;
|
||||
values->surfaceSize[0][0] = width;
|
||||
values->surfaceSize[0][1] = height;
|
||||
}
|
||||
|
||||
if (state->is_fixed_function) {
|
||||
/* update lighting constants */
|
||||
if (locs[VshUniform_ltctxa] != -1) {
|
||||
QEMU_BUILD_BUG_MSG(sizeof(values->ltctxa) != sizeof(pg->ltctxa),
|
||||
"Uniform value size inconsistency");
|
||||
memcpy(values->ltctxa, pg->ltctxa, sizeof(pg->ltctxa));
|
||||
}
|
||||
|
||||
if (locs[VshUniform_ltctxb] != -1) {
|
||||
QEMU_BUILD_BUG_MSG(sizeof(values->ltctxb) != sizeof(pg->ltctxb),
|
||||
"Uniform value size inconsistency");
|
||||
memcpy(values->ltctxb, pg->ltctxb, sizeof(pg->ltctxb));
|
||||
}
|
||||
|
||||
if (locs[VshUniform_ltc1] != -1) {
|
||||
QEMU_BUILD_BUG_MSG(sizeof(values->ltc1) != sizeof(pg->ltc1),
|
||||
"Uniform value size inconsistency");
|
||||
memcpy(values->ltc1, pg->ltc1, sizeof(pg->ltc1));
|
||||
}
|
||||
|
||||
if (locs[VshUniform_lightInfiniteHalfVector] != -1) {
|
||||
QEMU_BUILD_BUG_MSG(sizeof(values->lightInfiniteHalfVector) !=
|
||||
sizeof(pg->light_infinite_half_vector),
|
||||
"Uniform value size inconsistency");
|
||||
memcpy(values->lightInfiniteHalfVector,
|
||||
pg->light_infinite_half_vector,
|
||||
sizeof(pg->light_infinite_half_vector));
|
||||
}
|
||||
|
||||
if (locs[VshUniform_lightInfiniteDirection] != -1) {
|
||||
QEMU_BUILD_BUG_MSG(sizeof(values->lightInfiniteDirection) !=
|
||||
sizeof(pg->light_infinite_direction),
|
||||
"Uniform value size inconsistency");
|
||||
memcpy(values->lightInfiniteDirection, pg->light_infinite_direction,
|
||||
sizeof(pg->light_infinite_direction));
|
||||
}
|
||||
|
||||
if (locs[VshUniform_lightLocalPosition] != -1) {
|
||||
QEMU_BUILD_BUG_MSG(sizeof(values->lightLocalPosition) !=
|
||||
sizeof(pg->light_local_position),
|
||||
"Uniform value size inconsistency");
|
||||
memcpy(values->lightLocalPosition, pg->light_local_position,
|
||||
sizeof(pg->light_local_position));
|
||||
}
|
||||
|
||||
if (locs[VshUniform_lightLocalAttenuation] != -1) {
|
||||
QEMU_BUILD_BUG_MSG(sizeof(values->lightLocalAttenuation) !=
|
||||
sizeof(pg->light_local_attenuation),
|
||||
"Uniform value size inconsistency");
|
||||
memcpy(values->lightLocalAttenuation, pg->light_local_attenuation,
|
||||
sizeof(pg->light_local_attenuation));
|
||||
}
|
||||
|
||||
if (locs[VshUniform_specularPower] != -1) {
|
||||
values->specularPower[0] = pg->specular_power;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,26 @@
|
|||
|
||||
#include "qemu/mstring.h"
|
||||
#include "hw/xbox/nv2a/pgraph/vsh.h"
|
||||
#include "common.h"
|
||||
|
||||
#define VSH_UNIFORM_DECL_X(S, DECL) \
|
||||
DECL(S, c, vec4, NV2A_VERTEXSHADER_CONSTANTS) \
|
||||
DECL(S, clipRange, vec4, 1) \
|
||||
DECL(S, fogParam, vec2, 1) \
|
||||
DECL(S, inlineValue, vec4, NV2A_VERTEXSHADER_ATTRIBUTES) \
|
||||
DECL(S, lightInfiniteDirection, vec3, NV2A_MAX_LIGHTS) \
|
||||
DECL(S, lightInfiniteHalfVector, vec3, NV2A_MAX_LIGHTS) \
|
||||
DECL(S, lightLocalAttenuation, vec3, NV2A_MAX_LIGHTS) \
|
||||
DECL(S, lightLocalPosition, vec3, NV2A_MAX_LIGHTS) \
|
||||
DECL(S, ltc1, vec4, NV2A_LTC1_COUNT) \
|
||||
DECL(S, ltctxa, vec4, NV2A_LTCTXA_COUNT) \
|
||||
DECL(S, ltctxb, vec4, NV2A_LTCTXB_COUNT) \
|
||||
DECL(S, material_alpha, float, 1) \
|
||||
DECL(S, pointParams, float, 8) \
|
||||
DECL(S, specularPower, float, 1) \
|
||||
DECL(S, surfaceSize, vec2, 1)
|
||||
|
||||
DECL_UNIFORM_TYPES(VshUniform, VSH_UNIFORM_DECL_X)
|
||||
|
||||
typedef struct GenVshGlslOptions {
|
||||
bool vulkan;
|
||||
|
@ -32,7 +52,13 @@ typedef struct GenVshGlslOptions {
|
|||
int ubo_binding;
|
||||
} GenVshGlslOptions;
|
||||
|
||||
typedef struct PGRAPHState PGRAPHState;
|
||||
|
||||
MString *pgraph_gen_vsh_glsl(const VshState *state,
|
||||
GenVshGlslOptions glsl_opts);
|
||||
|
||||
void pgraph_set_vsh_uniform_values(PGRAPHState *pg, const VshState *state,
|
||||
const VshUniformLocs locs,
|
||||
VshUniformValues *values);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -269,12 +269,24 @@ static void block_to_uniforms(const SpvReflectBlockVariable *block, ShaderUnifor
|
|||
|
||||
assert(member->array.dims_count < 2);
|
||||
|
||||
int dim = 1;
|
||||
for (int i = 0; i < member->array.dims_count; i++) {
|
||||
dim *= member->array.dims[i];
|
||||
}
|
||||
int stride = MAX(member->array.stride, member->numeric.matrix.stride);
|
||||
if (member->numeric.matrix.column_count) {
|
||||
dim *= member->numeric.matrix.column_count;
|
||||
if (member->array.stride) {
|
||||
stride =
|
||||
member->array.stride / member->numeric.matrix.column_count;
|
||||
}
|
||||
}
|
||||
layout->uniforms[k] = (ShaderUniform){
|
||||
.name = strdup(member->name),
|
||||
.offset = member->offset,
|
||||
.dim_v = MAX(1, member->numeric.vector.component_count),
|
||||
.dim_a = MAX(member->array.dims_count ? member->array.dims[0] : 1, member->numeric.matrix.column_count),
|
||||
.stride = MAX(member->array.stride, member->numeric.matrix.stride),
|
||||
.dim_a = dim,
|
||||
.stride = stride,
|
||||
};
|
||||
|
||||
// fprintf(stderr, "<%s offset=%zd dim_v=%zd dim_a=%zd stride=%zd>\n",
|
||||
|
|
|
@ -63,7 +63,7 @@ static inline void uniform_std140(ShaderUniformLayout *layout)
|
|||
align = size;
|
||||
stride = 0;
|
||||
}
|
||||
|
||||
|
||||
offset = ROUND_UP(offset, align);
|
||||
|
||||
u->align = align;
|
||||
|
@ -87,7 +87,7 @@ static inline void uniform_std430(ShaderUniformLayout *layout)
|
|||
size *= u->dim_v;
|
||||
size_t align = size;
|
||||
size *= u->dim_a;
|
||||
|
||||
|
||||
offset = ROUND_UP(offset, align);
|
||||
|
||||
u->align = align;
|
||||
|
@ -120,10 +120,10 @@ void *uniform_ptr(ShaderUniformLayout *layout, int idx)
|
|||
return (char *)layout->allocation + layout->uniforms[idx - 1].offset;
|
||||
}
|
||||
|
||||
static inline
|
||||
void uniform_copy(ShaderUniformLayout *layout, int idx, void *values, size_t value_size, size_t count)
|
||||
static inline void uniform_copy(ShaderUniformLayout *layout, int idx,
|
||||
void *values, size_t value_size, size_t count)
|
||||
{
|
||||
assert(idx > 0 && "invalid uniform index");
|
||||
assert(idx > 0 && "invalid uniform index");
|
||||
|
||||
ShaderUniform *u = &layout->uniforms[idx - 1];
|
||||
const size_t element_size = value_size * u->dim_v;
|
||||
|
@ -135,14 +135,14 @@ void uniform_copy(ShaderUniformLayout *layout, int idx, void *values, size_t val
|
|||
|
||||
int index = 0;
|
||||
while (bytes_remaining) {
|
||||
assert(p_out < p_max);
|
||||
assert(index < u->dim_a);
|
||||
assert((p_out + element_size) <= p_max);
|
||||
assert(index < u->dim_a);
|
||||
memcpy(p_out, p_in, element_size);
|
||||
bytes_remaining -= element_size;
|
||||
p_out += u->stride;
|
||||
p_in += element_size;
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "hw/xbox/nv2a/pgraph/surface.h"
|
||||
#include "hw/xbox/nv2a/pgraph/texture.h"
|
||||
#include "hw/xbox/nv2a/pgraph/shaders.h"
|
||||
#include "hw/xbox/nv2a/pgraph/glsl/vsh.h"
|
||||
#include "hw/xbox/nv2a/pgraph/glsl/psh.h"
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <glslang/Include/glslang_c_interface.h>
|
||||
|
@ -165,39 +167,8 @@ typedef struct ShaderBinding {
|
|||
ShaderModuleInfo *fragment;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
int alpha_ref;
|
||||
int bump_mat[NV2A_MAX_TEXTURES];
|
||||
int bump_offset[NV2A_MAX_TEXTURES];
|
||||
int bump_scale[NV2A_MAX_TEXTURES];
|
||||
int clip_range;
|
||||
int clip_region;
|
||||
int color_key;
|
||||
int color_key_mask;
|
||||
int depth_offset;
|
||||
int fog_color;
|
||||
int psh_constant[9][2];
|
||||
int surface_size;
|
||||
int tex_scale[NV2A_MAX_TEXTURES];
|
||||
} psh;
|
||||
|
||||
struct {
|
||||
int clip_range;
|
||||
int fog_param;
|
||||
int light_infinite_direction[NV2A_MAX_LIGHTS];
|
||||
int light_infinite_half_vector[NV2A_MAX_LIGHTS];
|
||||
int light_local_attenuation[NV2A_MAX_LIGHTS];
|
||||
int light_local_position[NV2A_MAX_LIGHTS];
|
||||
int ltc1;
|
||||
int ltctxa;
|
||||
int ltctxb;
|
||||
int material_alpha;
|
||||
int point_params;
|
||||
int specular_power;
|
||||
int uniform_attrs;
|
||||
int vsh_constant;
|
||||
uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4];
|
||||
} vsh;
|
||||
PshUniformLocs psh;
|
||||
VshUniformLocs vsh;
|
||||
} uniform_locs;
|
||||
} ShaderBinding;
|
||||
|
||||
|
@ -555,7 +526,6 @@ void pgraph_vk_init_shaders(PGRAPHState *pg);
|
|||
void pgraph_vk_finalize_shaders(PGRAPHState *pg);
|
||||
void pgraph_vk_update_descriptor_sets(PGRAPHState *pg);
|
||||
void pgraph_vk_bind_shaders(PGRAPHState *pg);
|
||||
void pgraph_vk_update_shader_uniforms(PGRAPHState *pg);
|
||||
|
||||
// reports.c
|
||||
void pgraph_vk_init_reports(PGRAPHState *pg);
|
||||
|
|
|
@ -242,95 +242,15 @@ void pgraph_vk_update_descriptor_sets(PGRAPHState *pg)
|
|||
|
||||
static void update_shader_constant_locations(ShaderBinding *binding)
|
||||
{
|
||||
char tmp[64];
|
||||
|
||||
/* lookup fragment shader uniforms */
|
||||
for (int i = 0; i < 9; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
snprintf(tmp, sizeof(tmp), "c%d_%d", j, i);
|
||||
binding->uniform_locs.psh.psh_constant[i][j] =
|
||||
uniform_index(&binding->fragment->uniforms, tmp);
|
||||
}
|
||||
}
|
||||
binding->uniform_locs.psh.alpha_ref =
|
||||
uniform_index(&binding->fragment->uniforms, "alphaRef");
|
||||
binding->uniform_locs.psh.fog_color =
|
||||
uniform_index(&binding->fragment->uniforms, "fogColor");
|
||||
for (int i = 1; i < NV2A_MAX_TEXTURES; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "bumpMat%d", i);
|
||||
binding->uniform_locs.psh.bump_mat[i] =
|
||||
uniform_index(&binding->fragment->uniforms, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "bumpScale%d", i);
|
||||
binding->uniform_locs.psh.bump_scale[i] =
|
||||
uniform_index(&binding->fragment->uniforms, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "bumpOffset%d", i);
|
||||
binding->uniform_locs.psh.bump_offset[i] =
|
||||
uniform_index(&binding->fragment->uniforms, tmp);
|
||||
for (int i = 0; i < ARRAY_SIZE(binding->uniform_locs.vsh); i++) {
|
||||
binding->uniform_locs.vsh[i] =
|
||||
uniform_index(&binding->vertex->uniforms, VshUniformInfo[i].name);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NV2A_MAX_TEXTURES; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "texScale%d", i);
|
||||
binding->uniform_locs.psh.tex_scale[i] =
|
||||
uniform_index(&binding->fragment->uniforms, tmp);
|
||||
for (int i = 0; i < ARRAY_SIZE(binding->uniform_locs.psh); i++) {
|
||||
binding->uniform_locs.psh[i] =
|
||||
uniform_index(&binding->fragment->uniforms, PshUniformInfo[i].name);
|
||||
}
|
||||
|
||||
/* lookup vertex shader uniforms */
|
||||
binding->uniform_locs.vsh.vsh_constant =
|
||||
uniform_index(&binding->vertex->uniforms, "c");
|
||||
binding->uniform_locs.psh.surface_size =
|
||||
uniform_index(&binding->vertex->uniforms, "surfaceSize");
|
||||
binding->uniform_locs.vsh.clip_range =
|
||||
uniform_index(&binding->vertex->uniforms, "clipRange");
|
||||
binding->uniform_locs.psh.clip_range =
|
||||
uniform_index(&binding->fragment->uniforms, "clipRange");
|
||||
binding->uniform_locs.psh.depth_offset =
|
||||
uniform_index(&binding->fragment->uniforms, "depthOffset");
|
||||
binding->uniform_locs.vsh.fog_param =
|
||||
uniform_index(&binding->vertex->uniforms, "fogParam");
|
||||
|
||||
binding->uniform_locs.vsh.ltctxa =
|
||||
uniform_index(&binding->vertex->uniforms, "ltctxa");
|
||||
binding->uniform_locs.vsh.ltctxb =
|
||||
uniform_index(&binding->vertex->uniforms, "ltctxb");
|
||||
binding->uniform_locs.vsh.ltc1 =
|
||||
uniform_index(&binding->vertex->uniforms, "ltc1");
|
||||
|
||||
for (int i = 0; i < NV2A_MAX_LIGHTS; i++) {
|
||||
snprintf(tmp, sizeof(tmp), "lightInfiniteHalfVector%d", i);
|
||||
binding->uniform_locs.vsh.light_infinite_half_vector[i] =
|
||||
uniform_index(&binding->vertex->uniforms, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "lightInfiniteDirection%d", i);
|
||||
binding->uniform_locs.vsh.light_infinite_direction[i] =
|
||||
uniform_index(&binding->vertex->uniforms, tmp);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "lightLocalPosition%d", i);
|
||||
binding->uniform_locs.vsh.light_local_position[i] =
|
||||
uniform_index(&binding->vertex->uniforms, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "lightLocalAttenuation%d", i);
|
||||
binding->uniform_locs.vsh.light_local_attenuation[i] =
|
||||
uniform_index(&binding->vertex->uniforms, tmp);
|
||||
}
|
||||
|
||||
binding->uniform_locs.psh.clip_region =
|
||||
uniform_index(&binding->fragment->uniforms, "clipRegion");
|
||||
|
||||
binding->uniform_locs.vsh.point_params =
|
||||
uniform_index(&binding->vertex->uniforms, "pointParams");
|
||||
|
||||
binding->uniform_locs.vsh.material_alpha =
|
||||
uniform_index(&binding->vertex->uniforms, "material_alpha");
|
||||
|
||||
binding->uniform_locs.psh.color_key =
|
||||
uniform_index(&binding->fragment->uniforms, "colorKey");
|
||||
|
||||
binding->uniform_locs.psh.color_key_mask =
|
||||
uniform_index(&binding->fragment->uniforms, "colorKeyMask");
|
||||
|
||||
binding->uniform_locs.vsh.uniform_attrs =
|
||||
uniform_index(&binding->vertex->uniforms, "inlineValue");
|
||||
|
||||
binding->uniform_locs.vsh.specular_power =
|
||||
uniform_index(&binding->vertex->uniforms, "specularPower");
|
||||
}
|
||||
|
||||
static void shader_cache_entry_init(Lru *lru, LruNode *node, void *state)
|
||||
|
@ -467,310 +387,6 @@ static ShaderBinding *gen_shaders(PGRAPHState *pg, ShaderState *state)
|
|||
return snode;
|
||||
}
|
||||
|
||||
static void update_uniform_attr_values(PGRAPHState *pg, ShaderBinding *binding)
|
||||
{
|
||||
float values[NV2A_VERTEXSHADER_ATTRIBUTES][4];
|
||||
int num_uniform_attrs = 0;
|
||||
|
||||
pgraph_get_inline_values(pg, binding->state.vsh.uniform_attrs, values,
|
||||
&num_uniform_attrs);
|
||||
|
||||
if (num_uniform_attrs > 0) {
|
||||
uniform1fv(&binding->vertex->uniforms,
|
||||
binding->uniform_locs.vsh.uniform_attrs,
|
||||
num_uniform_attrs * 4, &values[0][0]);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Move to common
|
||||
static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding)
|
||||
{
|
||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||
ShaderState *state = &binding->state;
|
||||
|
||||
/* update combiner constants */
|
||||
for (int i = 0; i < 9; i++) {
|
||||
uint32_t constant[2];
|
||||
if (i == 8) {
|
||||
/* final combiner */
|
||||
constant[0] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR0);
|
||||
constant[1] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR1);
|
||||
} else {
|
||||
constant[0] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR0 + i * 4);
|
||||
constant[1] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR1 + i * 4);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
GLint loc = binding->uniform_locs.psh.psh_constant[i][j];
|
||||
if (loc != -1) {
|
||||
float value[4];
|
||||
pgraph_argb_pack32_to_rgba_float(constant[j], value);
|
||||
uniform1fv(&binding->fragment->uniforms, loc, 4, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (binding->uniform_locs.psh.alpha_ref != -1) {
|
||||
int alpha_ref = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0),
|
||||
NV_PGRAPH_CONTROL_0_ALPHAREF);
|
||||
uniform1i(&binding->fragment->uniforms,
|
||||
binding->uniform_locs.psh.alpha_ref, alpha_ref);
|
||||
}
|
||||
if (binding->uniform_locs.psh.color_key != -1) {
|
||||
uint32_t color_key_colors[4] = {
|
||||
pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR0),
|
||||
pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR1),
|
||||
pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR2),
|
||||
pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR3),
|
||||
};
|
||||
uniform1uiv(&binding->fragment->uniforms,
|
||||
binding->uniform_locs.psh.color_key, 4, color_key_colors);
|
||||
}
|
||||
uint32_t color_key_mask[4] = { 0 };
|
||||
|
||||
/* For each texture stage */
|
||||
for (int i = 0; i < NV2A_MAX_TEXTURES; i++) {
|
||||
int loc;
|
||||
|
||||
/* Bump luminance only during stages 1 - 3 */
|
||||
if (i > 0) {
|
||||
loc = binding->uniform_locs.psh.bump_mat[i];
|
||||
if (loc != -1) {
|
||||
uint32_t m_u32[4];
|
||||
m_u32[0] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT00 + 4 * (i - 1));
|
||||
m_u32[1] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT01 + 4 * (i - 1));
|
||||
m_u32[2] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT10 + 4 * (i - 1));
|
||||
m_u32[3] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT11 + 4 * (i - 1));
|
||||
float m[4];
|
||||
m[0] = *(float *)&m_u32[0];
|
||||
m[1] = *(float *)&m_u32[1];
|
||||
m[2] = *(float *)&m_u32[2];
|
||||
m[3] = *(float *)&m_u32[3];
|
||||
uniformMatrix2fv(&binding->fragment->uniforms, loc, m);
|
||||
}
|
||||
loc = binding->uniform_locs.psh.bump_scale[i];
|
||||
if (loc != -1) {
|
||||
uint32_t v =
|
||||
pgraph_reg_r(pg, NV_PGRAPH_BUMPSCALE1 + (i - 1) * 4);
|
||||
uniform1f(&binding->fragment->uniforms, loc, *(float *)&v);
|
||||
}
|
||||
loc = binding->uniform_locs.psh.bump_offset[i];
|
||||
if (loc != -1) {
|
||||
uint32_t v =
|
||||
pgraph_reg_r(pg, NV_PGRAPH_BUMPOFFSET1 + (i - 1) * 4);
|
||||
uniform1f(&binding->fragment->uniforms, loc, *(float *)&v);
|
||||
}
|
||||
}
|
||||
|
||||
loc = binding->uniform_locs.psh.tex_scale[i];
|
||||
if (loc != -1) {
|
||||
assert(pg->vk_renderer_state->texture_bindings[i] != NULL);
|
||||
float scale = pg->vk_renderer_state->texture_bindings[i]->key.scale;
|
||||
BasicColorFormatInfo f_basic =
|
||||
kelvin_color_format_info_map[pg->vk_renderer_state
|
||||
->texture_bindings[i]
|
||||
->key.state.color_format];
|
||||
if (!f_basic.linear) {
|
||||
scale = 1.0;
|
||||
}
|
||||
uniform1f(&binding->fragment->uniforms, loc, scale);
|
||||
}
|
||||
|
||||
color_key_mask[i] = pgraph_get_color_key_mask_for_texture(pg, i);
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.psh.color_key_mask != -1) {
|
||||
uniform1uiv(&binding->fragment->uniforms,
|
||||
binding->uniform_locs.psh.color_key_mask, 4,
|
||||
color_key_mask);
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.psh.fog_color != -1) {
|
||||
uint32_t fog_color = pgraph_reg_r(pg, NV_PGRAPH_FOGCOLOR);
|
||||
uniform4f(&binding->fragment->uniforms,
|
||||
binding->uniform_locs.psh.fog_color,
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_RED) / 255.0,
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_GREEN) / 255.0,
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_BLUE) / 255.0,
|
||||
GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_ALPHA) / 255.0);
|
||||
}
|
||||
if (binding->uniform_locs.vsh.fog_param != -1) {
|
||||
uint32_t v[2];
|
||||
v[0] = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM0);
|
||||
v[1] = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM1);
|
||||
uniform2f(&binding->vertex->uniforms,
|
||||
binding->uniform_locs.vsh.fog_param, *(float *)&v[0],
|
||||
*(float *)&v[1]);
|
||||
}
|
||||
|
||||
float zmax;
|
||||
switch (pg->surface_shape.zeta_format) {
|
||||
case NV097_SET_SURFACE_FORMAT_ZETA_Z16:
|
||||
zmax = pg->surface_shape.z_format ? f16_max : (float)0xFFFF;
|
||||
break;
|
||||
case NV097_SET_SURFACE_FORMAT_ZETA_Z24S8:
|
||||
zmax = pg->surface_shape.z_format ? f24_max : (float)0xFFFFFF;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (binding->state.vsh.is_fixed_function) {
|
||||
/* update lighting constants */
|
||||
struct {
|
||||
uint32_t *v;
|
||||
int locs;
|
||||
size_t len;
|
||||
} lighting_arrays[] = {
|
||||
{ &pg->ltctxa[0][0], binding->uniform_locs.vsh.ltctxa,
|
||||
NV2A_LTCTXA_COUNT },
|
||||
{ &pg->ltctxb[0][0], binding->uniform_locs.vsh.ltctxb,
|
||||
NV2A_LTCTXB_COUNT },
|
||||
{ &pg->ltc1[0][0], binding->uniform_locs.vsh.ltc1,
|
||||
NV2A_LTC1_COUNT },
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(lighting_arrays); i++) {
|
||||
uniform1iv(&binding->vertex->uniforms, lighting_arrays[i].locs,
|
||||
lighting_arrays[i].len * 4,
|
||||
(void *)lighting_arrays[i].v);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NV2A_MAX_LIGHTS; i++) {
|
||||
int loc = binding->uniform_locs.vsh.light_infinite_half_vector[i];
|
||||
if (loc != -1) {
|
||||
uniform1fv(&binding->vertex->uniforms, loc, 3,
|
||||
pg->light_infinite_half_vector[i]);
|
||||
}
|
||||
loc = binding->uniform_locs.vsh.light_infinite_direction[i];
|
||||
if (loc != -1) {
|
||||
uniform1fv(&binding->vertex->uniforms, loc, 3,
|
||||
pg->light_infinite_direction[i]);
|
||||
}
|
||||
|
||||
loc = binding->uniform_locs.vsh.light_local_position[i];
|
||||
if (loc != -1) {
|
||||
uniform1fv(&binding->vertex->uniforms, loc, 3,
|
||||
pg->light_local_position[i]);
|
||||
}
|
||||
loc = binding->uniform_locs.vsh.light_local_attenuation[i];
|
||||
if (loc != -1) {
|
||||
uniform1fv(&binding->vertex->uniforms, loc, 3,
|
||||
pg->light_local_attenuation[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.vsh.specular_power != -1) {
|
||||
uniform1f(&binding->vertex->uniforms,
|
||||
binding->uniform_locs.vsh.specular_power,
|
||||
pg->specular_power);
|
||||
}
|
||||
}
|
||||
|
||||
/* update vertex program constants */
|
||||
uniform1iv(&binding->vertex->uniforms,
|
||||
binding->uniform_locs.vsh.vsh_constant,
|
||||
NV2A_VERTEXSHADER_CONSTANTS * 4, (void *)pg->vsh_constants);
|
||||
|
||||
if (binding->uniform_locs.psh.surface_size != -1) {
|
||||
unsigned int aa_width = 1, aa_height = 1;
|
||||
pgraph_apply_anti_aliasing_factor(pg, &aa_width, &aa_height);
|
||||
uniform2f(&binding->vertex->uniforms,
|
||||
binding->uniform_locs.psh.surface_size,
|
||||
pg->surface_binding_dim.width / aa_width,
|
||||
pg->surface_binding_dim.height / aa_height);
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.vsh.clip_range != -1 ||
|
||||
binding->uniform_locs.psh.clip_range != -1) {
|
||||
uint32_t v[2];
|
||||
v[0] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMIN);
|
||||
v[1] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMAX);
|
||||
float zclip_min = *(float *)&v[0];
|
||||
float zclip_max = *(float *)&v[1];
|
||||
|
||||
if (binding->uniform_locs.vsh.clip_range != -1) {
|
||||
uniform4f(&binding->vertex->uniforms,
|
||||
binding->uniform_locs.vsh.clip_range, 0, zmax, zclip_min,
|
||||
zclip_max);
|
||||
}
|
||||
if (binding->uniform_locs.psh.clip_range != -1) {
|
||||
uniform4f(&binding->fragment->uniforms,
|
||||
binding->uniform_locs.psh.clip_range, 0, zmax, zclip_min,
|
||||
zclip_max);
|
||||
}
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.psh.depth_offset != -1) {
|
||||
float zbias = 0.0f;
|
||||
|
||||
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
|
||||
(NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) {
|
||||
uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS);
|
||||
zbias = *(float *)&zbias_u32;
|
||||
|
||||
if (pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR) != 0 &&
|
||||
(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
|
||||
NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE)) {
|
||||
/* TODO: emulate zfactor when z_perspective true, i.e.
|
||||
* w-buffering. Perhaps calculate an additional offset based on
|
||||
* triangle orientation in geometry shader and pass the result
|
||||
* to fragment shader and add it to gl_FragDepth as well.
|
||||
*/
|
||||
NV2A_UNIMPLEMENTED("NV_PGRAPH_ZOFFSETFACTOR for w-buffering");
|
||||
}
|
||||
}
|
||||
|
||||
uniform1f(&binding->fragment->uniforms,
|
||||
binding->uniform_locs.psh.depth_offset, zbias);
|
||||
}
|
||||
|
||||
/* Clipping regions */
|
||||
unsigned int max_gl_width = pg->surface_binding_dim.width;
|
||||
unsigned int max_gl_height = pg->surface_binding_dim.height;
|
||||
pgraph_apply_scaling_factor(pg, &max_gl_width, &max_gl_height);
|
||||
|
||||
uint32_t clip_regions[8][4];
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint32_t x = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPX0 + i * 4);
|
||||
unsigned int x_min = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMIN);
|
||||
unsigned int x_max = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMAX) + 1;
|
||||
uint32_t y = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPY0 + i * 4);
|
||||
unsigned int y_min = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMIN);
|
||||
unsigned int y_max = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMAX) + 1;
|
||||
pgraph_apply_anti_aliasing_factor(pg, &x_min, &y_min);
|
||||
pgraph_apply_anti_aliasing_factor(pg, &x_max, &y_max);
|
||||
|
||||
pgraph_apply_scaling_factor(pg, &x_min, &y_min);
|
||||
pgraph_apply_scaling_factor(pg, &x_max, &y_max);
|
||||
|
||||
clip_regions[i][0] = x_min;
|
||||
clip_regions[i][1] = y_min;
|
||||
clip_regions[i][2] = x_max;
|
||||
clip_regions[i][3] = y_max;
|
||||
}
|
||||
uniform1iv(&binding->fragment->uniforms,
|
||||
binding->uniform_locs.psh.clip_region, 8 * 4,
|
||||
(void *)clip_regions);
|
||||
|
||||
if (binding->uniform_locs.vsh.point_params != -1) {
|
||||
uniform1iv(&binding->vertex->uniforms,
|
||||
binding->uniform_locs.vsh.point_params,
|
||||
ARRAY_SIZE(pg->point_params), (void *)pg->point_params);
|
||||
}
|
||||
|
||||
if (binding->uniform_locs.vsh.material_alpha != -1) {
|
||||
uniform1f(&binding->vertex->uniforms,
|
||||
binding->uniform_locs.vsh.material_alpha, pg->material_alpha);
|
||||
}
|
||||
|
||||
if (!r->use_push_constants_for_uniform_attrs && state->vsh.uniform_attrs) {
|
||||
update_uniform_attr_values(pg, binding);
|
||||
}
|
||||
}
|
||||
|
||||
// Quickly check PGRAPH state to see if any registers have changed that
|
||||
// necessitate a full shader state inspection.
|
||||
static bool check_shaders_dirty(PGRAPHState *pg)
|
||||
|
@ -849,6 +465,71 @@ static bool check_shaders_dirty(PGRAPHState *pg)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void apply_uniform_updates(ShaderUniformLayout *layout,
|
||||
const UniformInfo *info, int *locs,
|
||||
void *values, size_t count)
|
||||
{
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (locs[i] != -1) {
|
||||
uniform_copy(layout, locs[i], (char*)values + info[i].val_offs,
|
||||
4, (info[i].size * info[i].count) / 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Dirty tracking
|
||||
static void update_shader_uniforms(PGRAPHState *pg)
|
||||
{
|
||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||
NV2A_VK_DGROUP_BEGIN("%s", __func__);
|
||||
nv2a_profile_inc_counter(NV2A_PROF_SHADER_BIND);
|
||||
|
||||
assert(r->shader_binding);
|
||||
ShaderBinding *binding = r->shader_binding;
|
||||
ShaderUniformLayout *layouts[] = { &binding->vertex->uniforms,
|
||||
&binding->fragment->uniforms };
|
||||
|
||||
VshUniformValues vsh_values;
|
||||
pgraph_set_vsh_uniform_values(pg, &binding->state.vsh,
|
||||
binding->uniform_locs.vsh, &vsh_values);
|
||||
apply_uniform_updates(&binding->vertex->uniforms, VshUniformInfo,
|
||||
binding->uniform_locs.vsh, &vsh_values,
|
||||
VshUniform__COUNT);
|
||||
|
||||
PshUniformValues psh_values;
|
||||
pgraph_set_psh_uniform_values(pg, binding->uniform_locs.psh, &psh_values);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
assert(r->texture_bindings[i] != NULL);
|
||||
float scale = r->texture_bindings[i]->key.scale;
|
||||
|
||||
BasicColorFormatInfo f_basic =
|
||||
kelvin_color_format_info_map[pg->vk_renderer_state
|
||||
->texture_bindings[i]
|
||||
->key.state.color_format];
|
||||
if (!f_basic.linear) {
|
||||
scale = 1.0;
|
||||
}
|
||||
|
||||
psh_values.texScale[i] = scale;
|
||||
}
|
||||
apply_uniform_updates(&binding->fragment->uniforms, PshUniformInfo,
|
||||
binding->uniform_locs.psh, &psh_values,
|
||||
PshUniform__COUNT);
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(layouts); i++) {
|
||||
uint64_t hash =
|
||||
fast_hash(layouts[i]->allocation, layouts[i]->total_size);
|
||||
r->uniforms_changed |= (hash != r->uniform_buffer_hashes[i]);
|
||||
r->uniform_buffer_hashes[i] = hash;
|
||||
}
|
||||
|
||||
nv2a_profile_inc_counter(r->uniforms_changed ?
|
||||
NV2A_PROF_SHADER_UBO_DIRTY :
|
||||
NV2A_PROF_SHADER_UBO_NOTDIRTY);
|
||||
|
||||
NV2A_VK_DGROUP_END();
|
||||
}
|
||||
|
||||
void pgraph_vk_bind_shaders(PGRAPHState *pg)
|
||||
{
|
||||
NV2A_VK_DGROUP_BEGIN("%s", __func__);
|
||||
|
@ -865,33 +546,7 @@ void pgraph_vk_bind_shaders(PGRAPHState *pg)
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Use dirty bits
|
||||
pgraph_vk_update_shader_uniforms(pg);
|
||||
|
||||
NV2A_VK_DGROUP_END();
|
||||
}
|
||||
|
||||
void pgraph_vk_update_shader_uniforms(PGRAPHState *pg)
|
||||
{
|
||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||
NV2A_VK_DGROUP_BEGIN("%s", __func__);
|
||||
nv2a_profile_inc_counter(NV2A_PROF_SHADER_BIND);
|
||||
|
||||
assert(r->shader_binding);
|
||||
ShaderBinding *binding = r->shader_binding;
|
||||
ShaderUniformLayout *layouts[] = { &binding->vertex->uniforms,
|
||||
&binding->fragment->uniforms };
|
||||
shader_update_constants(pg, r->shader_binding);
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(layouts); i++) {
|
||||
uint64_t hash = fast_hash(layouts[i]->allocation, layouts[i]->total_size);
|
||||
r->uniforms_changed |= (hash != r->uniform_buffer_hashes[i]);
|
||||
r->uniform_buffer_hashes[i] = hash;
|
||||
}
|
||||
|
||||
nv2a_profile_inc_counter(r->uniforms_changed ?
|
||||
NV2A_PROF_SHADER_UBO_DIRTY :
|
||||
NV2A_PROF_SHADER_UBO_NOTDIRTY);
|
||||
update_shader_uniforms(pg);
|
||||
|
||||
NV2A_VK_DGROUP_END();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue