Commit 2e5abc15 authored by Henri Verbeet's avatar Henri Verbeet Committed by Alexandre Julliard

wined3d: Implement WINED3DSIH_SAMPLE in the GLSL shader backend.

parent 52e665a3
......@@ -2957,6 +2957,74 @@ static void context_preload_textures(struct wined3d_context *context, const stru
}
}
static void context_bind_shader_resources(struct wined3d_context *context, const struct wined3d_state *state)
{
const struct wined3d_gl_info *gl_info = context->gl_info;
struct wined3d_shader_sampler_map_entry *entry;
struct wined3d_shader_resource_view *view;
struct wined3d_sampler *sampler;
struct wined3d_texture *texture;
struct wined3d_shader *shader;
unsigned int i, j, count;
static const struct
{
enum wined3d_shader_type type;
unsigned int base_idx;
unsigned int count;
}
shader_types[] =
{
{WINED3D_SHADER_TYPE_PIXEL, 0, MAX_FRAGMENT_SAMPLERS},
{WINED3D_SHADER_TYPE_VERTEX, MAX_FRAGMENT_SAMPLERS, MAX_VERTEX_SAMPLERS},
};
for (i = 0; i < ARRAY_SIZE(shader_types); ++i)
{
if (!(shader = state->shader[shader_types[i].type]))
continue;
count = shader->reg_maps.sampler_map.count;
if (count > shader_types[i].count)
{
FIXME("Shader %p needs %u samplers, but only %u are supported.\n",
shader, count, shader_types[i].count);
count = shader_types[i].count;
}
for (j = 0; j < count; ++j)
{
entry = &shader->reg_maps.sampler_map.entries[j];
if (!(view = state->shader_resource_view[shader_types[i].type][entry->resource_idx]))
{
WARN("No resource view bound at index %u, %u.\n", shader_types[i].type, entry->resource_idx);
continue;
}
if (view->resource->type == WINED3D_RTYPE_BUFFER)
{
FIXME("Buffer shader resources not supported.\n");
continue;
}
if (!(sampler = state->sampler[shader_types[i].type][entry->sampler_idx]))
{
WARN("No sampler object bound at index %u, %u.\n", shader_types[i].type, entry->sampler_idx);
continue;
}
texture = wined3d_texture_from_resource(view->resource);
wined3d_texture_load(texture, context, FALSE);
context_active_texture(context, gl_info, shader_types[i].base_idx + entry->bind_idx);
wined3d_texture_bind(texture, context, FALSE);
GL_EXTCALL(glBindSampler(shader_types[i].base_idx + entry->bind_idx, sampler->name));
checkGLcall("glBindSampler");
}
}
}
/* Context activation is done by the caller. */
BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_device *device)
{
......@@ -3030,6 +3098,12 @@ BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_de
context->constant_update_mask = 0;
}
if (context->update_shader_resource_bindings)
{
context_bind_shader_resources(context, state);
context->update_shader_resource_bindings = 0;
}
if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
{
context_check_fbo_status(context, GL_FRAMEBUFFER);
......
......@@ -704,6 +704,7 @@ static void wined3d_cs_exec_set_shader_resource_view(struct wined3d_cs *cs, cons
const struct wined3d_cs_set_shader_resource_view *op = data;
cs->state.shader_resource_view[op->type][op->view_idx] = op->view;
device_invalidate_state(cs->device, STATE_SHADER_RESOURCE_BINDING);
}
void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3d_shader_type type,
......@@ -725,6 +726,7 @@ static void wined3d_cs_exec_set_sampler(struct wined3d_cs *cs, const void *data)
const struct wined3d_cs_set_sampler *op = data;
cs->state.sampler[op->type][op->sampler_idx] = op->sampler;
device_invalidate_state(cs->device, STATE_SHADER_RESOURCE_BINDING);
}
void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type type,
......@@ -747,6 +749,7 @@ static void wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data)
cs->state.shader[op->type] = op->shader;
device_invalidate_state(cs->device, STATE_SHADER(op->type));
device_invalidate_state(cs->device, STATE_SHADER_RESOURCE_BINDING);
}
void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type type, struct wined3d_shader *shader)
......
......@@ -1058,59 +1058,68 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont
}
/* Declare texture samplers */
for (i = 0; i < shader->limits->sampler; ++i)
for (i = 0; i < reg_maps->sampler_map.count; ++i)
{
struct wined3d_shader_sampler_map_entry *entry;
BOOL shadow_sampler, tex_rect;
const char *sampler_type;
if (!reg_maps->resource_info[i].type)
entry = &reg_maps->sampler_map.entries[i];
if (entry->resource_idx >= ARRAY_SIZE(reg_maps->resource_info))
{
ERR("Invalid resource index %u.\n", entry->resource_idx);
continue;
}
shadow_sampler = version->type == WINED3D_SHADER_TYPE_PIXEL && (ps_args->shadow & (1 << i));
switch (reg_maps->resource_info[i].type)
shadow_sampler = version->type == WINED3D_SHADER_TYPE_PIXEL && (ps_args->shadow & (1 << entry->sampler_idx));
switch (reg_maps->resource_info[entry->resource_idx].type)
{
case WINED3D_SHADER_RESOURCE_TEXTURE_1D:
if (shadow_sampler)
shader_addline(buffer, "uniform sampler1DShadow %s_sampler%u;\n", prefix, i);
sampler_type = "sampler1DShadow";
else
shader_addline(buffer, "uniform sampler1D %s_sampler%u;\n", prefix, i);
sampler_type = "sampler1D";
break;
case WINED3D_SHADER_RESOURCE_TEXTURE_2D:
tex_rect = version->type == WINED3D_SHADER_TYPE_PIXEL && (ps_args->np2_fixup & (1 << i));
tex_rect = tex_rect && gl_info->supported[ARB_TEXTURE_RECTANGLE];
tex_rect = version->type == WINED3D_SHADER_TYPE_PIXEL
&& (ps_args->np2_fixup & (1 << entry->resource_idx))
&& gl_info->supported[ARB_TEXTURE_RECTANGLE];
if (shadow_sampler)
{
if (tex_rect)
shader_addline(buffer, "uniform sampler2DRectShadow %s_sampler%u;\n", prefix, i);
sampler_type = "sampler2DRectShadow";
else
shader_addline(buffer, "uniform sampler2DShadow %s_sampler%u;\n", prefix, i);
sampler_type = "sampler2DShadow";
}
else
{
if (tex_rect)
shader_addline(buffer, "uniform sampler2DRect %s_sampler%u;\n", prefix, i);
sampler_type = "sampler2DRect";
else
shader_addline(buffer, "uniform sampler2D %s_sampler%u;\n", prefix, i);
sampler_type = "sampler2D";
}
break;
case WINED3D_SHADER_RESOURCE_TEXTURE_3D:
if (shadow_sampler)
FIXME("Unsupported 3D shadow sampler.\n");
shader_addline(buffer, "uniform sampler3D %s_sampler%u;\n", prefix, i);
sampler_type = "sampler3D";
break;
case WINED3D_SHADER_RESOURCE_TEXTURE_CUBE:
if (shadow_sampler)
FIXME("Unsupported Cube shadow sampler.\n");
shader_addline(buffer, "uniform samplerCube %s_sampler%u;\n", prefix, i);
sampler_type = "samplerCube";
break;
default:
shader_addline(buffer, "uniform unsupported_sampler %s_sampler%u;\n", prefix, i);
sampler_type = "unsupported_sampler";
FIXME("Unhandled resource type %#x.\n", reg_maps->resource_info[i].type);
break;
}
shader_addline(buffer, "uniform %s %s_sampler%u;\n", sampler_type, prefix, entry->bind_idx);
}
/* Declare uniforms for NP2 texcoord fixup:
......@@ -3611,6 +3620,37 @@ static void shader_glsl_texldl(const struct wined3d_shader_instruction *ins)
"%s", coord_param.param_str);
}
static unsigned int shader_glsl_find_sampler(const struct wined3d_shader_sampler_map *sampler_map,
unsigned int resource_idx, unsigned int sampler_idx)
{
struct wined3d_shader_sampler_map_entry *entries = sampler_map->entries;
unsigned int i;
for (i = 0; i < sampler_map->count; ++i)
{
if (entries[i].resource_idx == resource_idx && entries[i].sampler_idx == sampler_idx)
return entries[i].bind_idx;
}
ERR("No GLSL sampler found for resource %u / sampler %u.\n", resource_idx, sampler_idx);
return ~0u;
}
static void shader_glsl_sample(const struct wined3d_shader_instruction *ins)
{
struct glsl_sample_function sample_function;
struct glsl_src_param coord_param;
unsigned int sampler_idx;
shader_glsl_get_sample_function(ins->ctx, ins->src[1].reg.idx[0].offset, 0, &sample_function);
shader_glsl_add_src_param(ins, &ins->src[0], sample_function.coord_mask, &coord_param);
sampler_idx = shader_glsl_find_sampler(&ins->ctx->reg_maps->sampler_map,
ins->src[1].reg.idx[0].offset, ins->src[2].reg.idx[0].offset);
shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE,
NULL, NULL, NULL, "%s", coord_param.param_str);
}
static void shader_glsl_texcoord(const struct wined3d_shader_instruction *ins)
{
/* FIXME: Make this work for more than just 2D textures */
......@@ -6736,7 +6776,7 @@ static const SHADER_HANDLER shader_glsl_instruction_handler_table[WINED3DSIH_TAB
/* WINED3DSIH_RET */ shader_glsl_ret,
/* WINED3DSIH_ROUND_NI */ shader_glsl_map2gl,
/* WINED3DSIH_RSQ */ shader_glsl_scalar_op,
/* WINED3DSIH_SAMPLE */ NULL,
/* WINED3DSIH_SAMPLE */ shader_glsl_sample,
/* WINED3DSIH_SAMPLE_GRAD */ NULL,
/* WINED3DSIH_SAMPLE_LOD */ NULL,
/* WINED3DSIH_SETP */ NULL,
......
......@@ -570,6 +570,51 @@ static BOOL shader_record_register_usage(struct wined3d_shader *shader, struct w
return TRUE;
}
static void shader_record_sample(struct wined3d_shader_reg_maps *reg_maps,
unsigned int resource_idx, unsigned int sampler_idx, unsigned int bind_idx)
{
struct wined3d_shader_sampler_map_entry *entries, *entry;
struct wined3d_shader_sampler_map *map;
unsigned int i;
map = &reg_maps->sampler_map;
entries = map->entries;
for (i = 0; i < map->count; ++i)
{
if (entries[i].resource_idx == resource_idx && entries[i].sampler_idx == sampler_idx)
return;
}
if (!map->size)
{
if (!(entries = HeapAlloc(GetProcessHeap(), 0, sizeof(*entries) * 4)))
{
ERR("Failed to allocate sampler map entries.\n");
return;
}
map->size = 4;
map->entries = entries;
}
else if (map->count == map->size)
{
size_t new_size = map->size * 2;
if (sizeof(*entries) * new_size <= sizeof(*entries) * map->size
|| !(entries = HeapReAlloc(GetProcessHeap(), 0, entries, sizeof(*entries) * new_size)))
{
ERR("Failed to resize sampler map entries.\n");
return;
}
map->size = new_size;
map->entries = entries;
}
entry = &entries[map->count++];
entry->resource_idx = resource_idx;
entry->sampler_idx = sampler_idx;
entry->bind_idx = bind_idx;
}
static unsigned int get_instr_extra_regcount(enum WINED3D_SHADER_INSTRUCTION_HANDLER instr, unsigned int param)
{
switch (instr)
......@@ -663,6 +708,7 @@ static HRESULT shader_get_registers_used(struct wined3d_shader *shader, const st
break;
case WINED3DSPR_SAMPLER:
shader_record_sample(reg_maps, reg_idx, reg_idx, reg_idx);
case WINED3DSPR_RESOURCE:
if (reg_idx >= ARRAY_SIZE(reg_maps->resource_info))
{
......@@ -903,6 +949,7 @@ static HRESULT shader_get_registers_used(struct wined3d_shader *shader, const st
TRACE("Setting fake 2D resource for 1.x pixelshader.\n");
reg_maps->resource_info[reg_idx].type = WINED3D_SHADER_RESOURCE_TEXTURE_2D;
reg_maps->resource_info[reg_idx].data_type = WINED3D_DATA_FLOAT;
shader_record_sample(reg_maps, reg_idx, reg_idx, reg_idx);
/* texbem is only valid with < 1.4 pixel shaders */
if (ins.handler_idx == WINED3DSIH_TEXBEM
......@@ -939,7 +986,16 @@ static HRESULT shader_get_registers_used(struct wined3d_shader *shader, const st
}
else if (ins.handler_idx == WINED3DSIH_ENDLOOP
|| ins.handler_idx == WINED3DSIH_ENDREP)
{
--cur_loop_depth;
}
else if (ins.handler_idx == WINED3DSIH_SAMPLE
|| ins.handler_idx == WINED3DSIH_SAMPLE_GRAD
|| ins.handler_idx == WINED3DSIH_SAMPLE_LOD)
{
shader_record_sample(reg_maps, ins.src[1].reg.idx[0].offset,
ins.src[2].reg.idx[0].offset, reg_maps->sampler_map.count);
}
if (ins.predicate)
if (!shader_record_register_usage(shader, reg_maps, &ins.predicate->reg,
......
......@@ -5081,6 +5081,14 @@ static void state_cb_warn(struct wined3d_context *context, const struct wined3d_
WARN("Constant buffers (%s) no supported.\n", debug_d3dstate(state_id));
}
static void state_shader_resource_binding(struct wined3d_context *context,
const struct wined3d_state *state, DWORD state_id)
{
TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id);
context->update_shader_resource_bindings = 1;
}
const struct StateEntryTemplate misc_state_template[] =
{
{ STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX), { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX), state_cb_vs, }, ARB_UNIFORM_BUFFER_OBJECT },
......@@ -5089,6 +5097,7 @@ const struct StateEntryTemplate misc_state_template[] =
{ STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY),{ STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY),state_cb_warn, }, WINED3D_GL_EXT_NONE },
{ STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL), { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL), state_cb_ps, }, ARB_UNIFORM_BUFFER_OBJECT },
{ STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL), { STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL), state_cb_warn, }, WINED3D_GL_EXT_NONE },
{ STATE_SHADER_RESOURCE_BINDING, { STATE_SHADER_RESOURCE_BINDING, state_shader_resource_binding}, WINED3D_GL_EXT_NONE },
{ STATE_RENDER(WINED3D_RS_SRCBLEND), { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE), NULL }, WINED3D_GL_EXT_NONE },
{ STATE_RENDER(WINED3D_RS_DESTBLEND), { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE), NULL }, WINED3D_GL_EXT_NONE },
{ STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE), { STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE), state_blend }, WINED3D_GL_EXT_NONE },
......@@ -6020,6 +6029,7 @@ static void validate_state_table(struct StateEntry *state_table)
STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX),
STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY),
STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL),
STATE_SHADER_RESOURCE_BINDING,
STATE_VIEWPORT,
STATE_LIGHT_TYPE,
STATE_SCISSORRECT,
......
......@@ -2901,6 +2901,8 @@ const char *debug_d3dstate(DWORD state)
return wine_dbg_sprintf("STATE_SHADER(%s)", debug_shader_type(state - STATE_SHADER(0)));
if (STATE_IS_CONSTANT_BUFFER(state))
return wine_dbg_sprintf("STATE_CONSTANT_BUFFER(%s)", debug_shader_type(state - STATE_CONSTANT_BUFFER(0)));
if (STATE_IS_SHADER_RESOURCE_BINDING(state))
return "STATE_SHADER_RESOURCE_BINDING";
if (STATE_IS_TRANSFORM(state))
return wine_dbg_sprintf("STATE_TRANSFORM(%s)", debug_d3dtstype(state - STATE_TRANSFORM(0)));
if (STATE_IS_STREAMSRC(state))
......
......@@ -581,6 +581,20 @@ struct wined3d_shader_resource_info
enum wined3d_data_type data_type;
};
struct wined3d_shader_sampler_map_entry
{
unsigned int resource_idx;
unsigned int sampler_idx;
unsigned int bind_idx;
};
struct wined3d_shader_sampler_map
{
struct wined3d_shader_sampler_map_entry *entries;
size_t size;
size_t count;
};
#define WINED3D_SHADER_VERSION(major, minor) (((major) << 8) | (minor))
struct wined3d_shader_reg_maps
......@@ -601,6 +615,7 @@ struct wined3d_shader_reg_maps
UINT cb_sizes[WINED3D_MAX_CBS];
struct wined3d_shader_resource_info resource_info[max(MAX_FRAGMENT_SAMPLERS, MAX_VERTEX_SAMPLERS)];
struct wined3d_shader_sampler_map sampler_map;
BYTE bumpmat; /* MAX_TEXTURES, 8 */
BYTE luminanceparams; /* MAX_TEXTURES, 8 */
......@@ -1002,7 +1017,10 @@ DWORD get_flexible_vertex_size(DWORD d3dvtVertexType) DECLSPEC_HIDDEN;
#define STATE_CONSTANT_BUFFER(a) (STATE_SHADER(WINED3D_SHADER_TYPE_COUNT) + (a))
#define STATE_IS_CONSTANT_BUFFER(a) ((a) >= STATE_CONSTANT_BUFFER(0) && (a) < STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COUNT))
#define STATE_TRANSFORM(a) (STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COUNT) + (a) - 1)
#define STATE_SHADER_RESOURCE_BINDING (STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COUNT))
#define STATE_IS_SHADER_RESOURCE_BINDING(a) ((a) == STATE_SHADER_RESOURCE_BINDING)
#define STATE_TRANSFORM(a) (STATE_SHADER_RESOURCE_BINDING + (a))
#define STATE_IS_TRANSFORM(a) ((a) >= STATE_TRANSFORM(1) && (a) <= STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(255)))
#define STATE_STREAMSRC (STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(255)) + 1)
......@@ -1141,7 +1159,8 @@ struct wined3d_context
DWORD needs_set : 1;
DWORD hdc_is_private : 1;
DWORD hdc_has_format : 1; /* only meaningful if hdc_is_private */
DWORD padding : 16;
DWORD update_shader_resource_bindings : 1;
DWORD padding : 15;
DWORD shader_update_mask;
DWORD constant_update_mask;
DWORD numbered_array_mask;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment