mesa/src/gallium/frontends/d3d10umd/Shader.cpp

1415 lines
45 KiB
C++

/**************************************************************************
*
* Copyright 2012-2021 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
**************************************************************************/
/*
* Shader.cpp --
* Functions that manipulate shader resources.
*/
#include "Shader.h"
#include "ShaderParse.h"
#include "State.h"
#include "Query.h"
#include "Debug.h"
#include "Format.h"
#include "tgsi/tgsi_ureg.h"
#include "util/u_gen_mipmap.h"
#include "util/u_sampler.h"
#include "util/format/u_format.h"
/*
* ----------------------------------------------------------------------
*
* CreateEmptyShader --
*
* Update the driver's currently bound constant buffers.
*
* ----------------------------------------------------------------------
*/
void *
CreateEmptyShader(Device *pDevice,
enum pipe_shader_type processor)
{
struct pipe_context *pipe = pDevice->pipe;
struct ureg_program *ureg;
const struct tgsi_token *tokens;
uint nr_tokens;
if (processor == PIPE_SHADER_GEOMETRY) {
return NULL;
}
ureg = ureg_create(processor);
if (!ureg)
return NULL;
ureg_END(ureg);
tokens = ureg_get_tokens(ureg, &nr_tokens);
if (!tokens)
return NULL;
ureg_destroy(ureg);
struct pipe_shader_state state;
memset(&state, 0, sizeof state);
state.tokens = tokens;
void *handle;
switch (processor) {
case PIPE_SHADER_FRAGMENT:
handle = pipe->create_fs_state(pipe, &state);
break;
case PIPE_SHADER_VERTEX:
handle = pipe->create_vs_state(pipe, &state);
break;
case PIPE_SHADER_GEOMETRY:
handle = pipe->create_gs_state(pipe, &state);
break;
default:
handle = NULL;
assert(0);
}
assert(handle);
ureg_free_tokens(tokens);
return handle;
}
/*
* ----------------------------------------------------------------------
*
* CreateEmptyShader --
*
* Update the driver's currently bound constant buffers.
*
* ----------------------------------------------------------------------
*/
void
DeleteEmptyShader(Device *pDevice,
enum pipe_shader_type processor, void *handle)
{
struct pipe_context *pipe = pDevice->pipe;
if (processor == PIPE_SHADER_GEOMETRY) {
assert(handle == NULL);
return;
}
assert(handle != NULL);
switch (processor) {
case PIPE_SHADER_FRAGMENT:
pipe->delete_fs_state(pipe, handle);
break;
case PIPE_SHADER_VERTEX:
pipe->delete_vs_state(pipe, handle);
break;
case PIPE_SHADER_GEOMETRY:
pipe->delete_gs_state(pipe, handle);
break;
default:
assert(0);
}
}
/*
* ----------------------------------------------------------------------
*
* SetConstantBuffers --
*
* Update the driver's currently bound constant buffers.
*
* ----------------------------------------------------------------------
*/
static void
SetConstantBuffers(enum pipe_shader_type shader_type, // IN
D3D10DDI_HDEVICE hDevice, // IN
UINT StartBuffer, // IN
UINT NumBuffers, // IN
const D3D10DDI_HRESOURCE *phBuffers) // IN
{
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
for (UINT i = 0; i < NumBuffers; i++) {
struct pipe_constant_buffer cb;
memset(&cb, 0, sizeof cb);
cb.buffer = CastPipeResource(phBuffers[i]);
cb.buffer_offset = 0;
cb.buffer_size = cb.buffer ? cb.buffer->width0 : 0;
pipe->set_constant_buffer(pipe,
shader_type,
StartBuffer + i,
FALSE,
&cb);
}
}
/*
* ----------------------------------------------------------------------
*
* SetSamplers --
*
* Update the driver's currently bound sampler state.
*
* ----------------------------------------------------------------------
*/
static void
SetSamplers(enum pipe_shader_type shader_type, // IN
D3D10DDI_HDEVICE hDevice, // IN
UINT Offset, // IN
UINT NumSamplers, // IN
const D3D10DDI_HSAMPLER *phSamplers) // IN
{
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
void **samplers = pDevice->samplers[shader_type];
for (UINT i = 0; i < NumSamplers; i++) {
assert(Offset + i < PIPE_MAX_SAMPLERS);
samplers[Offset + i] = CastPipeSamplerState(phSamplers[i]);
}
pipe->bind_sampler_states(pipe, shader_type, 0, PIPE_MAX_SAMPLERS, samplers);
}
/*
* ----------------------------------------------------------------------
*
* SetSamplers --
*
* Update the driver's currently bound sampler state.
*
* ----------------------------------------------------------------------
*/
static void
SetShaderResources(enum pipe_shader_type shader_type, // IN
D3D10DDI_HDEVICE hDevice, // IN
UINT Offset, // IN
UINT NumViews, // IN
const D3D10DDI_HSHADERRESOURCEVIEW *phShaderResourceViews) // IN
{
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
assert(Offset + NumViews <= D3D10_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT);
struct pipe_sampler_view **sampler_views = pDevice->sampler_views[shader_type];
for (UINT i = 0; i < NumViews; i++) {
struct pipe_sampler_view *sampler_view =
CastPipeShaderResourceView(phShaderResourceViews[i]);
if (Offset + i < PIPE_MAX_SHADER_SAMPLER_VIEWS) {
sampler_views[Offset + i] = sampler_view;
} else {
if (sampler_view) {
LOG_UNSUPPORTED(TRUE);
break;
}
}
}
/*
* XXX: Now that the semantics are actually the same in gallium, should
* probably think about not updating all always... It should just work.
*/
pipe->set_sampler_views(pipe, shader_type, 0, PIPE_MAX_SHADER_SAMPLER_VIEWS,
0, sampler_views);
}
/*
* ----------------------------------------------------------------------
*
* CalcPrivateShaderSize --
*
* The CalcPrivateShaderSize function determines the size of
* the user-mode display driver's private region of memory
* (that is, the size of internal driver structures, not the
* size of the resource video memory) for a shader.
*
* ----------------------------------------------------------------------
*/
SIZE_T APIENTRY
CalcPrivateShaderSize(D3D10DDI_HDEVICE hDevice, // IN
__in_ecount (pShaderCode[1]) const UINT *pShaderCode, // IN
__in const D3D10DDIARG_STAGE_IO_SIGNATURES *pSignatures) // IN
{
return sizeof(Shader);
}
/*
* ----------------------------------------------------------------------
*
* DestroyShader --
*
* The DestroyShader function destroys the specified shader object.
* The shader object can be destoyed only if it is not currently
* bound to a display device.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
DestroyShader(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HSHADER hShader) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
Shader *pShader = CastShader(hShader);
if (pShader->handle) {
switch (pShader->type) {
case PIPE_SHADER_FRAGMENT:
pipe->delete_fs_state(pipe, pShader->handle);
break;
case PIPE_SHADER_VERTEX:
pipe->delete_vs_state(pipe, pShader->handle);
break;
case PIPE_SHADER_GEOMETRY:
pipe->delete_gs_state(pipe, pShader->handle);
break;
default:
assert(0);
}
}
if (pShader->state.tokens) {
ureg_free_tokens(pShader->state.tokens);
}
}
/*
* ----------------------------------------------------------------------
*
* CalcPrivateSamplerSize --
*
* The CalcPrivateSamplerSize function determines the size of the
* user-mode display driver's private region of memory (that is,
* the size of internal driver structures, not the size of the
* resource video memory) for a sampler.
*
* ----------------------------------------------------------------------
*/
SIZE_T APIENTRY
CalcPrivateSamplerSize(D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10_DDI_SAMPLER_DESC *pSamplerDesc) // IN
{
return sizeof(SamplerState);
}
static uint
translate_address_mode(D3D10_DDI_TEXTURE_ADDRESS_MODE AddressMode)
{
switch (AddressMode) {
case D3D10_DDI_TEXTURE_ADDRESS_WRAP:
return PIPE_TEX_WRAP_REPEAT;
case D3D10_DDI_TEXTURE_ADDRESS_MIRROR:
return PIPE_TEX_WRAP_MIRROR_REPEAT;
case D3D10_DDI_TEXTURE_ADDRESS_CLAMP:
return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
case D3D10_DDI_TEXTURE_ADDRESS_BORDER:
return PIPE_TEX_WRAP_CLAMP_TO_BORDER;
case D3D10_DDI_TEXTURE_ADDRESS_MIRRORONCE:
return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE;
default:
assert(0);
return PIPE_TEX_WRAP_REPEAT;
}
}
static uint
translate_comparison(D3D10_DDI_COMPARISON_FUNC Func)
{
switch (Func) {
case D3D10_DDI_COMPARISON_NEVER:
return PIPE_FUNC_NEVER;
case D3D10_DDI_COMPARISON_LESS:
return PIPE_FUNC_LESS;
case D3D10_DDI_COMPARISON_EQUAL:
return PIPE_FUNC_EQUAL;
case D3D10_DDI_COMPARISON_LESS_EQUAL:
return PIPE_FUNC_LEQUAL;
case D3D10_DDI_COMPARISON_GREATER:
return PIPE_FUNC_GREATER;
case D3D10_DDI_COMPARISON_NOT_EQUAL:
return PIPE_FUNC_NOTEQUAL;
case D3D10_DDI_COMPARISON_GREATER_EQUAL:
return PIPE_FUNC_GEQUAL;
case D3D10_DDI_COMPARISON_ALWAYS:
return PIPE_FUNC_ALWAYS;
default:
assert(0);
return PIPE_FUNC_ALWAYS;
}
}
static uint
translate_filter(D3D10_DDI_FILTER_TYPE Filter)
{
switch (Filter) {
case D3D10_DDI_FILTER_TYPE_POINT:
return PIPE_TEX_FILTER_NEAREST;
case D3D10_DDI_FILTER_TYPE_LINEAR:
return PIPE_TEX_FILTER_LINEAR;
default:
assert(0);
return PIPE_TEX_FILTER_NEAREST;
}
}
static uint
translate_min_filter(D3D10_DDI_FILTER Filter)
{
return translate_filter(D3D10_DDI_DECODE_MIN_FILTER(Filter));
}
static uint
translate_mag_filter(D3D10_DDI_FILTER Filter)
{
return translate_filter(D3D10_DDI_DECODE_MAG_FILTER(Filter));
}
/* Gallium uses a different enum for mipfilters, to accomodate the GL
* MIPFILTER_NONE mode.
*/
static uint
translate_mip_filter(D3D10_DDI_FILTER Filter)
{
switch (D3D10_DDI_DECODE_MIP_FILTER(Filter)) {
case D3D10_DDI_FILTER_TYPE_POINT:
return PIPE_TEX_MIPFILTER_NEAREST;
case D3D10_DDI_FILTER_TYPE_LINEAR:
return PIPE_TEX_MIPFILTER_LINEAR;
default:
assert(0);
return PIPE_TEX_MIPFILTER_NEAREST;
}
}
/*
* ----------------------------------------------------------------------
*
* CreateSampler --
*
* The CreateSampler function creates a sampler.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CreateSampler(D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10_DDI_SAMPLER_DESC *pSamplerDesc, // IN
D3D10DDI_HSAMPLER hSampler, // IN
D3D10DDI_HRTSAMPLER hRTSampler) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
SamplerState *pSamplerState = CastSamplerState(hSampler);
struct pipe_sampler_state state;
memset(&state, 0, sizeof state);
/* d3d10 has seamless cube filtering always enabled */
state.seamless_cube_map = 1;
/* Wrapping modes. */
state.wrap_s = translate_address_mode(pSamplerDesc->AddressU);
state.wrap_t = translate_address_mode(pSamplerDesc->AddressV);
state.wrap_r = translate_address_mode(pSamplerDesc->AddressW);
/* Filtering */
state.min_img_filter = translate_min_filter(pSamplerDesc->Filter);
state.mag_img_filter = translate_mag_filter(pSamplerDesc->Filter);
state.min_mip_filter = translate_mip_filter(pSamplerDesc->Filter);
if (D3D10_DDI_DECODE_IS_ANISOTROPIC_FILTER(pSamplerDesc->Filter)) {
state.max_anisotropy = pSamplerDesc->MaxAnisotropy;
}
/* XXX: Handle the following bit.
*/
LOG_UNSUPPORTED(D3D10_DDI_DECODE_IS_TEXT_1BIT_FILTER(pSamplerDesc->Filter));
/* Comparison. */
if (D3D10_DDI_DECODE_IS_COMPARISON_FILTER(pSamplerDesc->Filter)) {
state.compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE;
state.compare_func = translate_comparison(pSamplerDesc->ComparisonFunc);
}
state.normalized_coords = 1;
/* Level of detail. */
state.lod_bias = pSamplerDesc->MipLODBias;
state.min_lod = pSamplerDesc->MinLOD;
state.max_lod = pSamplerDesc->MaxLOD;
/* Border color. */
state.border_color.f[0] = pSamplerDesc->BorderColor[0];
state.border_color.f[1] = pSamplerDesc->BorderColor[1];
state.border_color.f[2] = pSamplerDesc->BorderColor[2];
state.border_color.f[3] = pSamplerDesc->BorderColor[3];
pSamplerState->handle = pipe->create_sampler_state(pipe, &state);
}
/*
* ----------------------------------------------------------------------
*
* DestroySampler --
*
* The DestroySampler function destroys the specified sampler object.
* The sampler object can be destoyed only if it is not currently
* bound to a display device.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
DestroySampler(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HSAMPLER hSampler) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
SamplerState *pSamplerState = CastSamplerState(hSampler);
pipe->delete_sampler_state(pipe, pSamplerState->handle);
}
/*
* ----------------------------------------------------------------------
*
* CreateVertexShader --
*
* The CreateVertexShader function creates a vertex shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CreateVertexShader(D3D10DDI_HDEVICE hDevice, // IN
__in_ecount (pShaderCode[1]) const UINT *pCode, // IN
D3D10DDI_HSHADER hShader, // IN
D3D10DDI_HRTSHADER hRTShader, // IN
__in const D3D10DDIARG_STAGE_IO_SIGNATURES *pSignatures) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
Shader *pShader = CastShader(hShader);
pShader->type = PIPE_SHADER_VERTEX;
pShader->output_resolved = TRUE;
memset(&pShader->state, 0, sizeof pShader->state);
pShader->state.tokens = Shader_tgsi_translate(pCode, pShader->output_mapping);
pShader->handle = pipe->create_vs_state(pipe, &pShader->state);
}
/*
* ----------------------------------------------------------------------
*
* VsSetShader --
*
* The VsSetShader function sets the vertex shader code so that all
* of the subsequent drawing operations use that code.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
VsSetShader(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HSHADER hShader) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
Shader *pShader = CastShader(hShader);
void *state = CastPipeShader(hShader);
pDevice->bound_vs = pShader;
if (!state) {
state = pDevice->empty_vs;
}
pipe->bind_vs_state(pipe, state);
}
/*
* ----------------------------------------------------------------------
*
* VsSetShaderResources --
*
* The VsSetShaderResources function sets resources for a
* vertex shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
VsSetShaderResources(D3D10DDI_HDEVICE hDevice, // IN
UINT Offset, // IN
UINT NumViews, // IN
__in_ecount (NumViews)
const D3D10DDI_HSHADERRESOURCEVIEW *phShaderResourceViews) // IN
{
LOG_ENTRYPOINT();
SetShaderResources(PIPE_SHADER_VERTEX, hDevice, Offset, NumViews, phShaderResourceViews);
}
/*
* ----------------------------------------------------------------------
*
* VsSetConstantBuffers --
*
* The VsSetConstantBuffers function sets constant buffers
* for a vertex shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
VsSetConstantBuffers(D3D10DDI_HDEVICE hDevice, // IN
UINT StartBuffer, // IN
UINT NumBuffers, // IN
__in_ecount (NumBuffers) const D3D10DDI_HRESOURCE *phBuffers) // IN
{
LOG_ENTRYPOINT();
SetConstantBuffers(PIPE_SHADER_VERTEX,
hDevice, StartBuffer, NumBuffers, phBuffers);
}
/*
* ----------------------------------------------------------------------
*
* VsSetSamplers --
*
* The VsSetSamplers function sets samplers for a vertex shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
VsSetSamplers(D3D10DDI_HDEVICE hDevice, // IN
UINT Offset, // IN
UINT NumSamplers, // IN
__in_ecount (NumSamplers) const D3D10DDI_HSAMPLER *phSamplers) // IN
{
LOG_ENTRYPOINT();
SetSamplers(PIPE_SHADER_VERTEX, hDevice, Offset, NumSamplers, phSamplers);
}
/*
* ----------------------------------------------------------------------
*
* CreateGeometryShader --
*
* The CreateGeometryShader function creates a geometry shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CreateGeometryShader(D3D10DDI_HDEVICE hDevice, // IN
__in_ecount (pShaderCode[1]) const UINT *pShaderCode, // IN
D3D10DDI_HSHADER hShader, // IN
D3D10DDI_HRTSHADER hRTShader, // IN
__in const D3D10DDIARG_STAGE_IO_SIGNATURES *pSignatures) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
Shader *pShader = CastShader(hShader);
pShader->type = PIPE_SHADER_GEOMETRY;
pShader->output_resolved = TRUE;
memset(&pShader->state, 0, sizeof pShader->state);
pShader->state.tokens = Shader_tgsi_translate(pShaderCode, pShader->output_mapping);
pShader->handle = pipe->create_gs_state(pipe, &pShader->state);
}
/*
* ----------------------------------------------------------------------
*
* GsSetShader --
*
* The GsSetShader function sets the geometry shader code so that
* all of the subsequent drawing operations use that code.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
GsSetShader(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HSHADER hShader) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = CastPipeContext(hDevice);
void *state = CastPipeShader(hShader);
Shader *pShader = CastShader(hShader);
assert(pipe->bind_gs_state);
if (pShader && !pShader->state.tokens) {
pDevice->bound_empty_gs = pShader;
} else {
pDevice->bound_empty_gs = NULL;
pipe->bind_gs_state(pipe, state);
}
}
/*
* ----------------------------------------------------------------------
*
* GsSetShaderResources --
*
* The GsSetShaderResources function sets resources for a
* geometry shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
GsSetShaderResources(D3D10DDI_HDEVICE hDevice, // IN
UINT Offset, // IN
UINT NumViews, // IN
__in_ecount (NumViews)
const D3D10DDI_HSHADERRESOURCEVIEW *phShaderResourceViews) // IN
{
LOG_ENTRYPOINT();
SetShaderResources(PIPE_SHADER_GEOMETRY, hDevice, Offset, NumViews, phShaderResourceViews);
}
/*
* ----------------------------------------------------------------------
*
* GsSetConstantBuffers --
*
* The GsSetConstantBuffers function sets constant buffers for
* a geometry shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
GsSetConstantBuffers(D3D10DDI_HDEVICE hDevice, // IN
UINT StartBuffer, // IN
UINT NumBuffers, // IN
__in_ecount (NumBuffers) const D3D10DDI_HRESOURCE *phBuffers) // IN
{
LOG_ENTRYPOINT();
SetConstantBuffers(PIPE_SHADER_GEOMETRY,
hDevice, StartBuffer, NumBuffers, phBuffers);
}
/*
* ----------------------------------------------------------------------
*
* GsSetSamplers --
*
* The GsSetSamplers function sets samplers for a geometry shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
GsSetSamplers(D3D10DDI_HDEVICE hDevice, // IN
UINT Offset, // IN
UINT NumSamplers, // IN
__in_ecount (NumSamplers) const D3D10DDI_HSAMPLER *phSamplers) // IN
{
LOG_ENTRYPOINT();
SetSamplers(PIPE_SHADER_GEOMETRY, hDevice, Offset, NumSamplers, phSamplers);
}
/*
* ----------------------------------------------------------------------
*
* CalcPrivateGeometryShaderWithStreamOutput --
*
* The CalcPrivateGeometryShaderWithStreamOutput function determines
* the size of the user-mode display driver's private region of memory
* (that is, the size of internal driver structures, not the size of
* the resource video memory) for a geometry shader with stream output.
*
* ----------------------------------------------------------------------
*/
SIZE_T APIENTRY
CalcPrivateGeometryShaderWithStreamOutput(
D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10DDIARG_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT *pCreateGeometryShaderWithStreamOutput, // IN
__in const D3D10DDIARG_STAGE_IO_SIGNATURES *pSignatures) // IN
{
LOG_ENTRYPOINT();
return sizeof(Shader);
}
/*
* ----------------------------------------------------------------------
*
* CreateGeometryShaderWithStreamOutput --
*
* The CreateGeometryShaderWithStreamOutput function creates a
* geometry shader with stream output.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CreateGeometryShaderWithStreamOutput(
D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10DDIARG_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT *pData, // IN
D3D10DDI_HSHADER hShader, // IN
D3D10DDI_HRTSHADER hRTShader, // IN
__in const D3D10DDIARG_STAGE_IO_SIGNATURES *pSignatures) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
Shader *pShader = CastShader(hShader);
int total_components[PIPE_MAX_SO_BUFFERS] = {0};
unsigned num_holes = 0;
boolean all_slot_zero = TRUE;
pShader->type = PIPE_SHADER_GEOMETRY;
memset(&pShader->state, 0, sizeof pShader->state);
if (pData->pShaderCode) {
pShader->state.tokens = Shader_tgsi_translate(pData->pShaderCode,
pShader->output_mapping);
}
pShader->output_resolved = (pShader->state.tokens != NULL);
for (unsigned i = 0; i < pData->NumEntries; ++i) {
CONST D3D10DDIARG_STREAM_OUTPUT_DECLARATION_ENTRY* pOutputStreamDecl =
&pData->pOutputStreamDecl[i];
BYTE RegisterMask = pOutputStreamDecl->RegisterMask;
unsigned start_component = 0;
unsigned num_components = 0;
if (RegisterMask) {
while ((RegisterMask & 1) == 0) {
++start_component;
RegisterMask >>= 1;
}
while (RegisterMask) {
++num_components;
RegisterMask >>= 1;
}
assert(start_component < 4);
assert(1 <= num_components && num_components <= 4);
LOG_UNSUPPORTED(((1 << num_components) - 1) << start_component !=
pOutputStreamDecl->RegisterMask);
}
if (pOutputStreamDecl->RegisterIndex == 0xffffffff) {
++num_holes;
} else {
unsigned idx = i - num_holes;
pShader->state.stream_output.output[idx].start_component =
start_component;
pShader->state.stream_output.output[idx].num_components =
num_components;
pShader->state.stream_output.output[idx].output_buffer =
pOutputStreamDecl->OutputSlot;
pShader->state.stream_output.output[idx].register_index =
ShaderFindOutputMapping(pShader, pOutputStreamDecl->RegisterIndex);
pShader->state.stream_output.output[idx].dst_offset =
total_components[pOutputStreamDecl->OutputSlot];
if (pOutputStreamDecl->OutputSlot != 0)
all_slot_zero = FALSE;
}
total_components[pOutputStreamDecl->OutputSlot] += num_components;
}
pShader->state.stream_output.num_outputs = pData->NumEntries - num_holes;
for (unsigned i = 0; i < PIPE_MAX_SO_BUFFERS; ++i) {
/* stream_output.stride[i] is in dwords */
if (all_slot_zero) {
pShader->state.stream_output.stride[i] =
pData->StreamOutputStrideInBytes / sizeof(float);
} else {
pShader->state.stream_output.stride[i] = total_components[i];
}
}
pShader->handle = pipe->create_gs_state(pipe, &pShader->state);
}
/*
* ----------------------------------------------------------------------
*
* SoSetTargets --
*
* The SoSetTargets function sets stream output target resources.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
SoSetTargets(D3D10DDI_HDEVICE hDevice, // IN
UINT SOTargets, // IN
UINT ClearTargets, // IN
__in_ecount (SOTargets) const D3D10DDI_HRESOURCE *phResource, // IN
__in_ecount (SOTargets) const UINT *pOffsets) // IN
{
unsigned i;
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
assert(SOTargets + ClearTargets <= PIPE_MAX_SO_BUFFERS);
for (i = 0; i < SOTargets; ++i) {
Resource *resource = CastResource(phResource[i]);
struct pipe_resource *buffer = CastPipeResource(phResource[i]);
struct pipe_stream_output_target *so_target =
resource ? resource->so_target : NULL;
if (buffer) {
unsigned buffer_size = buffer->width0;
if (!so_target ||
so_target->buffer != buffer ||
so_target->buffer_size != buffer_size) {
if (so_target) {
pipe_so_target_reference(&so_target, NULL);
}
so_target = pipe->create_stream_output_target(pipe, buffer,
0,/*buffer offset*/
buffer_size);
resource->so_target = so_target;
}
}
pDevice->so_targets[i] = so_target;
}
for (i = 0; i < ClearTargets; ++i) {
pDevice->so_targets[SOTargets + i] = NULL;
}
if (!pipe->set_stream_output_targets) {
LOG_UNSUPPORTED(pipe->set_stream_output_targets);
return;
}
pipe->set_stream_output_targets(pipe, SOTargets, pDevice->so_targets,
pOffsets);
}
/*
* ----------------------------------------------------------------------
*
* CreatePixelShader --
*
* The CreatePixelShader function converts pixel shader code into a
* hardware-specific format and associates this code with a
* shader handle.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CreatePixelShader(D3D10DDI_HDEVICE hDevice, // IN
__in_ecount (pShaderCode[1]) const UINT *pShaderCode, // IN
D3D10DDI_HSHADER hShader, // IN
D3D10DDI_HRTSHADER hRTShader, // IN
__in const D3D10DDIARG_STAGE_IO_SIGNATURES *pSignatures) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
Shader *pShader = CastShader(hShader);
pShader->type = PIPE_SHADER_FRAGMENT;
pShader->output_resolved = TRUE;
memset(&pShader->state, 0, sizeof pShader->state);
pShader->state.tokens = Shader_tgsi_translate(pShaderCode,
pShader->output_mapping);
pShader->handle = pipe->create_fs_state(pipe, &pShader->state);
}
/*
* ----------------------------------------------------------------------
*
* PsSetShader --
*
* The PsSetShader function sets a pixel shader to be used
* in all drawing operations.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
PsSetShader(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HSHADER hShader) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
struct pipe_context *pipe = pDevice->pipe;
void *state = CastPipeShader(hShader);
if (!state) {
state = pDevice->empty_fs;
}
pipe->bind_fs_state(pipe, state);
}
/*
* ----------------------------------------------------------------------
*
* PsSetShaderResources --
*
* The PsSetShaderResources function sets resources for a pixel shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
PsSetShaderResources(D3D10DDI_HDEVICE hDevice, // IN
UINT Offset, // IN
UINT NumViews, // IN
__in_ecount (NumViews)
const D3D10DDI_HSHADERRESOURCEVIEW *phShaderResourceViews) // IN
{
LOG_ENTRYPOINT();
SetShaderResources(PIPE_SHADER_FRAGMENT, hDevice, Offset, NumViews, phShaderResourceViews);
}
/*
* ----------------------------------------------------------------------
*
* PsSetConstantBuffers --
*
* The PsSetConstantBuffers function sets constant buffers for
* a pixel shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
PsSetConstantBuffers(D3D10DDI_HDEVICE hDevice, // IN
UINT StartBuffer, // IN
UINT NumBuffers, // IN
__in_ecount (NumBuffers) const D3D10DDI_HRESOURCE *phBuffers) // IN
{
LOG_ENTRYPOINT();
SetConstantBuffers(PIPE_SHADER_FRAGMENT,
hDevice, StartBuffer, NumBuffers, phBuffers);
}
/*
* ----------------------------------------------------------------------
*
* PsSetSamplers --
*
* The PsSetSamplers function sets samplers for a pixel shader.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
PsSetSamplers(D3D10DDI_HDEVICE hDevice, // IN
UINT Offset, // IN
UINT NumSamplers, // IN
__in_ecount (NumSamplers) const D3D10DDI_HSAMPLER *phSamplers) // IN
{
LOG_ENTRYPOINT();
SetSamplers(PIPE_SHADER_FRAGMENT, hDevice, Offset, NumSamplers, phSamplers);
}
/*
* ----------------------------------------------------------------------
*
* ShaderResourceViewReadAfterWriteHazard --
*
* The ShaderResourceViewReadAfterWriteHazard function informs
* the usermode display driver that the specified resource was
* used as an output from the graphics processing unit (GPU)
* and that the resource will be used as an input to the GPU.
* A shader resource view is also provided to indicate which
* view caused the hazard.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
ShaderResourceViewReadAfterWriteHazard(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HSHADERRESOURCEVIEW hShaderResourceView, // IN
D3D10DDI_HRESOURCE hResource) // IN
{
LOG_ENTRYPOINT();
/* Not actually necessary */
}
/*
* ----------------------------------------------------------------------
*
* CalcPrivateShaderResourceViewSize --
*
* The CalcPrivateShaderResourceViewSize function determines the size
* of the usermode display driver's private region of memory
* (that is, the size of internal driver structures, not the size of
* the resource video memory) for a shader resource view.
*
* ----------------------------------------------------------------------
*/
SIZE_T APIENTRY
CalcPrivateShaderResourceViewSize(
D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10DDIARG_CREATESHADERRESOURCEVIEW *pCreateSRView) // IN
{
return sizeof(ShaderResourceView);
}
/*
* ----------------------------------------------------------------------
*
* CalcPrivateShaderResourceViewSize --
*
* The CalcPrivateShaderResourceViewSize function determines the size
* of the usermode display driver's private region of memory
* (that is, the size of internal driver structures, not the size of
* the resource video memory) for a shader resource view.
*
* ----------------------------------------------------------------------
*/
SIZE_T APIENTRY
CalcPrivateShaderResourceViewSize1(
D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10_1DDIARG_CREATESHADERRESOURCEVIEW *pCreateSRView) // IN
{
return sizeof(ShaderResourceView);
}
/*
* ----------------------------------------------------------------------
*
* CreateShaderResourceView --
*
* The CreateShaderResourceView function creates a shader
* resource view.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CreateShaderResourceView(
D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10DDIARG_CREATESHADERRESOURCEVIEW *pCreateSRView, // IN
D3D10DDI_HSHADERRESOURCEVIEW hShaderResourceView, // IN
D3D10DDI_HRTSHADERRESOURCEVIEW hRTShaderResourceView) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
ShaderResourceView *pSRView = CastShaderResourceView(hShaderResourceView);
struct pipe_resource *resource;
enum pipe_format format;
struct pipe_sampler_view desc;
memset(&desc, 0, sizeof desc);
resource = CastPipeResource(pCreateSRView->hDrvResource);
format = FormatTranslate(pCreateSRView->Format, FALSE);
u_sampler_view_default_template(&desc,
resource,
format);
switch (pCreateSRView->ResourceDimension) {
case D3D10DDIRESOURCE_BUFFER: {
const struct util_format_description *fdesc = util_format_description(format);
desc.u.buf.offset = pCreateSRView->Buffer.FirstElement *
(fdesc->block.bits / 8) * fdesc->block.width;
desc.u.buf.size = pCreateSRView->Buffer.NumElements *
(fdesc->block.bits / 8) * fdesc->block.width;
}
break;
case D3D10DDIRESOURCE_TEXTURE1D:
desc.u.tex.first_level = pCreateSRView->Tex1D.MostDetailedMip;
desc.u.tex.last_level = pCreateSRView->Tex1D.MipLevels - 1 + desc.u.tex.first_level;
desc.u.tex.first_layer = pCreateSRView->Tex1D.FirstArraySlice;
desc.u.tex.last_layer = pCreateSRView->Tex1D.ArraySize - 1 + desc.u.tex.first_layer;
assert(pCreateSRView->Tex1D.MipLevels != 0 && pCreateSRView->Tex1D.MipLevels != (UINT)-1);
assert(pCreateSRView->Tex1D.ArraySize != 0 && pCreateSRView->Tex1D.ArraySize != (UINT)-1);
break;
case D3D10DDIRESOURCE_TEXTURE2D:
desc.u.tex.first_level = pCreateSRView->Tex2D.MostDetailedMip;
desc.u.tex.last_level = pCreateSRView->Tex2D.MipLevels - 1 + desc.u.tex.first_level;
desc.u.tex.first_layer = pCreateSRView->Tex2D.FirstArraySlice;
desc.u.tex.last_layer = pCreateSRView->Tex2D.ArraySize - 1 + desc.u.tex.first_layer;
assert(pCreateSRView->Tex2D.MipLevels != 0 && pCreateSRView->Tex2D.MipLevels != (UINT)-1);
assert(pCreateSRView->Tex2D.ArraySize != 0 && pCreateSRView->Tex2D.ArraySize != (UINT)-1);
break;
case D3D10DDIRESOURCE_TEXTURE3D:
desc.u.tex.first_level = pCreateSRView->Tex3D.MostDetailedMip;
desc.u.tex.last_level = pCreateSRView->Tex3D.MipLevels - 1 + desc.u.tex.first_level;
/* layer info filled in by default_template */
assert(pCreateSRView->Tex3D.MipLevels != 0 && pCreateSRView->Tex3D.MipLevels != (UINT)-1);
break;
case D3D10DDIRESOURCE_TEXTURECUBE:
desc.u.tex.first_level = pCreateSRView->TexCube.MostDetailedMip;
desc.u.tex.last_level = pCreateSRView->TexCube.MipLevels - 1 + desc.u.tex.first_level;
/* layer info filled in by default_template */
assert(pCreateSRView->TexCube.MipLevels != 0 && pCreateSRView->TexCube.MipLevels != (UINT)-1);
break;
default:
assert(0);
return;
}
pSRView->handle = pipe->create_sampler_view(pipe, resource, &desc);
}
/*
* ----------------------------------------------------------------------
*
* CreateShaderResourceView1 --
*
* The CreateShaderResourceView function creates a shader
* resource view.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
CreateShaderResourceView1(
D3D10DDI_HDEVICE hDevice, // IN
__in const D3D10_1DDIARG_CREATESHADERRESOURCEVIEW *pCreateSRView, // IN
D3D10DDI_HSHADERRESOURCEVIEW hShaderResourceView, // IN
D3D10DDI_HRTSHADERRESOURCEVIEW hRTShaderResourceView) // IN
{
LOG_ENTRYPOINT();
struct pipe_context *pipe = CastPipeContext(hDevice);
ShaderResourceView *pSRView = CastShaderResourceView(hShaderResourceView);
struct pipe_resource *resource;
enum pipe_format format;
struct pipe_sampler_view desc;
memset(&desc, 0, sizeof desc);
resource = CastPipeResource(pCreateSRView->hDrvResource);
format = FormatTranslate(pCreateSRView->Format, FALSE);
u_sampler_view_default_template(&desc,
resource,
format);
switch (pCreateSRView->ResourceDimension) {
case D3D10DDIRESOURCE_BUFFER: {
const struct util_format_description *fdesc = util_format_description(format);
desc.u.buf.offset = pCreateSRView->Buffer.FirstElement *
(fdesc->block.bits / 8) * fdesc->block.width;
desc.u.buf.size = pCreateSRView->Buffer.NumElements *
(fdesc->block.bits / 8) * fdesc->block.width;
}
break;
case D3D10DDIRESOURCE_TEXTURE1D:
desc.u.tex.first_level = pCreateSRView->Tex1D.MostDetailedMip;
desc.u.tex.last_level = pCreateSRView->Tex1D.MipLevels - 1 + desc.u.tex.first_level;
desc.u.tex.first_layer = pCreateSRView->Tex1D.FirstArraySlice;
desc.u.tex.last_layer = pCreateSRView->Tex1D.ArraySize - 1 + desc.u.tex.first_layer;
assert(pCreateSRView->Tex1D.MipLevels != 0 && pCreateSRView->Tex1D.MipLevels != (UINT)-1);
assert(pCreateSRView->Tex1D.ArraySize != 0 && pCreateSRView->Tex1D.ArraySize != (UINT)-1);
break;
case D3D10DDIRESOURCE_TEXTURE2D:
desc.u.tex.first_level = pCreateSRView->Tex2D.MostDetailedMip;
desc.u.tex.last_level = pCreateSRView->Tex2D.MipLevels - 1 + desc.u.tex.first_level;
desc.u.tex.first_layer = pCreateSRView->Tex2D.FirstArraySlice;
desc.u.tex.last_layer = pCreateSRView->Tex2D.ArraySize - 1 + desc.u.tex.first_layer;
assert(pCreateSRView->Tex2D.MipLevels != 0 && pCreateSRView->Tex2D.MipLevels != (UINT)-1);
assert(pCreateSRView->Tex2D.ArraySize != 0 && pCreateSRView->Tex2D.ArraySize != (UINT)-1);
break;
case D3D10DDIRESOURCE_TEXTURE3D:
desc.u.tex.first_level = pCreateSRView->Tex3D.MostDetailedMip;
desc.u.tex.last_level = pCreateSRView->Tex3D.MipLevels - 1 + desc.u.tex.first_level;
/* layer info filled in by default_template */
assert(pCreateSRView->Tex3D.MipLevels != 0 && pCreateSRView->Tex3D.MipLevels != (UINT)-1);
break;
case D3D10DDIRESOURCE_TEXTURECUBE:
desc.u.tex.first_level = pCreateSRView->TexCube.MostDetailedMip;
desc.u.tex.last_level = pCreateSRView->TexCube.MipLevels - 1 + desc.u.tex.first_level;
desc.u.tex.first_layer = pCreateSRView->TexCube.First2DArrayFace;
desc.u.tex.last_layer = 6*pCreateSRView->TexCube.NumCubes - 1 +
pCreateSRView->TexCube.First2DArrayFace;
assert(pCreateSRView->TexCube.MipLevels != 0 && pCreateSRView->TexCube.MipLevels != (UINT)-1);
break;
default:
assert(0);
return;
}
pSRView->handle = pipe->create_sampler_view(pipe, resource, &desc);
}
/*
* ----------------------------------------------------------------------
*
* DestroyShaderResourceView --
*
* The DestroyShaderResourceView function destroys the specified
* shader resource view object. The shader resource view object
* can be destoyed only if it is not currently bound to a
* display device.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
DestroyShaderResourceView(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HSHADERRESOURCEVIEW hShaderResourceView) // IN
{
LOG_ENTRYPOINT();
ShaderResourceView *pSRView = CastShaderResourceView(hShaderResourceView);
pipe_sampler_view_reference(&pSRView->handle, NULL);
}
/*
* ----------------------------------------------------------------------
*
* GenMips --
*
* The GenMips function generates the lower MIP-map levels
* on the specified shader-resource view.
*
* ----------------------------------------------------------------------
*/
void APIENTRY
GenMips(D3D10DDI_HDEVICE hDevice, // IN
D3D10DDI_HSHADERRESOURCEVIEW hShaderResourceView) // IN
{
LOG_ENTRYPOINT();
Device *pDevice = CastDevice(hDevice);
if (!CheckPredicate(pDevice)) {
return;
}
struct pipe_context *pipe = pDevice->pipe;
struct pipe_sampler_view *sampler_view = CastPipeShaderResourceView(hShaderResourceView);
util_gen_mipmap(pipe,
sampler_view->texture,
sampler_view->format,
sampler_view->u.tex.first_level,
sampler_view->u.tex.last_level,
sampler_view->u.tex.first_layer,
sampler_view->u.tex.last_layer,
PIPE_TEX_FILTER_LINEAR);
}
unsigned
ShaderFindOutputMapping(Shader *shader, unsigned registerIndex)
{
if (!shader || !shader->state.tokens)
return registerIndex;
for (unsigned i = 0; i < PIPE_MAX_SHADER_OUTPUTS; ++i) {
if (shader->output_mapping[i] == registerIndex)
return i;
}
return registerIndex;
}