/************************************************************************** * * 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; }