/************************************************************************** * * 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. * **************************************************************************/ template struct GalliumD3D11DeviceChild : public GalliumPrivateDataComObject { GalliumD3D11Screen* device; // must not be null // if this is called, the subclass constructor must set device itself GalliumD3D11DeviceChild() : device(0) {} GalliumD3D11DeviceChild(GalliumD3D11Screen* p_device) { // we store the reference count minus one in refcnt device = p_device; device->AddRef(); } /* The purpose of this is to avoid cyclic garbage, since this won't hold * a pointer to the device if it is only held by a pipeline binding in the immediate context * * TODO: we could only manipulate the device refcnt when atomic_refcnt == 0 changes, * but this requires more complex atomic ops */ inline ULONG add_ref() { device->AddRef(); return GalliumPrivateDataComObject::add_ref(); } inline ULONG release() { device->Release(); return GalliumPrivateDataComObject::release(); } virtual ULONG STDMETHODCALLTYPE AddRef() { return add_ref(); } virtual ULONG STDMETHODCALLTYPE Release() { return release(); } virtual void STDMETHODCALLTYPE GetDevice( ID3D11Device **out_device ) { device->AddRef(); *out_device = device; } }; template struct GalliumD3D11Object : public GalliumD3D11DeviceChild { Object* object; GalliumD3D11Object(GalliumD3D11Screen* device, Object* object) : GalliumD3D11DeviceChild(device), object(object) {} virtual ~GalliumD3D11Object(); }; #define IMPLEMENT_OBJECT_DTOR(name, gallium) \ template<> \ GalliumD3D11Object::~GalliumD3D11Object() \ { \ DX10_ONLY(device->Unbind##name(this)); \ device->immediate_pipe->delete_##gallium##_state(device->immediate_pipe, object); \ } #define IMPLEMENT_VIEW_DTOR(name, gallium) \ template<> \ GalliumD3D11Object::~GalliumD3D11Object() \ { \ DX10_ONLY(device->Unbind##name(this)); \ pipe_##gallium##_reference(&object, 0); \ } IMPLEMENT_OBJECT_DTOR(InputLayout, vertex_elements) IMPLEMENT_OBJECT_DTOR(DepthStencilState, depth_stencil_alpha) IMPLEMENT_OBJECT_DTOR(RasterizerState, rasterizer) IMPLEMENT_OBJECT_DTOR(SamplerState, sampler) IMPLEMENT_OBJECT_DTOR(BlendState, blend) IMPLEMENT_OBJECT_DTOR(VertexShader, vs) IMPLEMENT_OBJECT_DTOR(PixelShader, fs) IMPLEMENT_OBJECT_DTOR(GeometryShader, gs) IMPLEMENT_VIEW_DTOR(ShaderResourceView, sampler_view) IMPLEMENT_VIEW_DTOR(RenderTargetView, surface) IMPLEMENT_VIEW_DTOR(DepthStencilView, surface) #if API >= 11 // IMPLEMENT_VIEW_DTOR(UnorderedAccessView, surface); // IMPLEMENT_OBJECT_DTOR(HullShader, tcs); // IMPLEMENT_OBJECT_DTOR(DomainShader, tes); // IMPLEMENT_OBJECT_DTOR(ComputeShader, cs); #else IMPLEMENT_OBJECT_DTOR(BlendState1, blend) IMPLEMENT_VIEW_DTOR(ShaderResourceView1, sampler_view) #endif template struct GalliumD3D11DescribedObject : public GalliumD3D11Object { Desc desc; GalliumD3D11DescribedObject(GalliumD3D11Screen* device, Object* object, const Desc& desc) : GalliumD3D11Object(device, object), desc(desc) {} virtual void STDMETHODCALLTYPE GetDesc(Desc *out_desc) { memcpy(out_desc, &desc, sizeof(desc)); } }; typedef GalliumD3D11Object GalliumD3D11InputLayout; typedef GalliumD3D11DescribedObject GalliumD3D11DepthStencilState; typedef GalliumD3D11DescribedObject GalliumD3D11RasterizerStateBase; typedef GalliumD3D11DescribedObject GalliumD3D11SamplerState; #if API >= 11 typedef GalliumD3D11DescribedObject GalliumD3D11BlendState; #else typedef GalliumD3D10DescribedObject GalliumD3D10BlendStateBase; struct GalliumD3D10BlendState : public GalliumD3D10BlendStateBase { static D3D10_BLEND_DESC convert_to_d3d10(const D3D10_BLEND_DESC1& desc1) { D3D10_BLEND_DESC desc; desc.AlphaToCoverageEnable = desc1.AlphaToCoverageEnable; desc.SrcBlend = desc1.RenderTarget[0].SrcBlend; desc.DestBlend = desc1.RenderTarget[0].DestBlend; desc.BlendOp = desc1.RenderTarget[0].BlendOp; desc.SrcBlendAlpha = desc1.RenderTarget[0].SrcBlendAlpha; desc.DestBlendAlpha = desc1.RenderTarget[0].DestBlendAlpha; desc.BlendOpAlpha = desc1.RenderTarget[0].BlendOpAlpha; for(unsigned i = 0; i < 8; ++i) { desc.BlendEnable[i] = desc1.RenderTarget[i].BlendEnable; desc.RenderTargetWriteMask[i] = desc1.RenderTarget[i].RenderTargetWriteMask; } return desc; } D3D10_BLEND_DESC1 desc1; GalliumD3D10BlendState(GalliumD3D10Screen* device, void* object, const D3D10_BLEND_DESC& desc) : GalliumD3D10BlendStateBase(device, object, desc) { memset(&desc1, 0, sizeof(desc1)); desc1.AlphaToCoverageEnable = desc.AlphaToCoverageEnable; desc1.RenderTarget[0].SrcBlend = desc.SrcBlend; desc1.RenderTarget[0].DestBlend = desc.DestBlend; desc1.RenderTarget[0].BlendOp = desc.BlendOp; desc1.RenderTarget[0].SrcBlendAlpha = desc.SrcBlendAlpha; desc1.RenderTarget[0].DestBlendAlpha = desc.DestBlendAlpha; desc1.RenderTarget[0].BlendOpAlpha = desc.BlendOpAlpha; for(unsigned i = 0; i < 8; ++i) { desc1.RenderTarget[i].BlendEnable = desc.BlendEnable[i]; desc1.RenderTarget[i].RenderTargetWriteMask = desc.RenderTargetWriteMask[i]; } } GalliumD3D10BlendState(GalliumD3D10Screen* device, void* object, const D3D10_BLEND_DESC1& desc) : GalliumD3D10BlendStateBase(device, object, convert_to_d3d10(desc)), desc1(desc1) {} virtual void STDMETHODCALLTYPE GetDesc1(D3D10_BLEND_DESC1 *out_desc) { memcpy(out_desc, &desc1, sizeof(desc1)); } }; #endif struct GalliumD3D11RasterizerState : public GalliumD3D11RasterizerStateBase { bool depth_clamp; GalliumD3D11RasterizerState(GalliumD3D11Screen* device, void* object, const D3D11_RASTERIZER_DESC& desc, bool depth_clamp) : GalliumD3D11RasterizerStateBase(device, object, desc), depth_clamp(depth_clamp) {} }; template struct GalliumD3D11Shader : public GalliumD3D11Object { std::vector slot_to_resource; std::vector slot_to_sampler; GalliumD3D11Shader(GalliumD3D11Screen* device, void* object) : GalliumD3D11Object(device, object) {} }; typedef GalliumD3D11Shader GalliumD3D11VertexShader; typedef GalliumD3D11Shader GalliumD3D11GeometryShader; typedef GalliumD3D11Shader GalliumD3D11PixelShader; #if API >= 11 /* typedef GalliumD3D11Shader GalliumD3D11HullShader; typedef GalliumD3D11Shader GalliumD3D11DomainShader; typedef GalliumD3D11Shader GalliumD3D11ComputeShader; */ #endif template struct GalliumD3D11ResourceBase : public GalliumD3D11DeviceChild { unsigned eviction_priority; virtual void STDMETHODCALLTYPE SetEvictionPriority( unsigned new_eviction_priority ) { eviction_priority = new_eviction_priority; } virtual unsigned STDMETHODCALLTYPE GetEvictionPriority() { return eviction_priority; } }; template struct GalliumDXGIResource : public IDXGIResource { virtual HRESULT STDMETHODCALLTYPE SetEvictionPriority( unsigned new_eviction_priority ) { static_cast(this)->eviction_priority = new_eviction_priority; return S_OK; } virtual HRESULT STDMETHODCALLTYPE GetEvictionPriority(unsigned* out_eviction_priority) { *out_eviction_priority = static_cast(this)->eviction_priority; return S_OK; } virtual HRESULT STDMETHODCALLTYPE GetDevice( REFIID riid, void **out_parent) { if(!static_cast(this)->device) return E_NOINTERFACE; return static_cast(this)->device->QueryInterface(riid, out_parent); } virtual HRESULT STDMETHODCALLTYPE GetParent( REFIID riid, void **out_parent) { if(!static_cast(this)->device) return E_NOINTERFACE; return static_cast(this)->device->QueryInterface(riid, out_parent); } }; template struct com_traits > : public com_traits {}; template struct GalliumD3D11Resource : public GalliumMultiComObject< GalliumMultiPrivateDataComObject< GalliumD3D11ResourceBase, GalliumDXGIResource > >, IGalliumResource > { struct pipe_resource* resource; std::unordered_map transfers; float min_lod; DXGI_USAGE dxgi_usage; GalliumD3D11Resource(GalliumD3D11Screen* device = 0, struct pipe_resource* resource = 0, unsigned dxgi_usage = 0) : resource(resource), min_lod(0), dxgi_usage(dxgi_usage) { this->device = device; if(device) device->AddRef(); this->eviction_priority = 0; } ~GalliumD3D11Resource() { pipe_resource_reference(&resource, 0); } virtual HRESULT STDMETHODCALLTYPE GetUsage( DXGI_USAGE *out_usage ) { *out_usage = this->dxgi_usage; return S_OK; } virtual HRESULT STDMETHODCALLTYPE GetSharedHandle(HANDLE *out_shared_handle) { return E_NOTIMPL; } virtual struct pipe_resource* STDMETHODCALLTYPE GetGalliumResource() { return resource; } }; template struct GalliumD3D11TypedResource : public GalliumD3D11Resource { Desc desc; GalliumD3D11TypedResource() {} GalliumD3D11TypedResource(GalliumD3D11Screen* device, struct pipe_resource* resource, const Desc& desc, unsigned dxgi_usage) : GalliumD3D11Resource(device, resource, dxgi_usage), desc(desc) {} virtual void STDMETHODCALLTYPE GetType( D3D11_RESOURCE_DIMENSION *out_resource_dimension) { *out_resource_dimension = Dim; } virtual void STDMETHODCALLTYPE GetDesc(Desc *out_desc) { memcpy(out_desc, &desc, sizeof(desc)); } }; typedef GalliumD3D11TypedResource GalliumD3D11Texture1DBase; typedef GalliumD3D11TypedResource GalliumD3D11Texture2DBase; typedef GalliumD3D11TypedResource GalliumD3D11Texture3DBase; typedef GalliumD3D11TypedResource GalliumD3D11BufferBase; #if API >= 11 typedef GalliumD3D11BufferBase GalliumD3D11Buffer; typedef GalliumD3D11Texture1DBase GalliumD3D11Texture1D; typedef GalliumD3D11Texture2DBase GalliumD3D11Texture2D; typedef GalliumD3D11Texture3DBase GalliumD3D11Texture3D; #else struct GalliumD3D10Buffer : public GalliumD3D10BufferBase { GalliumD3D10Buffer(GalliumD3D10Screen* device, struct pipe_resource* resource, const D3D10_BUFFER_DESC& desc, unsigned dxgi_usage) : GalliumD3D10BufferBase(device, resource, desc, dxgi_usage) {} ~GalliumD3D10Buffer() { device->UnbindBuffer(this); } virtual HRESULT STDMETHODCALLTYPE Map( D3D10_MAP map_type, unsigned map_flags, void **out_data) { D3D10_MAPPED_SUBRESOURCE msr; HRESULT hr = device->Map(this, 0, map_type, map_flags, &msr); if(!SUCCEEDED(hr)) return hr; *out_data = msr.pData; return S_OK; } virtual void STDMETHODCALLTYPE Unmap() { device->Unmap(this, 0); } }; struct GalliumD3D10Texture1D : public GalliumD3D10Texture1DBase { GalliumD3D10Texture1D(GalliumD3D10Screen* device, struct pipe_resource* resource, const D3D10_TEXTURE1D_DESC& desc, unsigned dxgi_usage) : GalliumD3D10Texture1DBase(device, resource, desc, dxgi_usage) {} virtual HRESULT STDMETHODCALLTYPE Map( unsigned subresource, D3D10_MAP map_type, unsigned map_flags, void **out_data) { D3D10_MAPPED_SUBRESOURCE msr; HRESULT hr = device->Map(this, subresource, map_type, map_flags, &msr); if(!SUCCEEDED(hr)) return hr; *out_data = msr.pData; return S_OK; } virtual void STDMETHODCALLTYPE Unmap( unsigned subresource ) { device->Unmap(this, subresource); } }; struct GalliumD3D10Texture2D : public GalliumD3D10Texture2DBase { GalliumD3D10Texture2D() {} GalliumD3D10Texture2D(GalliumD3D10Screen* device, struct pipe_resource* resource, const D3D10_TEXTURE2D_DESC& desc, unsigned dxgi_usage) : GalliumD3D10Texture2DBase(device, resource, desc, dxgi_usage) {} virtual HRESULT STDMETHODCALLTYPE Map( unsigned subresource, D3D10_MAP map_type, unsigned map_flags, D3D10_MAPPED_TEXTURE2D *out_mapped_subresource) { D3D10_MAPPED_SUBRESOURCE msr; HRESULT hr = device->Map(this, subresource, map_type, map_flags, &msr); if(!SUCCEEDED(hr)) return hr; out_mapped_subresource->pData = msr.pData; out_mapped_subresource->RowPitch = msr.RowPitch; return S_OK; } virtual void STDMETHODCALLTYPE Unmap( unsigned subresource ) { device->Unmap(this, subresource); } }; struct GalliumD3D10Texture3D : public GalliumD3D10Texture3DBase { GalliumD3D10Texture3D(GalliumD3D10Screen* device, struct pipe_resource* resource, const D3D10_TEXTURE3D_DESC& desc, unsigned dxgi_usage) : GalliumD3D10Texture3DBase(device, resource, desc, dxgi_usage) {} virtual HRESULT STDMETHODCALLTYPE Map( unsigned subresource, D3D10_MAP map_type, unsigned map_flags, D3D10_MAPPED_TEXTURE3D *out_mapped_subresource) { D3D10_MAPPED_SUBRESOURCE msr; HRESULT hr = device->Map(this, subresource, map_type, map_flags, &msr); if(!SUCCEEDED(hr)) return hr; out_mapped_subresource->pData = msr.pData; out_mapped_subresource->RowPitch = msr.RowPitch; out_mapped_subresource->DepthPitch = msr.DepthPitch; return S_OK; } virtual void STDMETHODCALLTYPE Unmap( unsigned subresource ) { device->Unmap(this, subresource); } }; #endif struct GalliumD3D11Surface : public GalliumMultiPrivateDataComObject { GalliumD3D11Surface(GalliumD3D11Screen* device, struct pipe_resource* resource, const D3D11_TEXTURE2D_DESC& desc, unsigned dxgi_usage) { this->device = device; this->device->AddRef(); this->resource = resource; this->desc = desc; this->dxgi_usage = dxgi_usage; } virtual HRESULT STDMETHODCALLTYPE GetDesc( DXGI_SURFACE_DESC *out_desc) { out_desc->Format = this->desc.Format; out_desc->Width = this->desc.Width; out_desc->Height = this->desc.Height; out_desc->SampleDesc = this->desc.SampleDesc; return S_OK; } virtual HRESULT STDMETHODCALLTYPE GetParent( REFIID riid, void **out_parent) { if(!device) return E_NOINTERFACE; return device->QueryInterface(riid, out_parent); } /* TODO: somehow implement these */ virtual HRESULT STDMETHODCALLTYPE GetDC( BOOL discard, HDC *out_hdc) { *out_hdc = 0; return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE ReleaseDC( RECT *out_dirty_rect) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE Map( DXGI_MAPPED_RECT *out_locked_rect, unsigned map_flags) { D3D11_MAP d3d_map; if(map_flags & DXGI_MAP_DISCARD) d3d_map = D3D11_MAP_WRITE_DISCARD; else { if(map_flags & DXGI_MAP_READ) { if(map_flags & DXGI_MAP_WRITE) d3d_map = D3D11_MAP_READ_WRITE; else d3d_map = D3D11_MAP_READ; } else d3d_map = D3D11_MAP_WRITE; } D3D11_MAPPED_SUBRESOURCE d3d_mapped; HRESULT hres = this->device->get_immediate_context()->Map(this, 0, d3d_map, 0, &d3d_mapped); out_locked_rect->pBits = (uint8_t*)d3d_mapped.pData; out_locked_rect->Pitch = d3d_mapped.RowPitch; return hres; } virtual HRESULT STDMETHODCALLTYPE Unmap(void) { this->device->get_immediate_context()->Unmap(this, 0); return S_OK; } virtual HRESULT STDMETHODCALLTYPE GetDevice( REFIID riid, void **out_parent) { if(!device) return E_NOINTERFACE; return device->QueryInterface(riid, out_parent); } }; template struct GalliumD3D11View : public GalliumD3D11DescribedObject { GalliumD3D11Resource<>* resource; GalliumD3D11View(GalliumD3D11Screen* device, GalliumD3D11Resource<>* resource, Object* object, const Desc& desc) : GalliumD3D11DescribedObject(device, object, desc), resource(resource) { resource->AddRef(); } ~GalliumD3D11View() { resource->Release(); } virtual void STDMETHODCALLTYPE GetResource(ID3D11Resource** out_resource) { resource->AddRef(); *out_resource = resource; } }; typedef GalliumD3D11View GalliumD3D11DepthStencilView; typedef GalliumD3D11View GalliumD3D11RenderTargetView; #if API >= 11 typedef GalliumD3D11View GalliumD3D11ShaderResourceView; #else typedef GalliumD3D10View GalliumD3D10ShaderResourceViewBase; struct GalliumD3D10ShaderResourceView : public GalliumD3D10ShaderResourceViewBase { GalliumD3D10ShaderResourceView(GalliumD3D10Screen* device, GalliumD3D10Resource<>* resource, struct pipe_sampler_view* view, const D3D10_SHADER_RESOURCE_VIEW_DESC1& desc) : GalliumD3D10ShaderResourceViewBase(device, resource, view, desc) {} virtual void STDMETHODCALLTYPE GetDesc1(D3D10_SHADER_RESOURCE_VIEW_DESC1 *out_desc) { memcpy(out_desc, &desc, sizeof(*out_desc)); } virtual void STDMETHODCALLTYPE GetDesc(D3D10_SHADER_RESOURCE_VIEW_DESC *out_desc) { memcpy(out_desc, &desc, sizeof(*out_desc)); } }; #endif template struct GalliumD3D11Asynchronous : public GalliumD3D11DeviceChild { struct pipe_query* query; unsigned data_size; GalliumD3D11Asynchronous(GalliumD3D11Screen* device, struct pipe_query* query, unsigned data_size) : GalliumD3D11DeviceChild(device), query(query), data_size(data_size) {} ~GalliumD3D11Asynchronous() { this->device->immediate_pipe->destroy_query(this->device->immediate_pipe, query); } virtual unsigned STDMETHODCALLTYPE GetDataSize() { return data_size; } #if API < 11 virtual void STDMETHODCALLTYPE Begin() { this->device->Begin(this); } virtual void STDMETHODCALLTYPE End() { this->device->End(this); } virtual HRESULT STDMETHODCALLTYPE GetData( void * out_data, unsigned data_size, unsigned get_data_flags) { return this->device->GetData(this, out_data, data_size, get_data_flags); } #endif }; template struct GalliumD3D11QueryOrPredicate : public GalliumD3D11Asynchronous { D3D11_QUERY_DESC desc; GalliumD3D11QueryOrPredicate(GalliumD3D11Screen* device, struct pipe_query* query, unsigned data_size, const D3D11_QUERY_DESC& desc) : GalliumD3D11Asynchronous(device, query, data_size), desc(desc) {} virtual void STDMETHODCALLTYPE GetDesc( D3D11_QUERY_DESC *out_desc) { *out_desc = desc; } }; struct GalliumD3D11Query : public GalliumD3D11QueryOrPredicate { GalliumD3D11Query(GalliumD3D11Screen* device, struct pipe_query* query, unsigned data_size, const D3D11_QUERY_DESC& desc) : GalliumD3D11QueryOrPredicate(device, query, data_size, desc) {} }; struct GalliumD3D11Predicate : public GalliumD3D11QueryOrPredicate { GalliumD3D11Predicate(GalliumD3D11Screen* device, struct pipe_query* query, unsigned data_size, const D3D11_QUERY_DESC& desc) : GalliumD3D11QueryOrPredicate(device, query, data_size, desc) {} ~GalliumD3D11Predicate() { DX10_ONLY(device->UnbindPredicate(this)); } }; struct GalliumD3D11Counter : public GalliumD3D11Asynchronous { D3D11_COUNTER_DESC desc; GalliumD3D11Counter(GalliumD3D11Screen* device, struct pipe_query* query, unsigned data_size, const D3D11_COUNTER_DESC& desc) : GalliumD3D11Asynchronous(device, query, data_size), desc(desc) {} virtual void STDMETHODCALLTYPE GetDesc( D3D11_COUNTER_DESC *out_desc) { *out_desc = desc; } };