blob: 31e59bf38b116695c9130645d320bc320ace74fb [file] [log] [blame]
/**************************************************************************
*
* Copyright 2010 Luca Barbieri
*
* 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, sublicense, 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 above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* 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 NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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.
*
**************************************************************************/
DEBUG_GET_ONCE_BOOL_OPTION(dump_shaders, "D3D1X_DUMP_SHADERS", FALSE);
/* These cap sets are much more correct than the ones in u_caps.c */
/* TODO: it seems cube levels should be the same as 2D levels */
/* DX 9_1 */
static unsigned caps_dx_9_1[] = {
UTIL_CHECK_INT(MAX_RENDER_TARGETS, 1),
UTIL_CHECK_INT(MAX_TEXTURE_2D_LEVELS, 12), /* 2048 */
UTIL_CHECK_INT(MAX_TEXTURE_3D_LEVELS, 8), /* 256 */
UTIL_CHECK_INT(MAX_TEXTURE_CUBE_LEVELS, 10), /* 512 */
UTIL_CHECK_TERMINATE
};
/* DX 9_2 */
static unsigned caps_dx_9_2[] = {
UTIL_CHECK_CAP(OCCLUSION_QUERY),
UTIL_CHECK_CAP(TWO_SIDED_STENCIL),
UTIL_CHECK_CAP(TEXTURE_MIRROR_CLAMP),
UTIL_CHECK_CAP(BLEND_EQUATION_SEPARATE),
UTIL_CHECK_INT(MAX_RENDER_TARGETS, 1),
UTIL_CHECK_INT(MAX_TEXTURE_2D_LEVELS, 12), /* 2048 */
UTIL_CHECK_INT(MAX_TEXTURE_3D_LEVELS, 9), /* 256 */
UTIL_CHECK_INT(MAX_TEXTURE_CUBE_LEVELS, 10), /* 512 */
UTIL_CHECK_TERMINATE
};
/* DX 9_3 */
static unsigned caps_dx_9_3[] = {
UTIL_CHECK_CAP(OCCLUSION_QUERY),
UTIL_CHECK_CAP(TWO_SIDED_STENCIL),
UTIL_CHECK_CAP(TEXTURE_MIRROR_CLAMP),
UTIL_CHECK_CAP(BLEND_EQUATION_SEPARATE),
UTIL_CHECK_CAP(SM3),
UTIL_CHECK_CAP(VERTEX_ELEMENT_INSTANCE_DIVISOR),
UTIL_CHECK_CAP(OCCLUSION_QUERY),
UTIL_CHECK_INT(MAX_RENDER_TARGETS, 4),
UTIL_CHECK_INT(MAX_TEXTURE_2D_LEVELS, 13), /* 4096 */
UTIL_CHECK_INT(MAX_TEXTURE_3D_LEVELS, 9), /* 256 */
UTIL_CHECK_INT(MAX_TEXTURE_CUBE_LEVELS, 10), /* 512 */
UTIL_CHECK_TERMINATE
};
static unsigned caps_dx_10_0[] = {
UTIL_CHECK_CAP(INDEP_BLEND_ENABLE),
UTIL_CHECK_CAP(ANISOTROPIC_FILTER),
UTIL_CHECK_CAP(MIXED_COLORBUFFER_FORMATS),
UTIL_CHECK_CAP(FRAGMENT_COLOR_CLAMP_CONTROL),
UTIL_CHECK_CAP(CONDITIONAL_RENDER),
UTIL_CHECK_CAP(PRIMITIVE_RESTART),
UTIL_CHECK_CAP(TGSI_INSTANCEID),
UTIL_CHECK_INT(MAX_RENDER_TARGETS, 8),
UTIL_CHECK_INT(MAX_TEXTURE_2D_LEVELS, 13),
UTIL_CHECK_INT(MAX_TEXTURE_ARRAY_LAYERS, 512),
UTIL_CHECK_INT(MAX_STREAM_OUTPUT_BUFFERS, 4),
UTIL_CHECK_SHADER(VERTEX, MAX_INPUTS, 16),
UTIL_CHECK_SHADER(GEOMETRY, MAX_CONST_BUFFERS, 14),
UTIL_CHECK_SHADER(GEOMETRY, MAX_TEXTURE_SAMPLERS, 16),
UTIL_CHECK_SHADER(GEOMETRY, SUBROUTINES, 1),
UTIL_CHECK_SHADER(FRAGMENT, INTEGERS, 1),
UTIL_CHECK_TERMINATE
};
// this is called "screen" because in the D3D10 case it's only part of the device
template<bool threadsafe>
struct GalliumD3D11ScreenImpl : public GalliumD3D11Screen
{
D3D_FEATURE_LEVEL feature_level;
int format_support[PIPE_FORMAT_COUNT];
unsigned creation_flags;
unsigned exception_mode;
maybe_mutex_t<threadsafe> mutex;
/* TODO: Direct3D 11 specifies that fine-grained locking should be used if the driver supports it.
* Right now, I don't trust Gallium drivers to get this right.
*/
#define SYNCHRONIZED lock_t<maybe_mutex_t<threadsafe> > lock_(mutex)
GalliumD3D11ScreenImpl(struct pipe_screen* screen, struct pipe_context* immediate_pipe, BOOL owns_immediate_pipe,unsigned creation_flags, IDXGIAdapter* adapter)
: GalliumD3D11Screen(screen, immediate_pipe, adapter), creation_flags(creation_flags)
{
memset(&screen_caps, 0, sizeof(screen_caps));
screen_caps.gs = screen->get_shader_param(screen, PIPE_SHADER_GEOMETRY, PIPE_SHADER_CAP_MAX_INSTRUCTIONS) > 0;
screen_caps.so = screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) > 0;
screen_caps.queries = screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY);
screen_caps.render_condition = screen->get_param(screen, PIPE_CAP_CONDITIONAL_RENDER);
for(unsigned i = 0; i < PIPE_SHADER_TYPES; ++i)
screen_caps.constant_buffers[i] = screen->get_shader_param(screen, i, PIPE_SHADER_CAP_MAX_CONST_BUFFERS);
screen_caps.stages = 0;
for(unsigned i = 0; i < PIPE_SHADER_TYPES; ++i)
{
if(!screen->get_shader_param(screen, i, PIPE_SHADER_CAP_MAX_INSTRUCTIONS))
break;
screen_caps.stages = i + 1;
}
screen_caps.stages_with_sampling = (1 << screen_caps.stages) - 1;
if(!screen->get_shader_param(screen, PIPE_SHADER_VERTEX, PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS))
screen_caps.stages_with_sampling &=~ (1 << PIPE_SHADER_VERTEX);
memset(format_support, 0xff, sizeof(format_support));
float default_level = 9.1f;
if(!util_check_caps(screen, caps_dx_9_1))
_debug_printf("Warning: driver does not even meet D3D_FEATURE_LEVEL_9_1 features, advertising it anyway!\n");
else if(!util_check_caps(screen, caps_dx_9_2))
default_level = 9.1f;
else if(!util_check_caps(screen, caps_dx_9_3))
default_level = 9.2f;
else if(!util_check_caps(screen, caps_dx_10_0))
default_level = 9.3f;
else
default_level = 10.0f;
char default_level_name[64];
sprintf(default_level_name, "%.1f", default_level);
float feature_level_number = atof(debug_get_option("D3D11_FEATURE_LEVEL", default_level_name));
if(!feature_level_number)
feature_level_number = default_level;
#if API >= 11
if(feature_level_number >= 11.0f)
feature_level = D3D_FEATURE_LEVEL_11_0;
else
#endif
if(feature_level_number >= 10.1f)
feature_level = D3D_FEATURE_LEVEL_10_1;
else if(feature_level_number >= 10.0f)
feature_level = D3D_FEATURE_LEVEL_10_0;
else if(feature_level_number >= 9.3f)
feature_level = D3D_FEATURE_LEVEL_9_3;
else if(feature_level_number >= 9.2f)
feature_level = D3D_FEATURE_LEVEL_9_2;
else
feature_level = D3D_FEATURE_LEVEL_9_1;
#if API >= 11
immediate_context = GalliumD3D11ImmediateDeviceContext_Create(this, immediate_pipe, owns_immediate_pipe);
// release to the reference to ourselves that the immediate context took, to avoid a garbage cycle
immediate_context->Release();
#endif
}
~GalliumD3D11ScreenImpl()
{
#if API >= 11
GalliumD3D11ImmediateDeviceContext_Destroy(immediate_context);
#endif
}
virtual D3D_FEATURE_LEVEL STDMETHODCALLTYPE GetFeatureLevel(void)
{
return feature_level;
}
virtual unsigned STDMETHODCALLTYPE GetCreationFlags(void)
{
return creation_flags;
}
virtual HRESULT STDMETHODCALLTYPE GetDeviceRemovedReason(void)
{
return S_OK;
}
#if API >= 11
virtual void STDMETHODCALLTYPE GetImmediateContext(
ID3D11DeviceContext **out_immediate_context)
{
immediate_context->AddRef();
*out_immediate_context = immediate_context;
}
#endif
virtual HRESULT STDMETHODCALLTYPE SetExceptionMode(unsigned RaiseFlags)
{
exception_mode = RaiseFlags;
return S_OK;
}
virtual unsigned STDMETHODCALLTYPE GetExceptionMode(void)
{
return exception_mode;
}
virtual HRESULT STDMETHODCALLTYPE CheckCounter(
const D3D11_COUNTER_DESC *desc,
D3D11_COUNTER_TYPE *type,
unsigned *active_counters,
LPSTR sz_name,
unsigned *name_length,
LPSTR sz_units,
unsigned *units_length,
LPSTR sz_description,
unsigned *description_length)
{
return E_NOTIMPL;
}
virtual void STDMETHODCALLTYPE CheckCounterInfo(
D3D11_COUNTER_INFO *counter_info)
{
/* none supported at the moment */
counter_info->LastDeviceDependentCounter = (D3D11_COUNTER)0;
counter_info->NumDetectableParallelUnits = 1;
counter_info->NumSimultaneousCounters = 0;
}
#if API >= 11
virtual HRESULT STDMETHODCALLTYPE CheckFeatureSupport(
D3D11_FEATURE feature,
void *out_feature_support_data,
unsigned feature_support_data_size)
{
SYNCHRONIZED;
switch(feature)
{
case D3D11_FEATURE_THREADING:
{
D3D11_FEATURE_DATA_THREADING* data = (D3D11_FEATURE_DATA_THREADING*)out_feature_support_data;
if(feature_support_data_size != sizeof(*data))
return E_INVALIDARG;
data->DriverCommandLists = FALSE;
data->DriverConcurrentCreates = FALSE;
return S_OK;
}
case D3D11_FEATURE_DOUBLES:
{
D3D11_FEATURE_DATA_DOUBLES* data = (D3D11_FEATURE_DATA_DOUBLES*)out_feature_support_data;
if(feature_support_data_size != sizeof(*data))
return E_INVALIDARG;
data->DoublePrecisionFloatShaderOps = FALSE;
return S_OK;
}
case D3D11_FEATURE_FORMAT_SUPPORT:
{
D3D11_FEATURE_DATA_FORMAT_SUPPORT* data = (D3D11_FEATURE_DATA_FORMAT_SUPPORT*)out_feature_support_data;
if(feature_support_data_size != sizeof(*data))
return E_INVALIDARG;
return this->CheckFormatSupport(data->InFormat, &data->OutFormatSupport);
}
case D3D11_FEATURE_FORMAT_SUPPORT2:
{
D3D11_FEATURE_DATA_FORMAT_SUPPORT* data = (D3D11_FEATURE_DATA_FORMAT_SUPPORT*)out_feature_support_data;
if(feature_support_data_size != sizeof(*data))
return E_INVALIDARG;
data->OutFormatSupport = 0;
/* TODO: should this be S_OK? */
return E_INVALIDARG;
}
case D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS:
{
D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS* data = (D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS*)out_feature_support_data;
if(feature_support_data_size != sizeof(*data))
return E_INVALIDARG;
data->ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x = FALSE;
return S_OK;
}
default:
return E_INVALIDARG;
}
}
#endif
virtual HRESULT STDMETHODCALLTYPE CheckFormatSupport(
DXGI_FORMAT dxgi_format,
unsigned *out_format_support
)
{
SYNCHRONIZED;
/* TODO: MSAA, advanced features */
pipe_format format = dxgi_to_pipe_format[dxgi_format];
if(!format)
return E_INVALIDARG;
int support = format_support[format];
if(support < 0)
{
support = 0;
if(dxgi_format == DXGI_FORMAT_R8_UINT ||
dxgi_format == DXGI_FORMAT_R16_UINT ||
dxgi_format == DXGI_FORMAT_R32_UINT)
support |= D3D11_FORMAT_SUPPORT_IA_INDEX_BUFFER;
if(screen->is_format_supported(screen, format, PIPE_BUFFER, 0, PIPE_BIND_VERTEX_BUFFER))
support |= D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER;
if(screen->is_format_supported(screen, format, PIPE_BUFFER, 0, PIPE_BIND_STREAM_OUTPUT))
support |= D3D11_FORMAT_SUPPORT_SO_BUFFER;
if(screen->is_format_supported(screen, format, PIPE_TEXTURE_1D, 0, PIPE_BIND_SAMPLER_VIEW))
support |= D3D11_FORMAT_SUPPORT_TEXTURE1D;
if(screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW))
support |= D3D11_FORMAT_SUPPORT_TEXTURE2D;
if(screen->is_format_supported(screen, format, PIPE_TEXTURE_CUBE, 0, PIPE_BIND_SAMPLER_VIEW))
support |= D3D11_FORMAT_SUPPORT_TEXTURECUBE;
if(screen->is_format_supported(screen, format, PIPE_TEXTURE_3D, 0, PIPE_BIND_SAMPLER_VIEW))
support |= D3D11_FORMAT_SUPPORT_TEXTURE3D;
if(support & (D3D11_FORMAT_SUPPORT_TEXTURE1D | D3D11_FORMAT_SUPPORT_TEXTURE2D |
D3D11_FORMAT_SUPPORT_TEXTURE3D | D3D11_FORMAT_SUPPORT_TEXTURECUBE))
{
support |=
D3D11_FORMAT_SUPPORT_SHADER_LOAD |
D3D11_FORMAT_SUPPORT_SHADER_SAMPLE |
D3D11_FORMAT_SUPPORT_MIP |
D3D11_FORMAT_SUPPORT_MIP_AUTOGEN;
if(util_format_is_depth_or_stencil(format))
support |= D3D11_FORMAT_SUPPORT_SHADER_SAMPLE_COMPARISON;
}
if(screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET | PIPE_BIND_BLENDABLE))
support |= D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_RENDER_TARGET | D3D11_FORMAT_SUPPORT_BLENDABLE;
else
if(screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET))
support |= D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_RENDER_TARGET;
if(screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_DEPTH_STENCIL))
support |= D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_DEPTH_STENCIL;
if(screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_DISPLAY_TARGET))
support |= D3D11_FORMAT_SUPPORT_DISPLAY;
unsigned ms;
for(ms = 2; ms <= 8; ++ms)
{
if(screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, ms, PIPE_BIND_RENDER_TARGET))
{
support |= D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET | D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE;
break;
}
}
if(ms <= 8 && screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, ms, PIPE_BIND_SAMPLER_VIEW))
support |= D3D11_FORMAT_SUPPORT_MULTISAMPLE_LOAD;
format_support[format] = support;
}
*out_format_support = support;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CheckMultisampleQualityLevels(
DXGI_FORMAT format,
unsigned sample_count,
unsigned *pcount
)
{
SYNCHRONIZED;
if(sample_count == 1)
*pcount = 1;
else
*pcount = 0;
return S_OK;
}
template<typename T, typename U>
bool convert_blend_state(T& to, const U& from, unsigned BlendEnable, unsigned RenderTargetWriteMask)
{
if(unlikely(BlendEnable &&
(from.SrcBlend >= D3D11_BLEND_COUNT ||
from.SrcBlendAlpha >= D3D11_BLEND_COUNT ||
from.DestBlend >= D3D11_BLEND_COUNT ||
from.DestBlendAlpha >= D3D11_BLEND_COUNT ||
from.BlendOp >= 6 ||
from.BlendOp == 0 ||
from.BlendOpAlpha >= 6 ||
from.BlendOpAlpha == 0)))
return false;
to.blend_enable = BlendEnable;
if(BlendEnable)
{
to.rgb_func = from.BlendOp - 1;
to.alpha_func = from.BlendOpAlpha - 1;
to.rgb_src_factor = d3d11_to_pipe_blend[from.SrcBlend];
to.alpha_src_factor = d3d11_to_pipe_blend[from.SrcBlendAlpha];
to.rgb_dst_factor = d3d11_to_pipe_blend[from.DestBlend];
to.alpha_dst_factor = d3d11_to_pipe_blend[from.DestBlendAlpha];
}
to.colormask = RenderTargetWriteMask & 0xf;
return true;
}
#if API >= 11
virtual HRESULT STDMETHODCALLTYPE CreateBlendState(
const D3D11_BLEND_DESC *blend_state_desc,
ID3D11BlendState **out_blend_state
)
#else
virtual HRESULT STDMETHODCALLTYPE CreateBlendState1(
const D3D10_BLEND_DESC1 *blend_state_desc,
ID3D10BlendState1 **out_blend_state
)
#endif
{
SYNCHRONIZED;
pipe_blend_state state;
memset(&state, 0, sizeof(state));
state.alpha_to_coverage = !!blend_state_desc->AlphaToCoverageEnable;
state.independent_blend_enable = !!blend_state_desc->IndependentBlendEnable;
assert(PIPE_MAX_COLOR_BUFS >= 8);
const unsigned n = blend_state_desc->IndependentBlendEnable ? 8 : 1;
for(unsigned i = 0; i < n; ++i)
{
if(!convert_blend_state(
state.rt[i],
blend_state_desc->RenderTarget[i],
blend_state_desc->RenderTarget[i].BlendEnable,
blend_state_desc->RenderTarget[i].RenderTargetWriteMask))
return E_INVALIDARG;
}
if(!out_blend_state)
return S_FALSE;
void* object = immediate_pipe->create_blend_state(immediate_pipe, &state);
if(!object)
return E_FAIL;
*out_blend_state = new GalliumD3D11BlendState(this, object, *blend_state_desc);
return S_OK;
}
#if API < 11
virtual HRESULT STDMETHODCALLTYPE CreateBlendState(
const D3D10_BLEND_DESC *blend_state_desc,
ID3D10BlendState **out_blend_state
)
{
SYNCHRONIZED;
pipe_blend_state state;
memset(&state, 0, sizeof(state));
state.alpha_to_coverage = !!blend_state_desc->AlphaToCoverageEnable;
assert(PIPE_MAX_COLOR_BUFS >= 8);
for(unsigned i = 0; i < 8; ++i)
{
if(!convert_blend_state(
state.rt[i],
*blend_state_desc,
blend_state_desc->BlendEnable[i],
blend_state_desc->RenderTargetWriteMask[i]))
return E_INVALIDARG;
}
for(unsigned i = 1; i < 8; ++i)
{
if(memcmp(&state.rt[0], &state.rt[i], sizeof(state.rt[0])))
{
state.independent_blend_enable = TRUE;
break;
}
}
void* object = immediate_pipe->create_blend_state(immediate_pipe, &state);
if(!object)
return E_FAIL;
*out_blend_state = new GalliumD3D11BlendState(this, object, *blend_state_desc);
return S_OK;
}
#endif
virtual HRESULT STDMETHODCALLTYPE CreateDepthStencilState(
const D3D11_DEPTH_STENCIL_DESC *depth_stencil_state_desc,
ID3D11DepthStencilState **depth_stencil_state
)
{
SYNCHRONIZED;
pipe_depth_stencil_alpha_state state;
memset(&state, 0, sizeof(state));
state.depth.enabled = !!depth_stencil_state_desc->DepthEnable;
if(depth_stencil_state_desc->DepthEnable)
{
if(depth_stencil_state_desc->DepthFunc == 0 ||
depth_stencil_state_desc->DepthFunc >= 9)
return E_INVALIDARG;
state.depth.writemask = depth_stencil_state_desc->DepthWriteMask;
state.depth.func = depth_stencil_state_desc->DepthFunc - 1;
}
state.stencil[0].enabled = !!depth_stencil_state_desc->StencilEnable;
if(depth_stencil_state_desc->StencilEnable)
{
if(depth_stencil_state_desc->FrontFace.StencilPassOp >= D3D11_STENCIL_OP_COUNT ||
depth_stencil_state_desc->FrontFace.StencilFailOp >= D3D11_STENCIL_OP_COUNT ||
depth_stencil_state_desc->FrontFace.StencilDepthFailOp >= D3D11_STENCIL_OP_COUNT ||
depth_stencil_state_desc->BackFace.StencilPassOp >= D3D11_STENCIL_OP_COUNT ||
depth_stencil_state_desc->BackFace.StencilFailOp >= D3D11_STENCIL_OP_COUNT ||
depth_stencil_state_desc->BackFace.StencilDepthFailOp >= D3D11_STENCIL_OP_COUNT)
return E_INVALIDARG;
state.stencil[0].writemask = depth_stencil_state_desc->StencilWriteMask;
state.stencil[0].valuemask = depth_stencil_state_desc->StencilReadMask;
state.stencil[0].zpass_op = d3d11_to_pipe_stencil_op[depth_stencil_state_desc->FrontFace.StencilPassOp];
state.stencil[0].fail_op = d3d11_to_pipe_stencil_op[depth_stencil_state_desc->FrontFace.StencilFailOp];
state.stencil[0].zfail_op = d3d11_to_pipe_stencil_op[depth_stencil_state_desc->FrontFace.StencilDepthFailOp];
state.stencil[0].func = depth_stencil_state_desc->FrontFace.StencilFunc - 1;
state.stencil[1].enabled = !!depth_stencil_state_desc->StencilEnable;
state.stencil[1].writemask = depth_stencil_state_desc->StencilWriteMask;
state.stencil[1].valuemask = depth_stencil_state_desc->StencilReadMask;
state.stencil[1].zpass_op = d3d11_to_pipe_stencil_op[depth_stencil_state_desc->BackFace.StencilPassOp];
state.stencil[1].fail_op = d3d11_to_pipe_stencil_op[depth_stencil_state_desc->BackFace.StencilFailOp];
state.stencil[1].zfail_op = d3d11_to_pipe_stencil_op[depth_stencil_state_desc->BackFace.StencilDepthFailOp];
state.stencil[1].func = depth_stencil_state_desc->BackFace.StencilFunc - 1;
}
if(!depth_stencil_state)
return S_FALSE;
void* object = immediate_pipe->create_depth_stencil_alpha_state(immediate_pipe, &state);
if(!object)
return E_FAIL;
*depth_stencil_state = new GalliumD3D11DepthStencilState(this, object, *depth_stencil_state_desc);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreateRasterizerState(
const D3D11_RASTERIZER_DESC *rasterizer_desc,
ID3D11RasterizerState **out_rasterizer_state)
{
SYNCHRONIZED;
pipe_rasterizer_state state;
memset(&state, 0, sizeof(state));
state.gl_rasterization_rules = 1; /* D3D10/11 use GL rules */
state.fill_front = state.fill_back = (rasterizer_desc->FillMode == D3D11_FILL_WIREFRAME) ? PIPE_POLYGON_MODE_LINE : PIPE_POLYGON_MODE_FILL;
if(rasterizer_desc->CullMode == D3D11_CULL_FRONT)
state.cull_face = PIPE_FACE_FRONT;
else if(rasterizer_desc->CullMode == D3D11_CULL_BACK)
state.cull_face = PIPE_FACE_BACK;
else
state.cull_face = PIPE_FACE_NONE;
state.front_ccw = !!rasterizer_desc->FrontCounterClockwise;
state.offset_tri = state.offset_line = state.offset_point = rasterizer_desc->SlopeScaledDepthBias || rasterizer_desc->DepthBias;
state.offset_scale = rasterizer_desc->SlopeScaledDepthBias;
state.offset_units = rasterizer_desc->DepthBias;
state.offset_clamp = rasterizer_desc->DepthBiasClamp;
state.depth_clip = rasterizer_desc->DepthClipEnable;
state.scissor = !!rasterizer_desc->ScissorEnable;
state.multisample = !!rasterizer_desc->MultisampleEnable;
state.line_smooth = !!rasterizer_desc->AntialiasedLineEnable;
state.flatshade_first = 1;
state.line_width = 1.0f;
state.point_size = 1.0f;
/* TODO: is this correct? */
state.point_quad_rasterization = 1;
if(!out_rasterizer_state)
return S_FALSE;
void* object = immediate_pipe->create_rasterizer_state(immediate_pipe, &state);
if(!object)
return E_FAIL;
*out_rasterizer_state = new GalliumD3D11RasterizerState(this, object, *rasterizer_desc);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreateSamplerState(
const D3D11_SAMPLER_DESC *sampler_desc,
ID3D11SamplerState **out_sampler_state)
{
SYNCHRONIZED;
pipe_sampler_state state;
memset(&state, 0, sizeof(state));
state.normalized_coords = 1;
state.min_mip_filter = (sampler_desc->Filter & 1);
state.mag_img_filter = ((sampler_desc->Filter >> 2) & 1);
state.min_img_filter = ((sampler_desc->Filter >> 4) & 1);
if(sampler_desc->Filter & 0x40)
state.max_anisotropy = sampler_desc->MaxAnisotropy;
if(sampler_desc->Filter & 0x80)
{
state.compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE;
state.compare_func = sampler_desc->ComparisonFunc - 1;
}
state.wrap_s = d3d11_to_pipe_wrap[sampler_desc->AddressU];
state.wrap_t = d3d11_to_pipe_wrap[sampler_desc->AddressV];
state.wrap_r = d3d11_to_pipe_wrap[sampler_desc->AddressW];
state.lod_bias = sampler_desc->MipLODBias;
memcpy(state.border_color.f, sampler_desc->BorderColor, sizeof(state.border_color));
state.min_lod = sampler_desc->MinLOD;
state.max_lod = sampler_desc->MaxLOD;
if(!out_sampler_state)
return S_FALSE;
void* object = immediate_pipe->create_sampler_state(immediate_pipe, &state);
if(!object)
return E_FAIL;
*out_sampler_state = new GalliumD3D11SamplerState(this, object, *sampler_desc);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreateInputLayout(
const D3D11_INPUT_ELEMENT_DESC *input_element_descs,
unsigned count,
const void *shader_bytecode_with_input_signature,
SIZE_T bytecode_length,
ID3D11InputLayout **out_input_layout)
{
SYNCHRONIZED;
if(count > D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT)
return E_INVALIDARG;
assert(D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT <= PIPE_MAX_ATTRIBS);
// putting semantics matching in the core API seems to be a (minor) design mistake
struct dxbc_chunk_signature* sig = dxbc_find_signature(shader_bytecode_with_input_signature, bytecode_length, DXBC_FIND_INPUT_SIGNATURE);
D3D11_SIGNATURE_PARAMETER_DESC* params;
unsigned num_params = dxbc_parse_signature(sig, &params);
typedef std::unordered_map<std::pair<c_string, unsigned>, unsigned> semantic_to_idx_map_t;
semantic_to_idx_map_t semantic_to_idx_map;
for(unsigned i = 0; i < count; ++i)
semantic_to_idx_map[std::make_pair(c_string(input_element_descs[i].SemanticName), input_element_descs[i].SemanticIndex)] = i;
struct pipe_vertex_element elements[D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT];
enum pipe_format formats[D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT];
unsigned offsets[D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT];
offsets[0] = 0;
for(unsigned i = 0; i < count; ++i)
{
formats[i] = dxgi_to_pipe_format[input_element_descs[i].Format];
if(likely(input_element_descs[i].AlignedByteOffset != D3D11_APPEND_ALIGNED_ELEMENT))
{
offsets[i] = input_element_descs[i].AlignedByteOffset;
}
else if(i > 0)
{
unsigned align_mask = util_format_description(formats[i])->channel[0].size;
if(align_mask & 7) // e.g. R10G10B10A2
align_mask = 32;
align_mask = (align_mask / 8) - 1;
offsets[i] = (offsets[i - 1] + util_format_get_blocksize(formats[i - 1]) + align_mask) & ~align_mask;
}
}
// TODO: check for & report errors (e.g. ambiguous layouts, unmatched semantics)
unsigned num_params_to_use = 0;
for(unsigned i = 0; i < num_params && num_params_to_use < D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT; ++i)
{
if(!strcasecmp(params[i].SemanticName, "SV_INSTANCEID") ||
!strcasecmp(params[i].SemanticName, "SV_VERTEXID"))
continue;
const unsigned n = num_params_to_use++;
semantic_to_idx_map_t::iterator iter = semantic_to_idx_map.find(std::make_pair(c_string(params[i].SemanticName), params[i].SemanticIndex));
if(iter != semantic_to_idx_map.end())
{
unsigned idx = iter->second;
elements[n].src_format = formats[idx];
elements[n].src_offset = offsets[idx];
elements[n].vertex_buffer_index = input_element_descs[idx].InputSlot;
elements[n].instance_divisor = input_element_descs[idx].InstanceDataStepRate;
if (input_element_descs[idx].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA)
if (elements[n].instance_divisor == 0)
elements[n].instance_divisor = ~0; // XXX: can't specify 'never' to gallium
}
else
{
// XXX: undefined input, is this valid or should we return an error ?
elements[n].src_format = PIPE_FORMAT_NONE;
elements[n].src_offset = 0;
elements[n].vertex_buffer_index = 0;
elements[n].instance_divisor = 0;
}
}
free(params);
if(!out_input_layout)
return S_FALSE;
void* object = immediate_pipe->create_vertex_elements_state(immediate_pipe, num_params_to_use, elements);
if(!object)
return E_FAIL;
*out_input_layout = new GalliumD3D11InputLayout(this, object);
return S_OK;
}
static unsigned d3d11_to_pipe_bind_flags(unsigned bind_flags)
{
unsigned bind = 0;
if(bind_flags & D3D11_BIND_VERTEX_BUFFER)
bind |= PIPE_BIND_VERTEX_BUFFER;
if(bind_flags & D3D11_BIND_INDEX_BUFFER)
bind |= PIPE_BIND_INDEX_BUFFER;
if(bind_flags & D3D11_BIND_CONSTANT_BUFFER)
bind |= PIPE_BIND_CONSTANT_BUFFER;
if(bind_flags & D3D11_BIND_SHADER_RESOURCE)
bind |= PIPE_BIND_SAMPLER_VIEW;
if(bind_flags & D3D11_BIND_STREAM_OUTPUT)
bind |= PIPE_BIND_STREAM_OUTPUT;
if(bind_flags & D3D11_BIND_RENDER_TARGET)
bind |= PIPE_BIND_RENDER_TARGET;
if(bind_flags & D3D11_BIND_DEPTH_STENCIL)
bind |= PIPE_BIND_DEPTH_STENCIL;
return bind;
}
inline HRESULT create_resource(
pipe_texture_target target,
unsigned width,
unsigned height,
unsigned depth,
unsigned mip_levels,
unsigned array_size,
DXGI_FORMAT format,
const DXGI_SAMPLE_DESC* SampleDesc,
D3D11_USAGE usage,
unsigned bind_flags,
unsigned c_p_u_access_flags,
unsigned misc_flags,
const D3D11_SUBRESOURCE_DATA *initial_data,
DXGI_USAGE dxgi_usage,
struct pipe_resource** ppresource
)
{
if(invalid(format >= DXGI_FORMAT_COUNT))
return E_INVALIDARG;
if(misc_flags & D3D11_RESOURCE_MISC_TEXTURECUBE)
{
if(target != PIPE_TEXTURE_2D)
return E_INVALIDARG;
target = PIPE_TEXTURE_CUBE;
if(array_size % 6)
return E_INVALIDARG;
}
else if(array_size > 1)
{
switch (target) {
case PIPE_TEXTURE_1D: target = PIPE_TEXTURE_1D_ARRAY; break;
case PIPE_TEXTURE_2D: target = PIPE_TEXTURE_2D_ARRAY; break;
default:
return E_INVALIDARG;
}
}
/* TODO: msaa */
struct pipe_resource templat;
memset(&templat, 0, sizeof(templat));
templat.target = target;
templat.width0 = width;
templat.height0 = height;
templat.depth0 = depth;
templat.array_size = array_size;
if(mip_levels)
templat.last_level = mip_levels - 1;
else
templat.last_level = MAX2(MAX2(util_logbase2(templat.width0), util_logbase2(templat.height0)), util_logbase2(templat.depth0));
templat.format = dxgi_to_pipe_format[format];
if(bind_flags & D3D11_BIND_DEPTH_STENCIL) {
// colour formats are not depth-renderable, but depth/stencil-formats may be colour-renderable
switch(format)
{
case DXGI_FORMAT_R32_TYPELESS: templat.format = PIPE_FORMAT_Z32_FLOAT; break;
case DXGI_FORMAT_R16_TYPELESS: templat.format = PIPE_FORMAT_Z16_UNORM; break;
default:
break;
}
}
templat.bind = d3d11_to_pipe_bind_flags(bind_flags);
if(c_p_u_access_flags & D3D11_CPU_ACCESS_READ)
templat.bind |= PIPE_BIND_TRANSFER_READ;
if(c_p_u_access_flags & D3D11_CPU_ACCESS_WRITE)
templat.bind |= PIPE_BIND_TRANSFER_WRITE;
if(misc_flags & D3D11_RESOURCE_MISC_SHARED)
templat.bind |= PIPE_BIND_SHARED;
if(misc_flags & D3D11_RESOURCE_MISC_GDI_COMPATIBLE)
templat.bind |= PIPE_BIND_TRANSFER_READ | PIPE_BIND_TRANSFER_WRITE;
if(dxgi_usage & DXGI_USAGE_BACK_BUFFER)
templat.bind |= PIPE_BIND_DISPLAY_TARGET;
templat.usage = d3d11_to_pipe_usage[usage];
if(invalid(!templat.format))
return E_NOTIMPL;
if(!ppresource)
return S_FALSE;
struct pipe_resource* resource = screen->resource_create(screen, &templat);
if(!resource)
return E_FAIL;
if(initial_data)
{
for(unsigned slice = 0; slice < array_size; ++slice)
{
for(unsigned level = 0; level <= templat.last_level; ++level)
{
struct pipe_box box;
box.x = box.y = 0;
box.z = slice;
box.width = u_minify(width, level);
box.height = u_minify(height, level);
box.depth = u_minify(depth, level);
immediate_pipe->transfer_inline_write(immediate_pipe, resource, level, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | PIPE_TRANSFER_UNSYNCHRONIZED, &box, initial_data->pSysMem, initial_data->SysMemPitch, initial_data->SysMemSlicePitch);
++initial_data;
}
}
}
*ppresource = resource;
return S_OK;
}
static unsigned d3d_to_dxgi_usage(unsigned bind, unsigned misc)
{
unsigned dxgi_usage = 0;
if(bind |= D3D11_BIND_RENDER_TARGET)
dxgi_usage |= DXGI_USAGE_RENDER_TARGET_OUTPUT;
if(bind & D3D11_BIND_SHADER_RESOURCE)
dxgi_usage |= DXGI_USAGE_SHADER_INPUT;
#if API >= 11
if(bind & D3D11_BIND_UNORDERED_ACCESS)
dxgi_usage |= DXGI_USAGE_UNORDERED_ACCESS;
#endif
if(misc & D3D11_RESOURCE_MISC_SHARED)
dxgi_usage |= DXGI_USAGE_SHARED;
return dxgi_usage;
}
virtual HRESULT STDMETHODCALLTYPE CreateTexture1D(
const D3D11_TEXTURE1D_DESC *desc,
const D3D11_SUBRESOURCE_DATA *initial_data,
ID3D11Texture1D **out_texture1d)
{
SYNCHRONIZED;
struct pipe_resource* resource;
DXGI_USAGE dxgi_usage = d3d_to_dxgi_usage(desc->BindFlags, desc->MiscFlags);
HRESULT hr = create_resource(PIPE_TEXTURE_1D, desc->Width, 1, 1, desc->MipLevels, desc->ArraySize, desc->Format, 0, desc->Usage, desc->BindFlags, desc->CPUAccessFlags, desc->MiscFlags, initial_data, dxgi_usage, out_texture1d ? &resource : 0);
if(hr != S_OK)
return hr;
D3D11_TEXTURE1D_DESC cdesc = *desc;
cdesc.MipLevels = resource->last_level + 1;
*out_texture1d = new GalliumD3D11Texture1D(this, resource, cdesc, dxgi_usage);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreateTexture2D(
const D3D11_TEXTURE2D_DESC *desc,
const D3D11_SUBRESOURCE_DATA *initial_data,
ID3D11Texture2D **out_texture2d)
{
SYNCHRONIZED;
struct pipe_resource* resource;
DXGI_USAGE dxgi_usage = d3d_to_dxgi_usage(desc->BindFlags, desc->MiscFlags);
HRESULT hr = create_resource(PIPE_TEXTURE_2D, desc->Width, desc->Height, 1, desc->MipLevels, desc->ArraySize, desc->Format, &desc->SampleDesc, desc->Usage, desc->BindFlags, desc->CPUAccessFlags, desc->MiscFlags, initial_data, dxgi_usage, out_texture2d ? &resource : 0);
if(hr != S_OK)
return hr;
D3D11_TEXTURE2D_DESC cdesc = *desc;
cdesc.MipLevels = resource->last_level + 1;
if(cdesc.MipLevels == 1 && cdesc.ArraySize == 1)
*out_texture2d = new GalliumD3D11Surface(this, resource, cdesc, dxgi_usage);
else
*out_texture2d = new GalliumD3D11Texture2D(this, resource, cdesc, dxgi_usage);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreateTexture3D(
const D3D11_TEXTURE3D_DESC *desc,
const D3D11_SUBRESOURCE_DATA *initial_data,
ID3D11Texture3D **out_texture3d)
{
SYNCHRONIZED;
struct pipe_resource* resource;
DXGI_USAGE dxgi_usage = d3d_to_dxgi_usage(desc->BindFlags, desc->MiscFlags);
HRESULT hr = create_resource(PIPE_TEXTURE_3D, desc->Width, desc->Height, desc->Depth, desc->MipLevels, 1, desc->Format, 0, desc->Usage, desc->BindFlags, desc->CPUAccessFlags, desc->MiscFlags, initial_data, dxgi_usage, out_texture3d ? &resource : 0);
if(hr != S_OK)
return hr;
D3D11_TEXTURE3D_DESC cdesc = *desc;
cdesc.MipLevels = resource->last_level + 1;
*out_texture3d = new GalliumD3D11Texture3D(this, resource, cdesc, dxgi_usage);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreateBuffer(
const D3D11_BUFFER_DESC *desc,
const D3D11_SUBRESOURCE_DATA *initial_data,
ID3D11Buffer **out_buffer)
{
SYNCHRONIZED;
struct pipe_resource* resource;
DXGI_USAGE dxgi_usage = d3d_to_dxgi_usage(desc->BindFlags, desc->MiscFlags);
HRESULT hr = create_resource(PIPE_BUFFER, desc->ByteWidth, 1, 1, 1, 1, DXGI_FORMAT_R8_UNORM, 0, desc->Usage, desc->BindFlags, desc->CPUAccessFlags, desc->MiscFlags, initial_data, dxgi_usage, out_buffer ? &resource : 0);
if(hr != S_OK)
return hr;
*out_buffer = new GalliumD3D11Buffer(this, resource, *desc, dxgi_usage);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE OpenGalliumResource(
struct pipe_resource* resource,
IUnknown** dxgi_resource)
{
SYNCHRONIZED;
/* TODO: maybe support others */
assert(resource->target == PIPE_TEXTURE_2D);
*dxgi_resource = 0;
D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.Width = resource->width0;
desc.Height = resource->height0;
init_pipe_to_dxgi_format();
desc.Format = pipe_to_dxgi_format[resource->format];
desc.SampleDesc.Count = resource->nr_samples;
desc.SampleDesc.Quality = 0;
desc.ArraySize = 1;
desc.MipLevels = resource->last_level + 1;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
if(resource->bind & PIPE_BIND_RENDER_TARGET)
desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
if(resource->bind & PIPE_BIND_DEPTH_STENCIL)
desc.BindFlags |= D3D11_BIND_DEPTH_STENCIL;
if(resource->bind & PIPE_BIND_SAMPLER_VIEW)
desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
if(resource->bind & PIPE_BIND_SHARED)
desc.MiscFlags |= D3D11_RESOURCE_MISC_SHARED;
DXGI_USAGE dxgi_usage = d3d_to_dxgi_usage(desc.BindFlags, desc.MiscFlags);
if(desc.MipLevels == 1 && desc.ArraySize == 1)
*dxgi_resource = (ID3D11Texture2D*)new GalliumD3D11Surface(this, resource, desc, dxgi_usage);
else
*dxgi_resource = (ID3D11Texture2D*)new GalliumD3D11Texture2D(this, resource, desc, dxgi_usage);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreateSurface(
const DXGI_SURFACE_DESC *dxgi_desc,
unsigned count,
DXGI_USAGE usage,
const DXGI_SHARED_RESOURCE *shared_resource,
IDXGISurface **out_surface)
{
SYNCHRONIZED;
D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
struct pipe_resource* resource;
desc.Width = dxgi_desc->Width;
desc.Height = dxgi_desc->Height;
desc.Format = dxgi_desc->Format;
desc.SampleDesc = dxgi_desc->SampleDesc;
desc.ArraySize = count;
desc.MipLevels = 1;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
if(usage & DXGI_USAGE_RENDER_TARGET_OUTPUT)
desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
if(usage & DXGI_USAGE_SHADER_INPUT)
desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
#if API >= 11
if(usage & DXGI_USAGE_UNORDERED_ACCESS)
desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
#endif
if(usage & DXGI_USAGE_SHARED)
desc.MiscFlags |= D3D11_RESOURCE_MISC_SHARED;
HRESULT hr = create_resource(PIPE_TEXTURE_2D, dxgi_desc->Width, dxgi_desc->Height, 1, 1, count, dxgi_desc->Format, &dxgi_desc->SampleDesc, D3D11_USAGE_DEFAULT, desc.BindFlags, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE, desc.MiscFlags, 0, usage, &resource);
if(hr != S_OK)
return hr;
*out_surface = new GalliumD3D11Surface(this, resource, desc, usage);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreateShaderResourceView(
ID3D11Resource *iresource,
const D3D11_SHADER_RESOURCE_VIEW_DESC *desc,
ID3D11ShaderResourceView **out_srv)
{
#if API >= 11
D3D11_SHADER_RESOURCE_VIEW_DESC def_desc;
#else
if(desc->ViewDimension == D3D10_1_SRV_DIMENSION_TEXTURECUBEARRAY)
return E_INVALIDARG;
D3D10_SHADER_RESOURCE_VIEW_DESC1 desc1;
memset(&desc1, 0, sizeof(desc1));
memcpy(&desc1, desc, sizeof(*desc));
return CreateShaderResourceView1(iresource, &desc1, (ID3D10ShaderResourceView1**)out_srv);
}
virtual HRESULT STDMETHODCALLTYPE CreateShaderResourceView1(
ID3D11Resource *iresource,
const D3D10_SHADER_RESOURCE_VIEW_DESC1 *desc,
ID3D10ShaderResourceView1 **out_srv)
{
D3D10_SHADER_RESOURCE_VIEW_DESC1 def_desc;
#endif
SYNCHRONIZED;
const struct pipe_resource* resource = ((GalliumD3D11Resource<>*)iresource)->resource;
if(!desc)
{
init_pipe_to_dxgi_format();
memset(&def_desc, 0, sizeof(def_desc));
def_desc.Format = pipe_to_dxgi_format[resource->format];
switch(resource->target)
{
case PIPE_BUFFER:
def_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
def_desc.Buffer.ElementWidth = resource->width0;
break;
case PIPE_TEXTURE_1D:
def_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
def_desc.Texture1D.MipLevels = resource->last_level + 1;
break;
case PIPE_TEXTURE_1D_ARRAY:
def_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
def_desc.Texture1DArray.MipLevels = resource->last_level + 1;
def_desc.Texture1DArray.ArraySize = resource->array_size;
break;
case PIPE_TEXTURE_2D:
case PIPE_TEXTURE_RECT:
def_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
def_desc.Texture2D.MipLevels = resource->last_level + 1;
break;
case PIPE_TEXTURE_2D_ARRAY:
def_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
def_desc.Texture2DArray.MipLevels = resource->last_level + 1;
def_desc.Texture2DArray.ArraySize = resource->array_size;
break;
case PIPE_TEXTURE_3D:
def_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
def_desc.Texture3D.MipLevels = resource->last_level + 1;
break;
case PIPE_TEXTURE_CUBE:
if(resource->array_size > 6)
{
def_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
def_desc.TextureCubeArray.NumCubes = resource->array_size / 6;
}
else
{
def_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
}
def_desc.TextureCube.MipLevels = resource->last_level + 1;
break;
default:
return E_INVALIDARG;
}
desc = &def_desc;
}
struct pipe_sampler_view templat;
memset(&templat, 0, sizeof(templat));
if(invalid(format >= DXGI_FORMAT_COUNT))
return E_INVALIDARG;
templat.format = (desc->Format == DXGI_FORMAT_UNKNOWN) ? resource->format : dxgi_to_pipe_format[desc->Format];
if(!templat.format)
return E_NOTIMPL;
templat.swizzle_r = PIPE_SWIZZLE_RED;
templat.swizzle_g = PIPE_SWIZZLE_GREEN;
templat.swizzle_b = PIPE_SWIZZLE_BLUE;
templat.swizzle_a = PIPE_SWIZZLE_ALPHA;
templat.texture = ((GalliumD3D11Resource<>*)iresource)->resource;
switch(desc->ViewDimension)
{
case D3D11_SRV_DIMENSION_TEXTURE1DARRAY:
case D3D11_SRV_DIMENSION_TEXTURE2DARRAY:
case D3D11_SRV_DIMENSION_TEXTURECUBEARRAY:
templat.u.tex.first_layer = desc->Texture1DArray.FirstArraySlice;
templat.u.tex.last_layer = desc->Texture1DArray.FirstArraySlice + desc->Texture1DArray.ArraySize - 1;
if (desc->ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) {
templat.u.tex.first_layer *= 6;
templat.u.tex.last_layer *= 6;
}
// fall through
case D3D11_SRV_DIMENSION_TEXTURE1D:
case D3D11_SRV_DIMENSION_TEXTURE2D:
case D3D11_SRV_DIMENSION_TEXTURE3D:
case D3D11_SRV_DIMENSION_TEXTURECUBE:
// yes, this works for all of these types
templat.u.tex.first_level = desc->Texture1D.MostDetailedMip;
if(desc->Texture1D.MipLevels == (unsigned)-1)
templat.u.tex.last_level = templat.texture->last_level;
else
templat.u.tex.last_level = templat.u.tex.first_level + desc->Texture1D.MipLevels - 1;
assert(templat.u.tex.last_level >= templat.u.tex.first_level);
break;
case D3D11_SRV_DIMENSION_BUFFER:
templat.u.buf.first_element = desc->Buffer.ElementOffset;
templat.u.buf.last_element = desc->Buffer.ElementOffset + desc->Buffer.ElementWidth - 1;
break;
case D3D11_SRV_DIMENSION_TEXTURE2DMS:
case D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY:
return E_NOTIMPL;
default:
return E_INVALIDARG;
}
if(!out_srv)
return S_FALSE;
struct pipe_sampler_view* view = immediate_pipe->create_sampler_view(immediate_pipe, templat.texture, &templat);
if(!view)
return E_FAIL;
*out_srv = new GalliumD3D11ShaderResourceView(this, (GalliumD3D11Resource<>*)iresource, view, *desc);
return S_OK;
}
#if API >= 11
virtual HRESULT STDMETHODCALLTYPE CreateUnorderedAccessView(
ID3D11Resource *resource,
const D3D11_UNORDERED_ACCESS_VIEW_DESC *desc,
ID3D11UnorderedAccessView **out_uav)
{
SYNCHRONIZED;
return E_NOTIMPL;
// remember to return S_FALSE and not crash if out_u_a_view == 0 and parameters are valid
}
#endif
virtual HRESULT STDMETHODCALLTYPE CreateRenderTargetView(
ID3D11Resource *iresource,
const D3D11_RENDER_TARGET_VIEW_DESC *desc,
ID3D11RenderTargetView **out_rtv)
{
SYNCHRONIZED;
const struct pipe_resource* resource = ((GalliumD3D11Resource<>*)iresource)->resource;
D3D11_RENDER_TARGET_VIEW_DESC def_desc;
if(!desc)
{
init_pipe_to_dxgi_format();
memset(&def_desc, 0, sizeof(def_desc));
def_desc.Format = pipe_to_dxgi_format[resource->format];
switch(resource->target)
{
case PIPE_BUFFER:
def_desc.ViewDimension = D3D11_RTV_DIMENSION_BUFFER;
def_desc.Buffer.ElementWidth = resource->width0;
break;
case PIPE_TEXTURE_1D:
def_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D;
break;
case PIPE_TEXTURE_1D_ARRAY:
def_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1DARRAY;
def_desc.Texture1DArray.ArraySize = resource->array_size;
break;
case PIPE_TEXTURE_2D:
case PIPE_TEXTURE_RECT:
def_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
break;
case PIPE_TEXTURE_2D_ARRAY:
def_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
def_desc.Texture2DArray.ArraySize = resource->array_size;
break;
case PIPE_TEXTURE_3D:
def_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
def_desc.Texture3D.WSize = resource->depth0;
break;
case PIPE_TEXTURE_CUBE:
def_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
def_desc.Texture2DArray.ArraySize = 6;
break;
default:
return E_INVALIDARG;
}
desc = &def_desc;
}
struct pipe_surface templat;
memset(&templat, 0, sizeof(templat));
if(invalid(desc->format >= DXGI_FORMAT_COUNT))
return E_INVALIDARG;
templat.format = (desc->Format == DXGI_FORMAT_UNKNOWN) ? resource->format : dxgi_to_pipe_format[desc->Format];
if(!templat.format)
return E_NOTIMPL;
templat.usage = PIPE_BIND_RENDER_TARGET;
templat.texture = ((GalliumD3D11Resource<>*)iresource)->resource;
switch(desc->ViewDimension)
{
case D3D11_RTV_DIMENSION_TEXTURE1D:
case D3D11_RTV_DIMENSION_TEXTURE2D:
templat.u.tex.level = desc->Texture1D.MipSlice;
break;
case D3D11_RTV_DIMENSION_TEXTURE3D:
templat.u.tex.level = desc->Texture3D.MipSlice;
templat.u.tex.first_layer = desc->Texture3D.FirstWSlice;
templat.u.tex.last_layer = desc->Texture3D.FirstWSlice + desc->Texture3D.WSize - 1;
break;
case D3D11_RTV_DIMENSION_TEXTURE1DARRAY:
case D3D11_RTV_DIMENSION_TEXTURE2DARRAY:
templat.u.tex.level = desc->Texture1DArray.MipSlice;
templat.u.tex.first_layer = desc->Texture1DArray.FirstArraySlice;
templat.u.tex.last_layer = desc->Texture1DArray.FirstArraySlice + desc->Texture1DArray.ArraySize - 1;
break;
case D3D11_RTV_DIMENSION_BUFFER:
templat.u.buf.first_element = desc->Buffer.ElementOffset;
templat.u.buf.last_element = desc->Buffer.ElementOffset + desc->Buffer.ElementWidth - 1;
break;
case D3D11_RTV_DIMENSION_TEXTURE2DMS:
case D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY:
return E_NOTIMPL;
default:
return E_INVALIDARG;
}
if(!out_rtv)
return S_FALSE;
struct pipe_surface* surface = immediate_pipe->create_surface(immediate_pipe, templat.texture, &templat);
if(!surface)
return E_FAIL;
*out_rtv = new GalliumD3D11RenderTargetView(this, (GalliumD3D11Resource<>*)iresource, surface, *desc);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreateDepthStencilView(
ID3D11Resource *iresource,
const D3D11_DEPTH_STENCIL_VIEW_DESC *desc,
ID3D11DepthStencilView **out_depth_stencil_view)
{
SYNCHRONIZED;
const struct pipe_resource* resource = ((GalliumD3D11Resource<>*)iresource)->resource;
D3D11_DEPTH_STENCIL_VIEW_DESC def_desc;
if(!desc)
{
init_pipe_to_dxgi_format();
memset(&def_desc, 0, sizeof(def_desc));
def_desc.Format = pipe_to_dxgi_format[resource->format];
switch(resource->target)
{
case PIPE_TEXTURE_1D:
def_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1D;
break;
case PIPE_TEXTURE_1D_ARRAY:
def_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE1DARRAY;
def_desc.Texture1DArray.ArraySize = resource->array_size;
break;
case PIPE_TEXTURE_2D:
case PIPE_TEXTURE_RECT:
def_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
break;
case PIPE_TEXTURE_2D_ARRAY:
def_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
def_desc.Texture2DArray.ArraySize = resource->array_size;
break;
case PIPE_TEXTURE_CUBE:
def_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
def_desc.Texture2DArray.ArraySize = 6;
break;
default:
return E_INVALIDARG;
}
desc = &def_desc;
}
struct pipe_surface templat;
memset(&templat, 0, sizeof(templat));
if(invalid(desc->format >= DXGI_FORMAT_COUNT))
return E_INVALIDARG;
templat.format = (desc->Format == DXGI_FORMAT_UNKNOWN) ? resource->format : dxgi_to_pipe_format[desc->Format];
if(!templat.format)
return E_NOTIMPL;
templat.usage = PIPE_BIND_DEPTH_STENCIL;
templat.texture = ((GalliumD3D11Resource<>*)iresource)->resource;
switch(desc->ViewDimension)
{
case D3D11_DSV_DIMENSION_TEXTURE1D:
case D3D11_DSV_DIMENSION_TEXTURE2D:
templat.u.tex.level = desc->Texture1D.MipSlice;
break;
case D3D11_DSV_DIMENSION_TEXTURE1DARRAY:
case D3D11_DSV_DIMENSION_TEXTURE2DARRAY:
templat.u.tex.level = desc->Texture1DArray.MipSlice;
templat.u.tex.first_layer = desc->Texture1DArray.FirstArraySlice;
templat.u.tex.last_layer = desc->Texture1DArray.FirstArraySlice + desc->Texture1DArray.ArraySize - 1;
break;
case D3D11_DSV_DIMENSION_TEXTURE2DMS:
case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY:
return E_NOTIMPL;
default:
return E_INVALIDARG;
}
if(!out_depth_stencil_view)
return S_FALSE;
struct pipe_surface* surface = immediate_pipe->create_surface(immediate_pipe, templat.texture, &templat);
if(!surface)
return E_FAIL;
*out_depth_stencil_view = new GalliumD3D11DepthStencilView(this, (GalliumD3D11Resource<>*)iresource, surface, *desc);
return S_OK;
}
#define D3D1X_SHVER_GEOMETRY_SHADER 2 /* D3D11_SHVER_GEOMETRY_SHADER */
GalliumD3D11Shader<>* create_stage_shader(unsigned type, const void* shader_bytecode, SIZE_T bytecode_length
#if API >= 11
, ID3D11ClassLinkage *class_linkage
#endif
, struct pipe_stream_output_info* so_info)
{
bool dump = debug_get_option_dump_shaders();
std::auto_ptr<sm4_program> sm4(0);
dxbc_chunk_header* sm4_chunk = dxbc_find_shader_bytecode(shader_bytecode, bytecode_length);
if(!sm4_chunk)
{
if(so_info)
sm4.reset(new sm4_program());
}
else
{
sm4.reset(sm4_parse(sm4_chunk + 1, bswap_le32(sm4_chunk->size)));
// check if this is a dummy GS, in which case we only need a place to store the signature
if(sm4.get() && so_info && sm4->version.type != D3D1X_SHVER_GEOMETRY_SHADER)
sm4.reset(new sm4_program());
}
if(!sm4.get())
return 0;
if(dump)
sm4->dump();
struct dxbc_chunk_signature* sig;
sig = dxbc_find_signature(shader_bytecode, bytecode_length, DXBC_FIND_INPUT_SIGNATURE);
if(sig)
sm4->num_params_in = dxbc_parse_signature(sig, &sm4->params_in);
sig = dxbc_find_signature(shader_bytecode, bytecode_length, DXBC_FIND_OUTPUT_SIGNATURE);
if(sig)
sm4->num_params_out = dxbc_parse_signature(sig, &sm4->params_out);
sig = dxbc_find_signature(shader_bytecode, bytecode_length, DXBC_FIND_PATCH_SIGNATURE);
if(sig)
sm4->num_params_patch = dxbc_parse_signature(sig, &sm4->params_patch);
struct pipe_shader_state tgsi_shader;
memset(&tgsi_shader, 0, sizeof(tgsi_shader));
if(so_info)
memcpy(&tgsi_shader.stream_output, so_info, sizeof(tgsi_shader.stream_output));
if(so_info && sm4->version.type != D3D1X_SHVER_GEOMETRY_SHADER)
tgsi_shader.tokens = (const tgsi_token*)sm4_to_tgsi_linkage_only(*sm4);
else
tgsi_shader.tokens = (const tgsi_token*)sm4_to_tgsi(*sm4);
if(!tgsi_shader.tokens)
return 0;
if(dump)
tgsi_dump(tgsi_shader.tokens, 0);
void* shader_cso;
GalliumD3D11Shader<>* shader;
switch(type)
{
case PIPE_SHADER_VERTEX:
shader_cso = immediate_pipe->create_vs_state(immediate_pipe, &tgsi_shader);
shader = (GalliumD3D11Shader<>*)new GalliumD3D11VertexShader(this, shader_cso);
break;
case PIPE_SHADER_FRAGMENT:
shader_cso = immediate_pipe->create_fs_state(immediate_pipe, &tgsi_shader);
shader = (GalliumD3D11Shader<>*)new GalliumD3D11PixelShader(this, shader_cso);
break;
case PIPE_SHADER_GEOMETRY:
shader_cso = immediate_pipe->create_gs_state(immediate_pipe, &tgsi_shader);
shader = (GalliumD3D11Shader<>*)new GalliumD3D11GeometryShader(this, shader_cso);
break;
default:
shader_cso = 0;
shader = 0;
break;
}
free((void*)tgsi_shader.tokens);
return shader;
}
#if API >= 11
#define CREATE_SHADER_ARGS \
const void *shader_bytecode, \
SIZE_T bytecode_length, \
ID3D11ClassLinkage *class_linkage
#define PASS_SHADER_ARGS shader_bytecode, bytecode_length, class_linkage
#else
#define CREATE_SHADER_ARGS \
const void *shader_bytecode, \
SIZE_T bytecode_length
#define PASS_SHADER_ARGS shader_bytecode, bytecode_length
#endif
#define IMPLEMENT_CREATE_SHADER(Stage, GALLIUM) \
virtual HRESULT STDMETHODCALLTYPE Create##Stage##Shader( \
CREATE_SHADER_ARGS, \
ID3D11##Stage##Shader **out_shader) \
{ \
SYNCHRONIZED; \
GalliumD3D11##Stage##Shader* shader = (GalliumD3D11##Stage##Shader*)create_stage_shader(PIPE_SHADER_##GALLIUM, PASS_SHADER_ARGS, NULL); \
if(!shader) \
return E_FAIL; \
if(out_shader) \
{ \
*out_shader = shader; \
return S_OK; \
} \
else \
{ \
shader->Release(); \
return S_FALSE; \
} \
}
#define IMPLEMENT_NOTIMPL_CREATE_SHADER(Stage) \
virtual HRESULT STDMETHODCALLTYPE Create##Stage##Shader( \
CREATE_SHADER_ARGS, \
ID3D11##Stage##Shader **out_shader) \
{ \
return E_NOTIMPL; \
}
IMPLEMENT_CREATE_SHADER(Vertex, VERTEX)
IMPLEMENT_CREATE_SHADER(Pixel, FRAGMENT)
IMPLEMENT_CREATE_SHADER(Geometry, GEOMETRY)
#if API >= 11
IMPLEMENT_NOTIMPL_CREATE_SHADER(Hull)
IMPLEMENT_NOTIMPL_CREATE_SHADER(Domain)
IMPLEMENT_NOTIMPL_CREATE_SHADER(Compute)
#endif
virtual HRESULT STDMETHODCALLTYPE CreateGeometryShaderWithStreamOutput(
const void *shader_bytecode,
SIZE_T bytecode_length,
const D3D11_SO_DECLARATION_ENTRY *so_declaration,
unsigned num_entries,
#if API >= 11
const unsigned *buffer_strides,
unsigned num_strides,
unsigned rasterized_stream,
ID3D11ClassLinkage *class_linkage,
#else
UINT output_stream_stride,
#endif
ID3D11GeometryShader **out_geometry_shader)
{
SYNCHRONIZED;
GalliumD3D11GeometryShader* gs;
#if API >= 11
if(rasterized_stream != 0)
return E_NOTIMPL; // not yet supported by gallium
#endif
struct dxbc_chunk_signature* sig = dxbc_find_signature(shader_bytecode, bytecode_length, DXBC_FIND_OUTPUT_SIGNATURE);
if(!sig)
return E_INVALIDARG;
D3D11_SIGNATURE_PARAMETER_DESC* out;
unsigned num_outputs = dxbc_parse_signature(sig, &out);
struct pipe_stream_output_info so;
memset(&so, 0, sizeof(so));
#if API >= 11
if(num_strides)
so.stride = buffer_strides[0];
if(num_strides > 1)
debug_printf("Warning: multiple user-specified strides not implemented !\n");
#else
so.stride = output_stream_stride;
#endif
for(unsigned i = 0; i < num_entries; ++i)
{
unsigned j;
for(j = 0; j < num_outputs; ++j)
if(out[j].SemanticIndex == so_declaration[i].SemanticIndex && !strcasecmp(out[j].SemanticName, so_declaration[i].SemanticName))
break;
if(j >= num_outputs)
continue;
const int first_comp = ffs(out[j].Mask) - 1 + so_declaration[i].StartComponent;
so.output[i].output_buffer = so_declaration[i].OutputSlot;
so.output[i].register_index = out[j].Register;
so.output[i].register_mask = ((1 << so_declaration[i].ComponentCount) - 1) << first_comp;
++so.num_outputs;
}
if(out)
free(out);
gs = reinterpret_cast<GalliumD3D11GeometryShader*>(create_stage_shader(PIPE_SHADER_GEOMETRY, PASS_SHADER_ARGS, &so));
if(!gs)
return E_FAIL;
if(!out_geometry_shader) {
gs->Release();
return S_FALSE;
}
*out_geometry_shader = gs;
return S_OK;
}
#if API >= 11
virtual HRESULT STDMETHODCALLTYPE CreateClassLinkage(
ID3D11ClassLinkage **out_linkage)
{
SYNCHRONIZED;
return E_NOTIMPL;
}
#endif
virtual HRESULT STDMETHODCALLTYPE CreateQuery(
const D3D11_QUERY_DESC *query_desc,
ID3D11Query **out_query)
{
SYNCHRONIZED;
if(invalid(query_desc->Query >= D3D11_QUERY_COUNT))
return E_INVALIDARG;
unsigned query_type = d3d11_to_pipe_query[query_desc->Query];
if(query_type >= PIPE_QUERY_TYPES)
return E_NOTIMPL;
if(!out_query)
return S_FALSE;
struct pipe_query* query = immediate_pipe->create_query(immediate_pipe, query_type);
if(!query)
return E_FAIL;
*out_query = new GalliumD3D11Query(this, query, d3d11_query_size[query_desc->Query], *query_desc);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreatePredicate(
const D3D11_QUERY_DESC *predicate_desc,
ID3D11Predicate **out_predicate)
{
SYNCHRONIZED;
unsigned query_type;
switch(predicate_desc->Query)
{
case D3D11_QUERY_SO_OVERFLOW_PREDICATE:
query_type = PIPE_QUERY_SO_OVERFLOW_PREDICATE;
break;
case D3D11_QUERY_OCCLUSION_PREDICATE:
query_type = PIPE_QUERY_OCCLUSION_PREDICATE;
break;
default:
return E_INVALIDARG;
}
if(out_predicate)
return S_FALSE;
struct pipe_query* query = immediate_pipe->create_query(immediate_pipe, query_type);
if(!query)
return E_FAIL;
*out_predicate = new GalliumD3D11Predicate(this, query, sizeof(BOOL), *predicate_desc);
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE CreateCounter(
const D3D11_COUNTER_DESC *counter_desc,
ID3D11Counter **out_counter)
{
SYNCHRONIZED;
return E_NOTIMPL;
// remember to return S_FALSE if out_counter == NULL and everything is OK
}
#if API >= 11
virtual HRESULT STDMETHODCALLTYPE CreateDeferredContext(
unsigned context_flags,
ID3D11DeviceContext **out_deferred_context)
{
SYNCHRONIZED;
// TODO: this will have to be implemented using a new Gallium util module
return E_NOTIMPL;
// remember to return S_FALSE if out_counter == NULL and everything is OK
}
#endif
virtual HRESULT STDMETHODCALLTYPE OpenSharedResource(
HANDLE resource,
REFIID iid,
void **out_resource)
{
SYNCHRONIZED;
// TODO: the problem here is that we need to communicate dimensions somehow
return E_NOTIMPL;
// remember to return S_FALSE if out_counter == NULL and everything is OK
#if 0
struct pipe_resou rce templat;
struct winsys_handle handle;
handle.stride = 0;
handle.handle = resource;
handle.type = DRM_API_HANDLE_TYPE_SHARED;
screen->resource_from_handle(screen, &templat, &handle);
#endif
}
#if API < 11
/* these are documented as "Not implemented".
* According to the UMDDI documentation, they apparently turn on a
* (width + 1) x (height + 1) convolution filter for 1-bit textures.
* Probably nothing uses these, assuming it has ever been implemented anywhere.
*/
void STDMETHODCALLTYPE SetTextFilterSize(
UINT width,
UINT height
)
{}
virtual void STDMETHODCALLTYPE GetTextFilterSize(
UINT *width,
UINT *height
)
{}
#endif
#if API >= 11
virtual void STDMETHODCALLTYPE RestoreGalliumState()
{
GalliumD3D11ImmediateDeviceContext_RestoreGalliumState(immediate_context);
}
virtual void STDMETHODCALLTYPE RestoreGalliumStateBlitOnly()
{
GalliumD3D11ImmediateDeviceContext_RestoreGalliumStateBlitOnly(immediate_context);
}
#endif
virtual struct pipe_context* STDMETHODCALLTYPE GetGalliumContext(void)
{
return immediate_pipe;
}
#undef SYNCHRONIZED
};