/************************************************************************** * * 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(INSTANCING), 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 }; // this is called "screen" because in the D3D10 case it's only part of the device template struct GalliumD3D11ScreenImpl : public GalliumD3D11Screen { D3D_FEATURE_LEVEL feature_level; int format_support[PIPE_FORMAT_COUNT]; unsigned creation_flags; unsigned exception_mode; maybe_mutex_t 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 > 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_STREAM_OUTPUT); screen_caps.queries = screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY); screen_caps.render_condition = screen_caps.queries; 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_param(screen, PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS)) screen_caps.stages_with_sampling &=~ (1 << PIPE_SHADER_VERTEX); memset(format_support, 0xff, sizeof(format_support)); float default_level; /* don't even attempt to autodetect D3D10 level support, since it's just not fully implemented yet */ if(util_check_caps(screen, caps_dx_9_3)) default_level = 9.3; else if(util_check_caps(screen, caps_dx_9_2)) default_level = 9.2; else if(util_check_caps(screen, caps_dx_9_1)) default_level = 9.1; else { _debug_printf("Warning: driver does not even meet D3D_FEATURE_LEVEL_9_1 features, advertising it anyway!\n"); default_level = 9.1; } 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; unsigned buffer = D3D11_FORMAT_SUPPORT_BUFFER | D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER | D3D11_FORMAT_SUPPORT_IA_INDEX_BUFFER; unsigned sampler_view = D3D11_FORMAT_SUPPORT_SHADER_SAMPLE | D3D11_FORMAT_SUPPORT_MIP | D3D11_FORMAT_SUPPORT_MIP_AUTOGEN; if(util_format_is_depth_or_stencil(format)) sampler_view |= D3D11_FORMAT_SUPPORT_SHADER_SAMPLE_COMPARISON; /* TODO: do this properly when Gallium drivers actually support index/vertex format queries */ if(screen->is_format_supported(screen, format, PIPE_BUFFER, 0, PIPE_BIND_VERTEX_BUFFER) || (screen->is_format_supported(screen, format, PIPE_BUFFER, 0, PIPE_BIND_INDEX_BUFFER) || format == PIPE_FORMAT_R8_UNORM)) support |= buffer; if(screen->is_format_supported(screen, format, PIPE_BUFFER, 0, PIPE_BIND_STREAM_OUTPUT)) support |= buffer | 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 | sampler_view; if(screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW)) support |= D3D11_FORMAT_SUPPORT_TEXTURE2D | sampler_view; if(screen->is_format_supported(screen, format, PIPE_TEXTURE_CUBE, 0, PIPE_BIND_SAMPLER_VIEW)) support |= D3D11_FORMAT_SUPPORT_TEXTURE2D | sampler_view; if(screen->is_format_supported(screen, format, PIPE_TEXTURE_3D, 0, PIPE_BIND_SAMPLER_VIEW)) support |= D3D11_FORMAT_SUPPORT_TEXTURE3D | sampler_view; 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 | D3D11_FORMAT_SUPPORT_BLENDABLE; 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; 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 bool convert_blend_state(T& to, const U& from, unsigned BlendEnable, unsigned RenderTargetWriteMask) { if(invalid(0 || from.SrcBlend >= D3D11_BLEND_COUNT || from.SrcBlendAlpha >= D3D11_BLEND_COUNT || from.DestBlend >= D3D11_BLEND_COUNT || from.DestBlendAlpha >= D3D11_BLEND_COUNT || from.BlendOp >= 6 || from.BlendOpAlpha >= 6 || !from.BlendOp || !from.BlendOpAlpha )) return false; to.blend_enable = 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); for(unsigned i = 0; i < 8; ++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; 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; 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; /* TODO: is this correct? */ /* TODO: we are ignoring depthBiasClamp! */ 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.scissor = !!rasterizer_desc->ScissorEnable; state.multisample = !!rasterizer_desc->MultisampleEnable; state.line_smooth = !!rasterizer_desc->AntialiasedLineEnable; /* 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, !rasterizer_desc->DepthClipEnable); 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; } 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, 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, false); D3D11_SIGNATURE_PARAMETER_DESC* params; unsigned num_params = dxbc_parse_signature(sig, ¶ms); typedef std::unordered_map, 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]; unsigned num_params_to_use = std::min(num_params, (unsigned)D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT); for(unsigned i = 0; i < num_params_to_use; ++i) { int idx = -1; 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()) idx = iter->second; // TODO: I kind of doubt Gallium drivers will like null elements; should we do something about it, either here, in the interface, or in the drivers? // TODO: also, in which cases should we return errors? (i.e. duplicate semantics in vs, duplicate semantics in layout, unmatched semantic in vs, unmatched semantic in layout) memset(&elements[i], 0, sizeof(elements[i])); if(idx >= 0) { elements[i].src_format = dxgi_to_pipe_format[input_element_descs[idx].Format]; elements[i].src_offset = input_element_descs[idx].AlignedByteOffset; elements[i].vertex_buffer_index = input_element_descs[idx].InputSlot; elements[i].instance_divisor = input_element_descs[idx].InstanceDataStepRate; } } 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_NOTIMPL; } else { if(array_size > 1) return E_NOTIMPL; array_size = 1; } /* TODO: msaa */ struct pipe_resource templat; memset(&templat, 0, sizeof(templat)); templat.target = target; templat.width0 = width; templat.height0 = height; templat.depth0 = depth; 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]; 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 = 1; 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; if(!desc) { struct pipe_resource* resource = ((GalliumD3D11Resource<>*)iresource)->resource; 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_2D: case PIPE_TEXTURE_RECT: def_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; def_desc.Texture2D.MipLevels = resource->last_level + 1; 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: 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 = 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_TEXTURE1D: case D3D11_SRV_DIMENSION_TEXTURE2D: case D3D11_SRV_DIMENSION_TEXTURE3D: case D3D11_SRV_DIMENSION_TEXTURE1DARRAY: case D3D11_SRV_DIMENSION_TEXTURE2DARRAY: /* yes, this works for all of these types (but TODO: texture arrays) */ templat.u.tex.first_level = desc->Texture1D.MostDetailedMip; templat.u.tex.last_level = templat.u.tex.first_level + desc->Texture1D.MipLevels - 1; break; case D3D11_SRV_DIMENSION_BUFFER: 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; D3D11_RENDER_TARGET_VIEW_DESC def_desc; if(!desc) { struct pipe_resource* resource = ((GalliumD3D11Resource<>*)iresource)->resource; 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_2D: case PIPE_TEXTURE_RECT: def_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; 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 = 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; /* XXX FIXME */ templat.u.tex.last_layer = desc->Texture3D.FirstWSlice; 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; /* XXX FIXME */ templat.u.tex.last_layer = desc->Texture1DArray.FirstArraySlice; break; case D3D11_RTV_DIMENSION_BUFFER: 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; D3D11_DEPTH_STENCIL_VIEW_DESC def_desc; if(!desc) { struct pipe_resource* resource = ((GalliumD3D11Resource<>*)iresource)->resource; 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_2D: case PIPE_TEXTURE_RECT: def_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; 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 = 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; /* XXX FIXME */ templat.u.tex.last_layer = desc->Texture1DArray.FirstArraySlice; 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; } GalliumD3D11Shader<>* create_stage_shader(unsigned type, const void* shader_bytecode, SIZE_T bytecode_length #if API >= 11 , ID3D11ClassLinkage *class_linkage #endif ) { bool dump = debug_get_option_dump_shaders(); dxbc_chunk_header* sm4_chunk = dxbc_find_shader_bytecode(shader_bytecode, bytecode_length); if(!sm4_chunk) return 0; std::auto_ptr sm4(sm4_parse(sm4_chunk + 1, bswap_le32(sm4_chunk->size))); if(!sm4.get()) return 0; if(dump) sm4->dump(); struct pipe_shader_state tgsi_shader; memset(&tgsi_shader, 0, sizeof(tgsi_shader)); 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; } if(shader) { shader->slot_to_resource = sm4->slot_to_resource; shader->slot_to_sampler = sm4->slot_to_sampler; } 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); \ 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; return E_NOTIMPL; // remember to return S_FALSE if ppGeometyShader == NULL and the shader is 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) 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: return E_NOTIMPL; case D3D11_QUERY_OCCLUSION_PREDICATE: query_type = PIPE_QUERY_OCCLUSION_COUNTER; 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 };