📄 glsl_shader.c
字号:
/*
* GLSL pixel and vertex shader implementation
*
* Copyright 2006 Jason Green
* Copyright 2006-2007 Henri Verbeet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/*
* D3D shader asm has swizzles on source parameters, and write masks for
* destination parameters. GLSL uses swizzles for both. The result of this is
* that for example "mov dst.xw, src.zyxw" becomes "dst.xw = src.zw" in GLSL.
* Ie, to generate a proper GLSL source swizzle, we need to take the D3D write
* mask for the destination parameter into account.
*/
#include "config.h"
#include <stdio.h>
#include "wined3d_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
WINE_DECLARE_DEBUG_CHANNEL(d3d_constants);
#define GLINFO_LOCATION (*gl_info)
typedef struct {
char reg_name[50];
char mask_str[6];
} glsl_dst_param_t;
typedef struct {
char reg_name[50];
char param_str[100];
} glsl_src_param_t;
typedef struct {
const char *name;
DWORD coord_mask;
} glsl_sample_function_t;
/** Prints the GLSL info log which will contain error messages if they exist */
void print_glsl_info_log(WineD3D_GL_Info *gl_info, GLhandleARB obj) {
int infologLength = 0;
char *infoLog;
GL_EXTCALL(glGetObjectParameterivARB(obj,
GL_OBJECT_INFO_LOG_LENGTH_ARB,
&infologLength));
/* A size of 1 is just a null-terminated string, so the log should be bigger than
* that if there are errors. */
if (infologLength > 1)
{
infoLog = HeapAlloc(GetProcessHeap(), 0, infologLength);
GL_EXTCALL(glGetInfoLogARB(obj, infologLength, NULL, infoLog));
FIXME("Error received from GLSL shader #%u: %s\n", obj, debugstr_a(infoLog));
HeapFree(GetProcessHeap(), 0, infoLog);
}
}
/**
* Loads (pixel shader) samplers
*/
static void shader_glsl_load_psamplers(
WineD3D_GL_Info *gl_info,
IWineD3DStateBlock* iface) {
IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface;
GLhandleARB programId = stateBlock->glsl_program->programId;
GLhandleARB name_loc;
int i;
char sampler_name[20];
for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
_snprintf(sampler_name, sizeof(sampler_name), "Psampler%d", i);
name_loc = GL_EXTCALL(glGetUniformLocationARB(programId, sampler_name));
if (name_loc != -1) {
int mapped_unit = stateBlock->wineD3DDevice->texUnitMap[i];
if (mapped_unit != -1 && mapped_unit < GL_LIMITS(fragment_samplers)) {
TRACE("Loading %s for texture %d\n", sampler_name, mapped_unit);
GL_EXTCALL(glUniform1iARB(name_loc, mapped_unit));
checkGLcall("glUniform1iARB");
} else {
ERR("Trying to load sampler %s on unsupported unit %d\n", sampler_name, mapped_unit);
}
}
}
}
static void shader_glsl_load_vsamplers(WineD3D_GL_Info *gl_info, IWineD3DStateBlock* iface) {
IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface;
GLhandleARB programId = stateBlock->glsl_program->programId;
GLhandleARB name_loc;
char sampler_name[20];
int i;
for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
_snprintf(sampler_name, sizeof(sampler_name), "Vsampler%d", i);
name_loc = GL_EXTCALL(glGetUniformLocationARB(programId, sampler_name));
if (name_loc != -1) {
int mapped_unit = stateBlock->wineD3DDevice->texUnitMap[MAX_FRAGMENT_SAMPLERS + i];
if (mapped_unit != -1 && mapped_unit < GL_LIMITS(combined_samplers)) {
TRACE("Loading %s for texture %d\n", sampler_name, mapped_unit);
GL_EXTCALL(glUniform1iARB(name_loc, mapped_unit));
checkGLcall("glUniform1iARB");
} else {
ERR("Trying to load sampler %s on unsupported unit %d\n", sampler_name, mapped_unit);
}
}
}
}
/**
* Loads floating point constants (aka uniforms) into the currently set GLSL program.
* When constant_list == NULL, it will load all the constants.
*/
static void shader_glsl_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info,
unsigned int max_constants, float* constants, GLhandleARB *constant_locations,
struct list *constant_list) {
constants_entry *constant;
local_constant* lconst;
GLhandleARB tmp_loc;
DWORD i, j;
DWORD *idx;
if (TRACE_ON(d3d_shader)) {
LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) {
idx = constant->idx;
j = constant->count;
while (j--) {
i = *idx++;
tmp_loc = constant_locations[i];
if (tmp_loc != -1) {
TRACE_(d3d_constants)("Loading constants %i: %f, %f, %f, %f\n", i,
constants[i * 4 + 0], constants[i * 4 + 1],
constants[i * 4 + 2], constants[i * 4 + 3]);
}
}
}
}
LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) {
idx = constant->idx;
j = constant->count;
while (j--) {
i = *idx++;
tmp_loc = constant_locations[i];
if (tmp_loc != -1) {
/* We found this uniform name in the program - go ahead and send the data */
GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, constants + (i * 4)));
}
}
}
checkGLcall("glUniform4fvARB()");
/* Load immediate constants */
if (TRACE_ON(d3d_shader)) {
LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
tmp_loc = constant_locations[lconst->idx];
if (tmp_loc != -1) {
GLfloat* values = (GLfloat*)lconst->value;
TRACE_(d3d_constants)("Loading local constants %i: %f, %f, %f, %f\n", lconst->idx,
values[0], values[1], values[2], values[3]);
}
}
}
LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
tmp_loc = constant_locations[lconst->idx];
if (tmp_loc != -1) {
/* We found this uniform name in the program - go ahead and send the data */
GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, (GLfloat*)lconst->value));
}
}
checkGLcall("glUniform4fvARB()");
}
/**
* Loads integer constants (aka uniforms) into the currently set GLSL program.
* When @constants_set == NULL, it will load all the constants.
*/
static void shader_glsl_load_constantsI(
IWineD3DBaseShaderImpl* This,
WineD3D_GL_Info *gl_info,
GLhandleARB programId,
unsigned max_constants,
int* constants,
BOOL* constants_set) {
GLhandleARB tmp_loc;
int i;
char tmp_name[8];
char is_pshader = shader_is_pshader_version(This->baseShader.hex_version);
const char* prefix = is_pshader? "PI":"VI";
struct list* ptr;
for (i=0; i<max_constants; ++i) {
if (NULL == constants_set || constants_set[i]) {
TRACE_(d3d_constants)("Loading constants %i: %i, %i, %i, %i\n",
i, constants[i*4], constants[i*4+1], constants[i*4+2], constants[i*4+3]);
/* TODO: Benchmark and see if it would be beneficial to store the
* locations of the constants to avoid looking up each time */
_snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, i);
tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name));
if (tmp_loc != -1) {
/* We found this uniform name in the program - go ahead and send the data */
GL_EXTCALL(glUniform4ivARB(tmp_loc, 1, &constants[i*4]));
checkGLcall("glUniform4ivARB");
}
}
}
/* Load immediate constants */
ptr = list_head(&This->baseShader.constantsI);
while (ptr) {
local_constant* lconst = LIST_ENTRY(ptr, struct local_constant, entry);
unsigned int idx = lconst->idx;
GLint* values = (GLint*) lconst->value;
TRACE_(d3d_constants)("Loading local constants %i: %i, %i, %i, %i\n", idx,
values[0], values[1], values[2], values[3]);
_snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, idx);
tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name));
if (tmp_loc != -1) {
/* We found this uniform name in the program - go ahead and send the data */
GL_EXTCALL(glUniform4ivARB(tmp_loc, 1, values));
checkGLcall("glUniform4ivARB");
}
ptr = list_next(&This->baseShader.constantsI, ptr);
}
}
/**
* Loads boolean constants (aka uniforms) into the currently set GLSL program.
* When @constants_set == NULL, it will load all the constants.
*/
static void shader_glsl_load_constantsB(
IWineD3DBaseShaderImpl* This,
WineD3D_GL_Info *gl_info,
GLhandleARB programId,
unsigned max_constants,
BOOL* constants,
BOOL* constants_set) {
GLhandleARB tmp_loc;
int i;
char tmp_name[8];
char is_pshader = shader_is_pshader_version(This->baseShader.hex_version);
const char* prefix = is_pshader? "PB":"VB";
struct list* ptr;
for (i=0; i<max_constants; ++i) {
if (NULL == constants_set || constants_set[i]) {
TRACE_(d3d_constants)("Loading constants %i: %i;\n", i, constants[i*4]);
/* TODO: Benchmark and see if it would be beneficial to store the
* locations of the constants to avoid looking up each time */
_snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, i);
tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name));
if (tmp_loc != -1) {
/* We found this uniform name in the program - go ahead and send the data */
GL_EXTCALL(glUniform1ivARB(tmp_loc, 1, &constants[i*4]));
checkGLcall("glUniform1ivARB");
}
}
}
/* Load immediate constants */
ptr = list_head(&This->baseShader.constantsB);
while (ptr) {
local_constant* lconst = LIST_ENTRY(ptr, struct local_constant, entry);
unsigned int idx = lconst->idx;
GLint* values = (GLint*) lconst->value;
TRACE_(d3d_constants)("Loading local constants %i: %i\n", idx, values[0]);
_snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, idx);
tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name));
if (tmp_loc != -1) {
/* We found this uniform name in the program - go ahead and send the data */
GL_EXTCALL(glUniform1ivARB(tmp_loc, 1, values));
checkGLcall("glUniform1ivARB");
}
ptr = list_next(&This->baseShader.constantsB, ptr);
}
}
/**
* Loads the app-supplied constants into the currently set GLSL program.
*/
void shader_glsl_load_constants(
IWineD3DDevice* device,
char usePixelShader,
char useVertexShader) {
IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) device;
IWineD3DStateBlockImpl* stateBlock = deviceImpl->stateBlock;
WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info;
GLhandleARB *constant_locations;
struct list *constant_list;
GLhandleARB programId;
GLint pos;
if (!stateBlock->glsl_program) {
/* No GLSL program set - nothing to do. */
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -