diff options
author | Luca Barbieri <[email protected]> | 2010-09-12 02:49:36 +0200 |
---|---|---|
committer | Luca Barbieri <[email protected]> | 2010-09-21 10:58:17 +0200 |
commit | 92617aeac109481258f0c3863d09c1b8903d438b (patch) | |
tree | d85d6a04e87d227964386ad1d6b3d6ae6954e179 /src/gallium/state_trackers/d3d1x/gd3d11 | |
parent | 894a307a91d6437ec418800952da2ec174e092f5 (diff) |
d3d1x: add new Direct3D 10/11 COM state tracker for Gallium
This is a new implementation of the Direct3D 11 COM API for Gallium.
Direct3D 10 and 10.1 implementations are also provided, which are
automatically generated with s/D3D11/D3D10/g plus a bunch of #ifs.
While this is an initial version, most of the code is there (limited
to what Gallium can express), and tri, gears and texturing demos
are working.
The primary goal is to realize Gallium's promise of multiple API
support, and provide an API that can be easily implemented with just
a very thin wrapper over Gallium, instead of the enormous amount of
complex code needed for OpenGL.
The secondary goal is to run Windows Direct3D 10/11 games on Linux
using Wine.
Wine dlls are currently not provided, but adding them should be
quite easy.
Fglrx and nvidia drivers can also be supported by writing a Gallium
driver that talks to them using OpenGL, which is a relatively easy
task.
Thanks to the great design of Direct3D 10/11 and closeness to Gallium,
this approach should not result in detectable overhead, and is the
most maintainable way to do it, providing a path to switch to the
open Gallium drivers once they are on par with the proprietary ones.
Currently Wine has a very limited Direct3D 10 implementation, and
completely lacks a Direct3D 11 implementation.
Note that Direct3D 10/11 are completely different from Direct3D 9
and earlier, and thus warrant a fully separate implementation.
The third goal is to provide a superior alternative to OpenGL for
graphics programming on non-Windows systems, particularly Linux
and other free and open systems.
Thanks to a very clean and well-though design done from scratch,
the Direct3D 10/11 APIs are vastly better than OpenGL and can be
supported with orders of magnitude less code and development time,
as you can see by comparing the lines of code of this commit and
those in the existing Mesa OpenGL implementation.
This would have been true for the Longs Peak proposal as well, but
unfortunately it was abandoned by Khronos, leaving the OpenGL
ecosystem without a graphics API with a modern design.
A binding of Direct3D 10/11 to EGL would solve this issue in the
most economical way possible, and this would be great to provide
in Mesa, since DXGI, the API used to bind Direct3D 10/11 to Windows,
is a bit suboptimal, especially on non-Windows platforms.
Finally, a mature Direct3D 10/11 implementation is intrinsically going
to be faster and more reliable than an OpenGL implementation, thanks
to the dramatically smaller API and the segregation of all nontrivial
work to object creation that the application must perform ahead of
time.
Currently, this commit contains:
- Independently created headers for Direct3D 10, 10.1, 11 and DXGI 1.1,
partially based on the existing Wine headers for D3D10 and DXGI 1.0
- A parser for Direct3D 10/11 DXBC and TokenizedProgramFormat (TPF)
- A shader translator from TokenizedProgramFormat to TGSI
- Implementation of the Direct3D 11 core interfaces
- Automatically generated implementation of Direct3D 10 and 10.1
- Implementation of DXGI using the "native" framework of the EGL st
- Demos, usable either on Windows or on this implementation
- d3d11tri, a clone of tri
- d3d11tex, a (multi)texturing demo
- d3d11gears, an improved version of glxgears
- d3d11spikysphere, a D3D11 tessellation demo (currently Windows-only)
- A downloader for the Microsoft HLSL compiler, needed to recompile
the shaders (compiled shader bytecode is also included)
To compile this, configure at least with these options:
--with-state-trackers=egl,d3d1x --with-egl-platforms=x11
plus some gallium drivers (such as softpipe with --enable-gallium-swrast)
The Wine headers (usually from a wine-dev or wine-devel package) must
be installed.
Only x86-32 has been tested.
You may need to run "make" in the subdirectories of src/gallium/winsys/sw
and you may need to manually run "sudo make install" in
src/gallium/targets/egl
To test it, run the demos in the "progs" directory.
Windows binaries are included to find out how demos should work, and to
test Wine integration when it will be done.
Enjoy, and let me know if you manage to compile and run this, or
which issues you are facing if not.
Using softpipe is recommended for now, and your mileage with hardware
drivers may vary.
However, getting this to work on hardware drivers is also obviously very
important.
Note that currently llvmpipe is buggy and causes all 3 gears to be
drawn with the same color.
Use export GALLIUM_DRIVER=softpipe to avoid this.
Thanks to all the Gallium contributors and especially the VMware
team, whose work made it possible to implement Direct3D 10/11 much
more easily than it would have been otherwise.
Diffstat (limited to 'src/gallium/state_trackers/d3d1x/gd3d11')
-rw-r--r-- | src/gallium/state_trackers/d3d1x/gd3d11/Makefile | 6 | ||||
-rw-r--r-- | src/gallium/state_trackers/d3d1x/gd3d11/d3d11.cpp | 236 | ||||
-rw-r--r-- | src/gallium/state_trackers/d3d1x/gd3d11/d3d11_context.h | 2033 | ||||
-rw-r--r-- | src/gallium/state_trackers/d3d1x/gd3d11/d3d11_objects.h | 715 | ||||
-rw-r--r-- | src/gallium/state_trackers/d3d1x/gd3d11/d3d11_screen.h | 1447 |
5 files changed, 4437 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/d3d1x/gd3d11/Makefile b/src/gallium/state_trackers/d3d1x/gd3d11/Makefile new file mode 100644 index 00000000000..650c11d3d0a --- /dev/null +++ b/src/gallium/state_trackers/d3d1x/gd3d11/Makefile @@ -0,0 +1,6 @@ +LIBNAME=gd3d11 +CPP_SOURCES=d3d11.cpp +LIBRARY_INCLUDES=-I../gd3d1x -I../gd3dapi -I../d3dapi -I../w32api -I../d3d1xstutil/include -I../d3d1xshader/include -I../../../include -I../../../auxiliary -I../../../state_trackers/egl/common + +include ../Makefile.inc + diff --git a/src/gallium/state_trackers/d3d1x/gd3d11/d3d11.cpp b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11.cpp new file mode 100644 index 00000000000..22cbf150fe1 --- /dev/null +++ b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11.cpp @@ -0,0 +1,236 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +#include "d3d1x_private.h" + +extern "C" +{ +#include "util/u_gen_mipmap.h" +#include "tgsi/tgsi_ureg.h" +#include "cso_cache/cso_context.h" +} + + +// the perl script will change this to 10 for d3d10, and also do s/D3D11/D3D10 in the whole file +#define API 11 + +#if API >= 11 +#define DX10_ONLY(x) +#else +#define DX10_ONLY(x) x +#endif + +typedef D3D10_MAPPED_TEXTURE3D D3D10_MAPPED_SUBRESOURCE; + +// used to make QueryInterface know the IIDs of the interface and its ancestors +COM_INTERFACE(ID3D11DeviceChild, IUnknown) +COM_INTERFACE(ID3D11InputLayout, ID3D11DeviceChild) +COM_INTERFACE(ID3D11DepthStencilState, ID3D11DeviceChild) +COM_INTERFACE(ID3D11BlendState, ID3D11DeviceChild) +COM_INTERFACE(ID3D11RasterizerState, ID3D11DeviceChild) +COM_INTERFACE(ID3D11SamplerState, ID3D11DeviceChild) +COM_INTERFACE(ID3D11Resource, ID3D11DeviceChild) +COM_INTERFACE(ID3D11Buffer, ID3D11Resource) +COM_INTERFACE(ID3D11Texture1D, ID3D11Resource) +COM_INTERFACE(ID3D11Texture2D, ID3D11Resource) +COM_INTERFACE(ID3D11Texture3D, ID3D11Resource) +COM_INTERFACE(ID3D11View, ID3D11DeviceChild) +COM_INTERFACE(ID3D11ShaderResourceView, ID3D11View) +COM_INTERFACE(ID3D11RenderTargetView, ID3D11View) +COM_INTERFACE(ID3D11DepthStencilView, ID3D11View) +COM_INTERFACE(ID3D11VertexShader, ID3D11DeviceChild) +COM_INTERFACE(ID3D11GeometryShader, ID3D11DeviceChild) +COM_INTERFACE(ID3D11PixelShader, ID3D11DeviceChild) +COM_INTERFACE(ID3D11Asynchronous, ID3D11DeviceChild) +COM_INTERFACE(ID3D11Query, ID3D11Asynchronous) +COM_INTERFACE(ID3D11Predicate, ID3D11Query) +COM_INTERFACE(ID3D11Counter, ID3D11Asynchronous) +COM_INTERFACE(ID3D11Device, IUnknown) + +#if API >= 11 +COM_INTERFACE(ID3D11UnorderedAccessView, ID3D11View) +COM_INTERFACE(ID3D11HullShader, ID3D11DeviceChild) +COM_INTERFACE(ID3D11DomainShader, ID3D11DeviceChild) +COM_INTERFACE(ID3D11ComputeShader, ID3D11DeviceChild) +COM_INTERFACE(ID3D11ClassInstance, ID3D11DeviceChild) +COM_INTERFACE(ID3D11ClassLinkage, ID3D11DeviceChild) +COM_INTERFACE(ID3D11CommandList, ID3D11DeviceChild) +COM_INTERFACE(ID3D11DeviceContext, ID3D11DeviceChild) +#else +COM_INTERFACE(ID3D10BlendState1, ID3D10BlendState) +COM_INTERFACE(ID3D10ShaderResourceView1, ID3D10ShaderResourceView) +COM_INTERFACE(ID3D10Device1, ID3D10Device) +#endif + +struct GalliumD3D11Screen; + +#if API >= 11 +static ID3D11DeviceContext* GalliumD3D11ImmediateDeviceContext_Create(GalliumD3D11Screen* device, struct pipe_context* pipe, bool owns_pipe); +static void GalliumD3D11ImmediateDeviceContext_RestoreGalliumState(ID3D11DeviceContext* context); +static void GalliumD3D11ImmediateDeviceContext_RestoreGalliumStateBlitOnly(ID3D11DeviceContext* context); +static void GalliumD3D11ImmediateDeviceContext_Destroy(ID3D11DeviceContext* device); +#endif + +static inline pipe_box d3d11_to_pipe_box(struct pipe_resource* resource, unsigned level, const D3D11_BOX* pBox) +{ + pipe_box box; + if(pBox) + { + box.x = pBox->left; + box.y = pBox->top; + box.z = pBox->front; + box.width = pBox->right - pBox->left; + box.height = pBox->bottom - pBox->top; + box.depth = pBox->back - pBox->front; + } + else + { + box.x = box.y = box.z = 0; + box.width = u_minify(resource->width0, level); + box.height = u_minify(resource->height0, level); + box.depth = u_minify(resource->depth0, level); + } + return box; +} + +struct GalliumD3D11Caps +{ + bool so; + bool gs; + bool queries; + bool render_condition; + unsigned constant_buffers[D3D11_STAGES]; + unsigned stages; +}; + +// used to avoid needing to have forward declarations of functions +// this is called "screen" because in the D3D10 case it's only part of the device +struct GalliumD3D11Screen + : public GalliumDXGIDevice< + GalliumMultiComObject< +#if API >= 11 + GalliumPrivateDataComObject<ID3D11Device>, +#else + GalliumPrivateDataComObject<ID3D10Device1>, +#endif + IGalliumDevice + > + > +{ + pipe_screen* screen; + pipe_context* immediate_pipe; + GalliumD3D11Caps screen_caps; + +#if API >= 11 + ID3D11DeviceContext* immediate_context; + ID3D11DeviceContext* get_immediate_context() + { + return immediate_context; + } +#else + GalliumD3D11Screen* get_immediate_context() + { + return this; + } +#endif + + + GalliumD3D11Screen(pipe_screen* screen, struct pipe_context* immediate_pipe, IDXGIAdapter* adapter) + : GalliumDXGIDevice(adapter), screen(screen), immediate_pipe(immediate_pipe) + { + } + +#if API < 11 + // we use a D3D11-like API internally + virtual HRESULT STDMETHODCALLTYPE Map( + __in ID3D11Resource *pResource, + __in unsigned Subresource, + __in D3D11_MAP MapType, + __in unsigned MapFlags, + __out D3D11_MAPPED_SUBRESOURCE *pMappedResource) = 0; + virtual void STDMETHODCALLTYPE Unmap( + __in ID3D11Resource *pResource, + __in unsigned Subresource) = 0; + virtual void STDMETHODCALLTYPE Begin( + __in ID3D11Asynchronous *pAsync) = 0; + virtual void STDMETHODCALLTYPE End( + __in ID3D11Asynchronous *pAsync) = 0; + virtual HRESULT STDMETHODCALLTYPE GetData( + __in ID3D11Asynchronous *pAsync, + __out_bcount_opt(DataSize) void *pData, + __in unsigned DataSize, + __in unsigned GetDataFlags) = 0; + + // TODO: maybe we should use function overloading, but that might risk silent errors, + // and cannot be exported to a C interface + virtual void UnbindBlendState(ID3D11BlendState* state) = 0; + virtual void UnbindRasterizerState(ID3D11RasterizerState* state) = 0; + virtual void UnbindDepthStencilState(ID3D11DepthStencilState* state) = 0; + virtual void UnbindInputLayout(ID3D11InputLayout* state) = 0; + virtual void UnbindPixelShader(ID3D11PixelShader* state) = 0; + virtual void UnbindVertexShader(ID3D11VertexShader* state) = 0; + virtual void UnbindGeometryShader(ID3D11GeometryShader* state) = 0; + virtual void UnbindPredicate(ID3D11Predicate* predicate) = 0; + virtual void UnbindSamplerState(ID3D11SamplerState* state) = 0; + virtual void UnbindBuffer(ID3D11Buffer* buffer) = 0; + virtual void UnbindDepthStencilView(ID3D11DepthStencilView* view) = 0; + virtual void UnbindRenderTargetView(ID3D11RenderTargetView* view) = 0; + virtual void UnbindShaderResourceView(ID3D11ShaderResourceView* view) = 0; + + void UnbindBlendState1(ID3D11BlendState1* state) + { + UnbindBlendState(state); + } + void UnbindShaderResourceView1(ID3D11ShaderResourceView1* view) + { + UnbindShaderResourceView(view); + } +#endif +}; + +#include "d3d11_objects.h" +#include "d3d11_screen.h" +#include "d3d11_context.h" + +#if API >= 11 +HRESULT STDMETHODCALLTYPE GalliumD3D11DeviceCreate(struct pipe_screen* screen, struct pipe_context* context, BOOL owns_context, unsigned creation_flags, IDXGIAdapter* adapter, ID3D11Device** ppDevice) +{ + if(creation_flags & D3D11_CREATE_DEVICE_SINGLETHREADED) + *ppDevice = new GalliumD3D11ScreenImpl<false>(screen, context, owns_context, creation_flags, adapter); + else + *ppDevice = new GalliumD3D11ScreenImpl<true>(screen, context, owns_context, creation_flags, adapter); + return S_OK; +} +#else +HRESULT STDMETHODCALLTYPE GalliumD3D10DeviceCreate1(struct pipe_screen* screen, struct pipe_context* context, BOOL owns_context, unsigned creation_flags, IDXGIAdapter* adapter, ID3D10Device1** ppDevice) +{ + if(creation_flags & D3D10_CREATE_DEVICE_SINGLETHREADED) + *ppDevice = new GalliumD3D10Device<false>(screen, context, owns_context, creation_flags, adapter); + else + *ppDevice = new GalliumD3D10Device<true>(screen, context, owns_context, creation_flags, adapter); + return S_OK; +} +#endif diff --git a/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_context.h b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_context.h new file mode 100644 index 00000000000..a8573cdf686 --- /dev/null +++ b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_context.h @@ -0,0 +1,2033 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +/* used to unbind things, we need 128 due to resources */ +static const void* zero_data[128]; + +#define UPDATE_VIEWS_SHIFT (D3D11_STAGES * 0) +#define UPDATE_SAMPLERS_SHIFT (D3D11_STAGES * 1) +#define UPDATE_VERTEX_BUFFERS (1 << (D3D11_STAGES * 2)) + +#if API >= 11 +template<typename PtrTraits> +struct GalliumD3D11DeviceContext : + public GalliumD3D11DeviceChild<ID3D11DeviceContext> +{ +#else +template<bool threadsafe> +struct GalliumD3D10Device : public GalliumD3D10ScreenImpl<threadsafe> +{ + typedef simple_ptr_traits PtrTraits; + typedef GalliumD3D10Device GalliumD3D10DeviceContext; +#endif + + refcnt_ptr<GalliumD3D11Shader<>, PtrTraits> shaders[D3D11_STAGES]; + refcnt_ptr<GalliumD3D11InputLayout, PtrTraits> input_layout; + refcnt_ptr<GalliumD3D11Buffer, PtrTraits> index_buffer; + refcnt_ptr<GalliumD3D11RasterizerState, PtrTraits> rasterizer_state; + refcnt_ptr<GalliumD3D11DepthStencilState, PtrTraits> depth_stencil_state; + refcnt_ptr<GalliumD3D11BlendState, PtrTraits> blend_state; + refcnt_ptr<GalliumD3D11DepthStencilView, PtrTraits> depth_stencil_view; + refcnt_ptr<GalliumD3D11Predicate, PtrTraits> render_predicate; + + refcnt_ptr<GalliumD3D11Buffer, PtrTraits> constant_buffers[D3D11_STAGES][D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; + refcnt_ptr<GalliumD3D11ShaderResourceView, PtrTraits> shader_resource_views[D3D11_STAGES][D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + refcnt_ptr<GalliumD3D11SamplerState, PtrTraits> samplers[D3D11_STAGES][D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + refcnt_ptr<GalliumD3D11Buffer, PtrTraits> input_buffers[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + refcnt_ptr<GalliumD3D11RenderTargetView, PtrTraits> render_target_views[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; + refcnt_ptr<GalliumD3D11Buffer, PtrTraits> so_targets[D3D11_SO_BUFFER_SLOT_COUNT]; + +#if API >= 11 + refcnt_ptr<ID3D11UnorderedAccessView, PtrTraits> cs_unordered_access_views[D3D11_PS_CS_UAV_REGISTER_COUNT]; + refcnt_ptr<ID3D11UnorderedAccessView, PtrTraits> om_unordered_access_views[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT]; +#endif + + D3D11_VIEWPORT viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + D3D11_RECT scissor_rects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + unsigned so_offsets[D3D11_SO_BUFFER_SLOT_COUNT]; + D3D11_PRIMITIVE_TOPOLOGY primitive_topology; + DXGI_FORMAT index_format; + unsigned index_offset; + BOOL render_predicate_value; + float blend_color[4]; + unsigned sample_mask; + unsigned stencil_ref; + bool depth_clamp; + + void* default_input_layout; + void* default_rasterizer; + void* default_depth_stencil; + void* default_blend; + void* default_sampler; + void* ld_sampler; + void * default_shaders[D3D11_STAGES]; + + // derived state + int primitive_mode; + struct pipe_vertex_buffer vertex_buffers[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; + struct pipe_resource* so_buffers[D3D11_SO_BUFFER_SLOT_COUNT]; + struct pipe_sampler_view* sampler_views[D3D11_STAGES][D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; + struct + { + void* ld; // accessed with a -1 index from v + void* v[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; + } sampler_csos[D3D11_STAGES]; + struct pipe_resource * buffers[D3D11_SO_BUFFER_SLOT_COUNT]; + unsigned num_shader_resource_views[D3D11_STAGES]; + unsigned num_samplers[D3D11_STAGES]; + unsigned num_vertex_buffers; + unsigned num_render_target_views; + unsigned num_viewports; + unsigned num_scissor_rects; + unsigned num_so_targets; + + struct pipe_context* pipe; + unsigned update_flags; + + bool owns_pipe; + unsigned context_flags; + + GalliumD3D11Caps caps; + + cso_context* cso_ctx; + gen_mipmap_state* gen_mipmap; + +#if API >= 11 +#define SYNCHRONIZED do {} while(0) + + GalliumD3D11DeviceContext(GalliumD3D11Screen* device, pipe_context* pipe, bool owns_pipe, unsigned context_flags = 0) + : GalliumD3D11DeviceChild(device), pipe(pipe), owns_pipe(owns_pipe), context_flags(context_flags) + { + caps = device->screen_caps; + init_context(); + } + + ~GalliumD3D11DeviceContext() + { + destroy_context(); + } +#else +#define SYNCHRONIZED lock_t<maybe_mutex_t<threadsafe> > lock_(this->mutex) + + GalliumD3D10Device(pipe_screen* screen, pipe_context* pipe, bool owns_pipe, unsigned creation_flags, IDXGIAdapter* adapter) + : GalliumD3D10ScreenImpl<threadsafe>(screen, pipe, owns_pipe, creation_flags, adapter), pipe(pipe), owns_pipe(owns_pipe), context_flags(0) + { + caps = this->screen_caps; + init_context(); + } + + ~GalliumD3D10Device() + { + destroy_context(); + } +#endif + + void init_context() + { + if(!pipe->begin_query) + caps.queries = false; + if(!pipe->render_condition) + caps.render_condition = false; + if(!pipe->bind_gs_state) + { + caps.gs = false; + caps.stages = 2; + } + if(!pipe->set_stream_output_buffers) + caps.so = false; + + update_flags = 0; + + // pipeline state + memset(viewports, 0, sizeof(viewports)); + memset(scissor_rects, 0, sizeof(scissor_rects)); + memset(so_offsets, 0, sizeof(so_offsets)); + primitive_topology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + index_format = DXGI_FORMAT_UNKNOWN; + index_offset = 0; + render_predicate_value = 0; + memset(blend_color, 0, sizeof(blend_color)); + sample_mask = ~0; + stencil_ref = 0; + depth_clamp = 0; + + // derived state + primitive_mode = 0; + memset(vertex_buffers, 0, sizeof(vertex_buffers)); + memset(so_buffers, 0, sizeof(so_buffers)); + memset(sampler_views, 0, sizeof(sampler_views)); + memset(sampler_csos, 0, sizeof(sampler_csos)); + memset(num_shader_resource_views, 0, sizeof(num_shader_resource_views)); + memset(num_samplers, 0, sizeof(num_samplers)); + num_vertex_buffers = 0; + num_render_target_views = 0; + num_viewports = 0; + num_scissor_rects = 0; + num_so_targets = 0; + + default_input_layout = pipe->create_vertex_elements_state(pipe, 0, 0); + + struct pipe_rasterizer_state rasterizerd; + memset(&rasterizerd, 0, sizeof(rasterizerd)); + rasterizerd.gl_rasterization_rules = 1; + rasterizerd.cull_face = PIPE_FACE_BACK; + default_rasterizer = pipe->create_rasterizer_state(pipe, &rasterizerd); + + struct pipe_depth_stencil_alpha_state depth_stencild; + memset(&depth_stencild, 0, sizeof(depth_stencild)); + depth_stencild.depth.enabled = TRUE; + depth_stencild.depth.writemask = 1; + depth_stencild.depth.func = PIPE_FUNC_LESS; + default_depth_stencil = pipe->create_depth_stencil_alpha_state(pipe, &depth_stencild); + + struct pipe_blend_state blendd; + memset(&blendd, 0, sizeof(blendd)); + blendd.rt[0].colormask = 0xf; + default_blend = pipe->create_blend_state(pipe, &blendd); + + struct pipe_sampler_state samplerd; + memset(&samplerd, 0, sizeof(samplerd)); + samplerd.normalized_coords = 1; + samplerd.min_img_filter = PIPE_TEX_FILTER_LINEAR; + samplerd.mag_img_filter = PIPE_TEX_FILTER_LINEAR; + samplerd.min_mip_filter = PIPE_TEX_MIPFILTER_LINEAR; + samplerd.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samplerd.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samplerd.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + samplerd.border_color[0] = 1.0f; + samplerd.border_color[1] = 1.0f; + samplerd.border_color[2] = 1.0f; + samplerd.border_color[3] = 1.0f; + samplerd.min_lod = -FLT_MAX; + samplerd.max_lod = FLT_MAX; + samplerd.max_anisotropy = 1; + default_sampler = pipe->create_sampler_state(pipe, &samplerd); + + memset(&samplerd, 0, sizeof(samplerd)); + samplerd.normalized_coords = 0; + samplerd.min_img_filter = PIPE_TEX_FILTER_NEAREST; + samplerd.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + samplerd.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + samplerd.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_BORDER; + samplerd.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_BORDER; + samplerd.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_BORDER; + samplerd.min_lod = -FLT_MAX; + samplerd.max_lod = FLT_MAX; + samplerd.max_anisotropy = 1; + ld_sampler = pipe->create_sampler_state(pipe, &samplerd); + + for(unsigned s = 0; s < D3D11_STAGES; ++s) + { + sampler_csos[s].ld = ld_sampler; + for(unsigned i = 0; i < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; ++i) + sampler_csos[s].v[i] = default_sampler; + } + + // TODO: should this really be empty shaders, or should they be all-passthrough? + memset(default_shaders, 0, sizeof(default_shaders)); + struct ureg_program *ureg; + ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); + ureg_END(ureg); + default_shaders[PIPE_SHADER_FRAGMENT] = ureg_create_shader_and_destroy(ureg, pipe); + + ureg = ureg_create(TGSI_PROCESSOR_VERTEX); + ureg_END(ureg); + default_shaders[PIPE_SHADER_VERTEX] = ureg_create_shader_and_destroy(ureg, pipe); + + cso_ctx = cso_create_context(pipe); + gen_mipmap = util_create_gen_mipmap(pipe, cso_ctx); + + RestoreGalliumState(); + } + + void destroy_context() + { + util_destroy_gen_mipmap(gen_mipmap); + cso_destroy_context(cso_ctx); + pipe->delete_vertex_elements_state(pipe, default_input_layout); + pipe->delete_rasterizer_state(pipe, default_rasterizer); + pipe->delete_depth_stencil_alpha_state(pipe, default_depth_stencil); + pipe->delete_blend_state(pipe, default_blend); + pipe->delete_sampler_state(pipe, default_sampler); + pipe->delete_sampler_state(pipe, ld_sampler); + pipe->delete_fs_state(pipe, default_shaders[PIPE_SHADER_FRAGMENT]); + pipe->delete_vs_state(pipe, default_shaders[PIPE_SHADER_VERTEX]); + if(owns_pipe) + pipe->destroy(pipe); + } + + virtual unsigned STDMETHODCALLTYPE GetContextFlags(void) + { + return context_flags; + } +#if API >= 11 +#define SET_SHADER_EXTRA_ARGS , \ + __in_ecount_opt(NumClassInstances) ID3D11ClassInstance *const *ppClassInstances, \ + unsigned NumClassInstances +#define GET_SHADER_EXTRA_ARGS , \ + __out_ecount_opt(*pNumClassInstances) ID3D11ClassInstance **ppClassInstances, \ + __inout_opt unsigned *pNumClassInstances +#else +#define SET_SHADER_EXTRA_ARGS +#define GET_SHADER_EXTRA_ARGS +#endif + +/* On Windows D3D11, SetConstantBuffers and SetShaderResources crash if passed a null pointer. + * Instead, you have to pass a pointer to nulls to unbind things. + * We do the same. + * TODO: is D3D10 the same? + */ + template<unsigned s> + void xs_set_shader(GalliumD3D11Shader<>* shader) + { + if(shader != shaders[s].p) + { + shaders[s] = shader; + void* shader_cso = shader ? shader->object : default_shaders[s]; + switch(s) + { + case PIPE_SHADER_VERTEX: + pipe->bind_vs_state(pipe, shader_cso); + break; + case PIPE_SHADER_FRAGMENT: + pipe->bind_fs_state(pipe, shader_cso); + break; + case PIPE_SHADER_GEOMETRY: + pipe->bind_gs_state(pipe, shader_cso); + break; + } + update_flags |= (1 << (UPDATE_SAMPLERS_SHIFT + s)) | (1 << (UPDATE_VIEWS_SHIFT + s)); + } + } + + template<unsigned s> + void xs_set_constant_buffers(unsigned start, unsigned count, GalliumD3D11Buffer *const *constbufs) + { + for(unsigned i = 0; i < count; ++i) + { + if(constbufs[i] != constant_buffers[s][i].p) + { + constant_buffers[s][i] = constbufs[i]; + if(s < caps.stages && start + i < caps.constant_buffers[s]) + pipe->set_constant_buffer(pipe, s, start + i, constbufs[i] ? constbufs[i]->resource : NULL); + } + } + } + + template<unsigned s> + void xs_set_shader_resources(unsigned start, unsigned count, GalliumD3D11ShaderResourceView *const *srvs) + { + int last_different = -1; + for(unsigned i = 0; i < count; ++i) + { + if(shader_resource_views[s][start + i].p != srvs[i]) + { + shader_resource_views[s][start + i] = srvs[i]; + sampler_views[s][start + i] = srvs[i] ? srvs[i]->object : 0; + last_different = i; + } + } + if(last_different >= 0) + { + num_shader_resource_views[s] = std::max(num_shader_resource_views[s], start + last_different + 1); + update_flags |= 1 << (UPDATE_VIEWS_SHIFT + s); + } + } + + template<unsigned s> + void xs_set_samplers(unsigned start, unsigned count, GalliumD3D11SamplerState *const *samps) + { + int last_different = -1; + for(unsigned i = 0; i < count; ++i) + { + if(samplers[s][start + i].p != samps[i]) + { + samplers[s][start + i] = samps[i]; + sampler_csos[s].v[start + i] = samps[i] ? samps[i]->object : default_sampler; + } + if(last_different >= 0) + { + num_samplers[s] = std::max(num_samplers[s], start + last_different + 1); + update_flags |= (UPDATE_SAMPLERS_SHIFT + s); + } + } + } + +#define IMPLEMENT_SHADER_STAGE(XS, Stage) \ + virtual void STDMETHODCALLTYPE XS##SetShader( \ + __in_opt ID3D11##Stage##Shader *pShader \ + SET_SHADER_EXTRA_ARGS) \ + { \ + SYNCHRONIZED; \ + xs_set_shader<D3D11_STAGE_##XS>((GalliumD3D11Shader<>*)pShader); \ + } \ + virtual void STDMETHODCALLTYPE XS##GetShader(\ + __out ID3D11##Stage##Shader **ppShader \ + GET_SHADER_EXTRA_ARGS) \ + { \ + SYNCHRONIZED; \ + *ppShader = (ID3D11##Stage##Shader*)shaders[D3D11_STAGE_##XS].ref(); \ + } \ + virtual void STDMETHODCALLTYPE XS##SetConstantBuffers(\ + __in_range(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) unsigned StartSlot, \ + __in_range(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) unsigned NumBuffers, \ + __in_ecount(NumBuffers) ID3D11Buffer *const *ppConstantBuffers) \ + { \ + SYNCHRONIZED; \ + xs_set_constant_buffers<D3D11_STAGE_##XS>(StartSlot, NumBuffers, (GalliumD3D11Buffer *const *)ppConstantBuffers); \ + } \ + virtual void STDMETHODCALLTYPE XS##GetConstantBuffers(\ + __in_range(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - 1) unsigned StartSlot, \ + __in_range(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - StartSlot) unsigned NumBuffers, \ + __out_ecount(NumBuffers) ID3D11Buffer **ppConstantBuffers) \ + { \ + SYNCHRONIZED; \ + for(unsigned i = 0; i < NumBuffers; ++i) \ + ppConstantBuffers[i] = constant_buffers[D3D11_STAGE_##XS][StartSlot + i].ref(); \ + } \ + virtual void STDMETHODCALLTYPE XS##SetShaderResources(\ + __in_range(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) unsigned StartSlot, \ + __in_range(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) unsigned NumViews, \ + __in_ecount(NumViews) ID3D11ShaderResourceView *const *ppShaderResourceViews) \ + { \ + SYNCHRONIZED; \ + xs_set_shader_resources<D3D11_STAGE_##XS>(StartSlot, NumViews, (GalliumD3D11ShaderResourceView *const *)ppShaderResourceViews); \ + } \ + virtual void STDMETHODCALLTYPE XS##GetShaderResources(\ + __in_range(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - 1) unsigned StartSlot, \ + __in_range(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT - StartSlot) unsigned NumViews, \ + __out_ecount(NumViews) ID3D11ShaderResourceView **ppShaderResourceViews) \ + { \ + SYNCHRONIZED; \ + for(unsigned i = 0; i < NumViews; ++i) \ + ppShaderResourceViews[i] = shader_resource_views[D3D11_STAGE_##XS][StartSlot + i].ref(); \ + } \ + virtual void STDMETHODCALLTYPE XS##SetSamplers(\ + __in_range(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) unsigned StartSlot, \ + __in_range(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) unsigned NumSamplers, \ + __in_ecount(NumSamplers) ID3D11SamplerState *const *ppSamplers) \ + { \ + SYNCHRONIZED; \ + xs_set_samplers<D3D11_STAGE_##XS>(StartSlot, NumSamplers, (GalliumD3D11SamplerState *const *)ppSamplers); \ + } \ + virtual void STDMETHODCALLTYPE XS##GetSamplers( \ + __in_range(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - 1) unsigned StartSlot, \ + __in_range(0, D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT - StartSlot) unsigned NumSamplers, \ + __out_ecount(NumSamplers) ID3D11SamplerState **ppSamplers) \ + { \ + SYNCHRONIZED; \ + for(unsigned i = 0; i < NumSamplers; ++i) \ + ppSamplers[i] = samplers[D3D11_STAGE_##XS][StartSlot + i].ref(); \ + } + +#define DO_VS(x) x +#define DO_GS(x) do {if(caps.gs) {x;}} while(0) +#define DO_PS(x) x +#define DO_HS(x) +#define DO_DS(x) +#define DO_CS(x) + IMPLEMENT_SHADER_STAGE(VS, Vertex) + IMPLEMENT_SHADER_STAGE(GS, Geometry) + IMPLEMENT_SHADER_STAGE(PS, Pixel) + +#if API >= 11 + IMPLEMENT_SHADER_STAGE(HS, Hull) + IMPLEMENT_SHADER_STAGE(DS, Domain) + IMPLEMENT_SHADER_STAGE(CS, Compute) + + virtual void STDMETHODCALLTYPE CSSetUnorderedAccessViews( + __in_range(0, D3D11_PS_CS_UAV_REGISTER_COUNT - 1) unsigned StartSlot, + __in_range(0, D3D11_PS_CS_UAV_REGISTER_COUNT - StartSlot) unsigned NumUAVs, + __in_ecount(NumUAVs) ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, + __in_ecount(NumUAVs) const unsigned *pUAVInitialCounts) + { + SYNCHRONIZED; + for(unsigned i = 0; i < NumUAVs; ++i) + cs_unordered_access_views[StartSlot + i] = ppUnorderedAccessViews[i]; + } + + virtual void STDMETHODCALLTYPE CSGetUnorderedAccessViews( + __in_range(0, D3D11_PS_CS_UAV_REGISTER_COUNT - 1) unsigned StartSlot, + __in_range(0, D3D11_PS_CS_UAV_REGISTER_COUNT - StartSlot) unsigned NumUAVs, + __out_ecount(NumUAVs) ID3D11UnorderedAccessView **ppUnorderedAccessViews) + { + SYNCHRONIZED; + for(unsigned i = 0; i < NumUAVs; ++i) + ppUnorderedAccessViews[i] = cs_unordered_access_views[StartSlot + i].ref(); + } +#endif + + template<unsigned s> + void update_stage() + { + if(update_flags & (1 << (UPDATE_VIEWS_SHIFT + s))) + { + while(num_shader_resource_views[s] && !sampler_views[s][num_shader_resource_views[s] - 1]) \ + --num_shader_resource_views[s]; + if(s < caps.stages) + { + struct pipe_sampler_view* views_to_bind[PIPE_MAX_SAMPLERS]; + unsigned num_views_to_bind = shaders[s] ? shaders[s]->slot_to_resource.size() : 0; + for(unsigned i = 0; i < num_views_to_bind; ++i) + { + views_to_bind[i] = sampler_views[s][shaders[s]->slot_to_resource[i]]; + } + switch(s) + { + case PIPE_SHADER_VERTEX: + pipe->set_vertex_sampler_views(pipe, num_views_to_bind, views_to_bind); + break; + case PIPE_SHADER_FRAGMENT: + pipe->set_fragment_sampler_views(pipe, num_views_to_bind, views_to_bind); + break; + case PIPE_SHADER_GEOMETRY: + pipe->set_geometry_sampler_views(pipe, num_views_to_bind, views_to_bind); + break; + } + } + } + + if(update_flags & (1 << (UPDATE_SAMPLERS_SHIFT + s))) + { + while(num_samplers[s] && !sampler_csos[s].v[num_samplers[s] - 1]) + --num_samplers[s]; + if(s < caps.stages) + { + void* samplers_to_bind[PIPE_MAX_SAMPLERS]; + unsigned num_samplers_to_bind = shaders[s] ? shaders[s]->slot_to_sampler.size() : 0; + for(unsigned i = 0; i < num_samplers_to_bind; ++i) + { + // index can be -1 to access sampler_csos[s].ld + samplers_to_bind[i] = *(sampler_csos[s].v + shaders[s]->slot_to_sampler[i]); + } + switch(s) + { + case PIPE_SHADER_VERTEX: + pipe->bind_vertex_sampler_states(pipe, num_samplers_to_bind, samplers_to_bind); + break; + case PIPE_SHADER_FRAGMENT: + pipe->bind_fragment_sampler_states(pipe, num_samplers_to_bind, samplers_to_bind); + break; + case PIPE_SHADER_GEOMETRY: + pipe->bind_geometry_sampler_states(pipe, num_samplers_to_bind, samplers_to_bind); + break; + } + } + } + } + + void update_state() + { + update_stage<D3D11_STAGE_PS>(); + update_stage<D3D11_STAGE_VS>(); + update_stage<D3D11_STAGE_GS>(); +#if API >= 11 + update_stage<D3D11_STAGE_HS>(); + update_stage<D3D11_STAGE_DS>(); + update_stage<D3D11_STAGE_CS>(); +#endif + + if(update_flags & UPDATE_VERTEX_BUFFERS) + { + while(num_vertex_buffers && !vertex_buffers[num_vertex_buffers - 1].buffer) + --num_vertex_buffers; + pipe->set_vertex_buffers(pipe, num_vertex_buffers, vertex_buffers); + } + + update_flags = 0; + } + + virtual void STDMETHODCALLTYPE IASetInputLayout( + __in_opt ID3D11InputLayout *pInputLayout) + { + SYNCHRONIZED; + if(pInputLayout != input_layout.p) + { + input_layout = pInputLayout; + pipe->bind_vertex_elements_state(pipe, pInputLayout ? ((GalliumD3D11InputLayout*)pInputLayout)->object : default_input_layout); + } + } + + virtual void STDMETHODCALLTYPE IAGetInputLayout( + __out ID3D11InputLayout **ppInputLayout) + { + SYNCHRONIZED; + *ppInputLayout = input_layout.ref(); + } + + virtual void STDMETHODCALLTYPE IASetVertexBuffers( + __in_range(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - 1) unsigned StartSlot, + __in_range(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - StartSlot) unsigned NumBuffers, + __in_ecount(NumBuffers) ID3D11Buffer *const *ppVertexBuffers, + __in_ecount(NumBuffers) const unsigned *pStrides, + __in_ecount(NumBuffers) const unsigned *pOffsets) + { + SYNCHRONIZED; + int last_different = -1; + for(unsigned i = 0; i < NumBuffers; ++i) + { + ID3D11Buffer* buffer = ppVertexBuffers[i]; + if(buffer != input_buffers[StartSlot + i].p + || vertex_buffers[StartSlot + i].buffer_offset != pOffsets[i] + || vertex_buffers[StartSlot + i].stride != pOffsets[i] + ) + { + input_buffers[StartSlot + i] = buffer; + vertex_buffers[StartSlot + i].buffer = buffer ? ((GalliumD3D11Buffer*)buffer)->resource : 0; + vertex_buffers[StartSlot + i].buffer_offset = pOffsets[i]; + vertex_buffers[StartSlot + i].stride = pStrides[i]; + vertex_buffers[StartSlot + i].max_index = ~0; + last_different = i; + } + } + if(last_different >= 0) + { + num_vertex_buffers = std::max(num_vertex_buffers, StartSlot + NumBuffers); + update_flags |= UPDATE_VERTEX_BUFFERS; + } + } + + virtual void STDMETHODCALLTYPE IAGetVertexBuffers( + __in_range(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - 1) unsigned StartSlot, + __in_range(0, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - StartSlot) unsigned NumBuffers, + __out_ecount_opt(NumBuffers) ID3D11Buffer **ppVertexBuffers, + __out_ecount_opt(NumBuffers) unsigned *pStrides, + __out_ecount_opt(NumBuffers) unsigned *pOffsets) + { + SYNCHRONIZED; + if(ppVertexBuffers) + { + for(unsigned i = 0; i < NumBuffers; ++i) + ppVertexBuffers[i] = input_buffers[StartSlot + i].ref(); + } + + if(pOffsets) + { + for(unsigned i = 0; i < NumBuffers; ++i) + pOffsets[i] = vertex_buffers[StartSlot + i].buffer_offset; + } + + if(pStrides) + { + for(unsigned i = 0; i < NumBuffers; ++i) + pStrides[i] = vertex_buffers[StartSlot + i].stride; + } + } + + void set_index_buffer() + { + pipe_index_buffer ib; + if(!index_buffer) + { + memset(&ib, 0, sizeof(ib)); + } + else + { + if(index_format == DXGI_FORMAT_R32_UINT) + ib.index_size = 4; + else if(index_format == DXGI_FORMAT_R16_UINT) + ib.index_size = 2; + else + ib.index_size = 1; + ib.offset = index_offset; + ib.buffer = index_buffer ? ((GalliumD3D11Buffer*)index_buffer.p)->resource : 0; + } + pipe->set_index_buffer(pipe, &ib); + } + + virtual void STDMETHODCALLTYPE IASetIndexBuffer( + __in_opt ID3D11Buffer *pIndexBuffer, + __in DXGI_FORMAT Format, + __in unsigned Offset) + { + SYNCHRONIZED; + if(index_buffer.p != pIndexBuffer || index_format != Format || index_offset != Offset) + { + index_buffer = pIndexBuffer; + index_format = Format; + index_offset = Offset; + + set_index_buffer(); + } + } + + virtual void STDMETHODCALLTYPE IAGetIndexBuffer( + __out_opt ID3D11Buffer **pIndexBuffer, + __out_opt DXGI_FORMAT *Format, + __out_opt unsigned *Offset) + { + SYNCHRONIZED; + if(pIndexBuffer) + *pIndexBuffer = index_buffer.ref(); + if(Format) + *Format = index_format; + if(Offset) + *Offset = index_offset; + } + + virtual void STDMETHODCALLTYPE IASetPrimitiveTopology( + __in D3D11_PRIMITIVE_TOPOLOGY Topology) + { + SYNCHRONIZED; + if(primitive_topology != Topology) + { + if(Topology < D3D_PRIMITIVE_TOPOLOGY_COUNT) + primitive_mode = d3d_to_pipe_prim[Topology]; + else + primitive_mode = 0; + primitive_topology = Topology; + } + } + + virtual void STDMETHODCALLTYPE IAGetPrimitiveTopology( + __out D3D11_PRIMITIVE_TOPOLOGY *pTopology) + { + SYNCHRONIZED; + *pTopology = primitive_topology; + } + + virtual void STDMETHODCALLTYPE DrawIndexed( + __in unsigned IndexCount, + __in unsigned StartIndexLocation, + __in int BaseVertexLocation) + { + SYNCHRONIZED; + if(update_flags) + update_state(); + + pipe_draw_info info; + info.mode = primitive_mode; + info.indexed = TRUE; + info.count = IndexCount; + info.start = StartIndexLocation; + info.index_bias = BaseVertexLocation; + info.min_index = 0; + info.max_index = ~0; + info.start_instance = 0; + info.instance_count = 1; + + pipe->draw_vbo(pipe, &info); + } + + virtual void STDMETHODCALLTYPE Draw( + __in unsigned VertexCount, + __in unsigned StartVertexLocation) + { + SYNCHRONIZED; + if(update_flags) + update_state(); + + pipe_draw_info info; + info.mode = primitive_mode; + info.indexed = FALSE; + info.count = VertexCount; + info.start = StartVertexLocation; + info.index_bias = 0; + info.min_index = 0; + info.max_index = ~0; + info.start_instance = 0; + info.instance_count = 1; + + pipe->draw_vbo(pipe, &info); + } + + virtual void STDMETHODCALLTYPE DrawIndexedInstanced( + __in unsigned IndexCountPerInstance, + __in unsigned InstanceCount, + __in unsigned StartIndexLocation, + __in int BaseVertexLocation, + __in unsigned StartInstanceLocation) + { + SYNCHRONIZED; + if(update_flags) + update_state(); + + pipe_draw_info info; + info.mode = primitive_mode; + info.indexed = TRUE; + info.count = IndexCountPerInstance; + info.start = StartIndexLocation; + info.index_bias = BaseVertexLocation; + info.min_index = 0; + info.max_index = ~0; + info.start_instance = StartInstanceLocation; + info.instance_count = InstanceCount; + + pipe->draw_vbo(pipe, &info); + } + + virtual void STDMETHODCALLTYPE DrawInstanced( + __in unsigned VertexCountPerInstance, + __in unsigned InstanceCount, + __in unsigned StartVertexLocation, + __in unsigned StartInstanceLocation) + { + SYNCHRONIZED; + if(update_flags) + update_state(); + + pipe_draw_info info; + info.mode = primitive_mode; + info.indexed = FALSE; + info.count = VertexCountPerInstance; + info.start = StartVertexLocation; + info.index_bias = 0; + info.min_index = 0; + info.max_index = ~0; + info.start_instance = StartInstanceLocation; + info.instance_count = InstanceCount; + + pipe->draw_vbo(pipe, &info); + } + + virtual void STDMETHODCALLTYPE DrawAuto(void) + { + if(!caps.so) + return; + + SYNCHRONIZED; + if(update_flags) + update_state(); + + pipe->draw_stream_output(pipe, primitive_mode); + } + + virtual void STDMETHODCALLTYPE DrawIndexedInstancedIndirect( + __in ID3D11Buffer *pBufferForArgs, + __in unsigned AlignedByteOffsetForArgs) + { + SYNCHRONIZED; + if(update_flags) + update_state(); + + struct { + unsigned count; + unsigned instance_count; + unsigned start; + unsigned index_bias; + } data; + + pipe_buffer_read(pipe, ((GalliumD3D11Buffer*)pBufferForArgs)->resource, AlignedByteOffsetForArgs, sizeof(data), &data); + + pipe_draw_info info; + info.mode = primitive_mode; + info.indexed = TRUE; + info.start = data.start; + info.count = data.count; + info.index_bias = data.index_bias; + info.min_index = 0; + info.max_index = ~0; + info.start_instance = 0; + info.instance_count = data.instance_count; + + pipe->draw_vbo(pipe, &info); + } + + virtual void STDMETHODCALLTYPE DrawInstancedIndirect( + __in ID3D11Buffer *pBufferForArgs, + __in unsigned AlignedByteOffsetForArgs) + { + SYNCHRONIZED; + if(update_flags) + update_state(); + + struct { + unsigned count; + unsigned instance_count; + unsigned start; + } data; + + pipe_buffer_read(pipe, ((GalliumD3D11Buffer*)pBufferForArgs)->resource, AlignedByteOffsetForArgs, sizeof(data), &data); + + pipe_draw_info info; + info.mode = primitive_mode; + info.indexed = FALSE; + info.start = data.start; + info.count = data.count; + info.index_bias = 0; + info.min_index = 0; + info.max_index = ~0; + info.start_instance = 0; + info.instance_count = data.instance_count; + + pipe->draw_vbo(pipe, &info); + } + +#if API >= 11 + virtual void STDMETHODCALLTYPE Dispatch( + __in unsigned ThreadGroupCountX, + __in unsigned ThreadGroupCountY, + __in unsigned ThreadGroupCountZ) + { +// uncomment this when this is implemented +// SYNCHRONIZED; +// if(update_flags) +// update_state(); + } + + virtual void STDMETHODCALLTYPE DispatchIndirect( + __in ID3D11Buffer *pBufferForArgs, + __in unsigned AlignedByteOffsetForArgs) + { +// uncomment this when this is implemented +// SYNCHRONIZED; +// if(update_flags) +// update_state(); + } +#endif + + void set_clip() + { + SYNCHRONIZED; + pipe_clip_state clip; + clip.nr = 0; + clip.depth_clamp = depth_clamp; + pipe->set_clip_state(pipe, &clip); + } + + virtual void STDMETHODCALLTYPE RSSetState( + __in_opt ID3D11RasterizerState *pRasterizerState) + { + SYNCHRONIZED; + if(pRasterizerState != rasterizer_state.p) + { + rasterizer_state = pRasterizerState; + pipe->bind_rasterizer_state(pipe, pRasterizerState ? ((GalliumD3D11RasterizerState*)pRasterizerState)->object : default_rasterizer); + bool new_depth_clamp = pRasterizerState ? ((GalliumD3D11RasterizerState*)pRasterizerState)->depth_clamp : false; + if(depth_clamp != new_depth_clamp) + { + depth_clamp = new_depth_clamp; + set_clip(); + } + } + } + + virtual void STDMETHODCALLTYPE RSGetState( + __out ID3D11RasterizerState **ppRasterizerState) + { + SYNCHRONIZED; + *ppRasterizerState = rasterizer_state.ref(); + } + + void set_viewport() + { + // TODO: is depth correct? it seems D3D10/11 uses a [-1,1]x[-1,1]x[0,1] cube + pipe_viewport_state viewport; + float half_width = viewports[0].Width * 0.5f; + float half_height = viewports[0].Height * 0.5f; + + viewport.scale[0] = half_width; + viewport.scale[1] = -half_height; + viewport.scale[2] = (viewports[0].MaxDepth - viewports[0].MinDepth); + viewport.scale[3] = 1.0f; + viewport.translate[0] = half_width + viewports[0].TopLeftX; + viewport.translate[1] = half_height + viewports[0].TopLeftY; + viewport.translate[2] = viewports[0].MinDepth; + viewport.translate[3] = 1.0f; + pipe->set_viewport_state(pipe, &viewport); + } + + virtual void STDMETHODCALLTYPE RSSetViewports( + __in_range(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) unsigned NumViewports, + __in_ecount_opt(NumViewports) const D3D11_VIEWPORT *pViewports) + { + SYNCHRONIZED; + if(NumViewports) + { + if(memcmp(&viewports[0], &pViewports[0], sizeof(viewports[0]))) + { + viewports[0] = pViewports[0]; + set_viewport(); + } + for(unsigned i = 1; i < NumViewports; ++i) + viewports[i] = pViewports[i]; + } + else if(num_viewports) + { + // TODO: what should we do here? + memset(&viewports[0], 0, sizeof(viewports[0])); + set_viewport(); + } + num_viewports = NumViewports; + } + + virtual void STDMETHODCALLTYPE RSGetViewports( + __inout_range(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) unsigned *pNumViewports, + __out_ecount_opt(*pNumViewports) D3D11_VIEWPORT *pViewports) + { + SYNCHRONIZED; + if(pViewports) + { + unsigned i; + for(i = 0; i < std::min(*pNumViewports, num_viewports); ++i) + pViewports[i] = viewports[i]; + + memset(pViewports + i, 0, (*pNumViewports - i) * sizeof(D3D11_VIEWPORT)); + } + + *pNumViewports = num_viewports; + } + + void set_scissor() + { + pipe_scissor_state scissor; + scissor.minx = scissor_rects[0].left; + scissor.miny = scissor_rects[0].top; + scissor.maxx = scissor_rects[0].right; + scissor.maxy = scissor_rects[0].bottom; + pipe->set_scissor_state(pipe, &scissor); + } + + virtual void STDMETHODCALLTYPE RSSetScissorRects( + __in_range(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) unsigned NumRects, + __in_ecount_opt(NumRects) const D3D11_RECT *pRects) + { + SYNCHRONIZED; + if(NumRects) + { + if(memcmp(&scissor_rects[0], &pRects[0], sizeof(scissor_rects[0]))) + { + scissor_rects[0] = pRects[0]; + set_scissor(); + } + for(unsigned i = 1; i < NumRects; ++i) + scissor_rects[i] = pRects[i]; + } + else if(num_scissor_rects) + { + // TODO: what should we do here? + memset(&scissor_rects[0], 0, sizeof(scissor_rects[0])); + set_scissor(); + } + + num_scissor_rects = NumRects; + } + + virtual void STDMETHODCALLTYPE RSGetScissorRects( + __inout_range(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) unsigned *pNumRects, + __out_ecount_opt(*pNumRects) D3D11_RECT *pRects) + { + SYNCHRONIZED; + if(pRects) + { + unsigned i; + for(i = 0; i < std::min(*pNumRects, num_scissor_rects); ++i) + pRects[i] = scissor_rects[i]; + + memset(pRects + i, 0, (*pNumRects - i) * sizeof(D3D11_RECT)); + } + + *pNumRects = num_scissor_rects; + } + + virtual void STDMETHODCALLTYPE OMSetBlendState( + __in_opt ID3D11BlendState *pBlendState, + __in_opt const float BlendFactor[ 4 ], + __in unsigned SampleMask) + { + SYNCHRONIZED; + float white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + if(blend_state.p != pBlendState) + { + pipe->bind_blend_state(pipe, pBlendState ? ((GalliumD3D11BlendState*)pBlendState)->object : default_blend); + blend_state = pBlendState; + } + + // Windows D3D11 does this, even though it's apparently undocumented + if(!BlendFactor) + BlendFactor = white; + + if(memcmp(blend_color, BlendFactor, sizeof(blend_color))) + { + pipe->set_blend_color(pipe, (struct pipe_blend_color*)BlendFactor); + memcpy(blend_color, BlendFactor, sizeof(blend_color)); + } + + if(sample_mask != SampleMask) + { + pipe->set_sample_mask(pipe, sample_mask); + sample_mask = SampleMask; + } + } + + virtual void STDMETHODCALLTYPE OMGetBlendState( + __out_opt ID3D11BlendState **ppBlendState, + __out_opt float BlendFactor[ 4 ], + __out_opt unsigned *pSampleMask) + { + SYNCHRONIZED; + if(ppBlendState) + *ppBlendState = blend_state.ref(); + if(BlendFactor) + memcpy(BlendFactor, blend_color, sizeof(blend_color)); + if(pSampleMask) + *pSampleMask = sample_mask; + } + + void set_stencil_ref() + { + struct pipe_stencil_ref sref; + sref.ref_value[0] = stencil_ref; + sref.ref_value[1] = stencil_ref; + pipe->set_stencil_ref(pipe, &sref); + } + + virtual void STDMETHODCALLTYPE OMSetDepthStencilState( + __in_opt ID3D11DepthStencilState *pDepthStencilState, + __in unsigned StencilRef) + { + SYNCHRONIZED; + if(pDepthStencilState != depth_stencil_state.p) + { + pipe->bind_depth_stencil_alpha_state(pipe, pDepthStencilState ? ((GalliumD3D11DepthStencilState*)pDepthStencilState)->object : default_depth_stencil); + depth_stencil_state = pDepthStencilState; + } + + if(StencilRef != stencil_ref) + { + stencil_ref = StencilRef; + set_stencil_ref(); + } + } + + virtual void STDMETHODCALLTYPE OMGetDepthStencilState( + __out_opt ID3D11DepthStencilState **ppDepthStencilState, + __out_opt unsigned *pStencilRef) + { + SYNCHRONIZED; + if(*ppDepthStencilState) + *ppDepthStencilState = depth_stencil_state.ref(); + if(pStencilRef) + *pStencilRef = stencil_ref; + } + + void set_framebuffer() + { + struct pipe_framebuffer_state fb; + memset(&fb, 0, sizeof(fb)); + if(depth_stencil_view) + { + struct pipe_surface* surf = ((GalliumD3D11DepthStencilView*)depth_stencil_view.p)->object; + fb.zsbuf = surf; + if(surf->width > fb.width) + fb.width = surf->width; + if(surf->height > fb.height) + fb.height = surf->height; + } + fb.nr_cbufs = num_render_target_views; + unsigned i; + for(i = 0; i < num_render_target_views; ++i) + { + if(render_target_views[i]) + { + struct pipe_surface* surf = ((GalliumD3D11RenderTargetView*)render_target_views[i].p)->object; + fb.cbufs[i] = surf; + if(surf->width > fb.width) + fb.width = surf->width; + if(surf->height > fb.height) + fb.height = surf->height; + } + } + + pipe->set_framebuffer_state(pipe, &fb); + } + + /* TODO: the docs say that we should unbind conflicting resources (e.g. those bound for read while we are binding them for write too), but we aren't. + * Hopefully nobody relies on this happening + */ + + virtual void STDMETHODCALLTYPE OMSetRenderTargets( + __in_range(0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT) unsigned NumViews, + __in_ecount_opt(NumViews) ID3D11RenderTargetView *const *ppRenderTargetViews, + __in_opt ID3D11DepthStencilView *pDepthStencilView) + { + SYNCHRONIZED; + if(!ppRenderTargetViews) + NumViews = 0; + if(NumViews == num_render_target_views) + { + for(unsigned i = 0; i < NumViews; ++i) + { + if(ppRenderTargetViews[i] != render_target_views[i].p) + goto changed; + } + return; + } +changed: + depth_stencil_view = pDepthStencilView; + unsigned i; + for(i = 0; i < NumViews; ++i) + { + render_target_views[i] = ppRenderTargetViews[i]; +#if API >= 11 + om_unordered_access_views[i] = (ID3D11UnorderedAccessView*)NULL; +#endif + } + for(; i < num_render_target_views; ++i) + render_target_views[i] = (ID3D11RenderTargetView*)NULL; + num_render_target_views = NumViews; + set_framebuffer(); + } + + virtual void STDMETHODCALLTYPE OMGetRenderTargets( + __in_range(0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT) unsigned NumViews, + __out_ecount_opt(NumViews) ID3D11RenderTargetView **ppRenderTargetViews, + __out_opt ID3D11DepthStencilView **ppDepthStencilView) + { + SYNCHRONIZED; + if(ppRenderTargetViews) + { + unsigned i; + for(i = 0; i < std::min(num_render_target_views, NumViews); ++i) + ppRenderTargetViews[i] = render_target_views[i].ref(); + + for(; i < NumViews; ++i) + ppRenderTargetViews[i] = 0; + } + + if(ppDepthStencilView) + *ppDepthStencilView = depth_stencil_view.ref(); + } + +#if API >= 11 + /* TODO: what is this supposed to do _exactly_? are we doing the right thing? */ + virtual void STDMETHODCALLTYPE OMSetRenderTargetsAndUnorderedAccessViews( + __in unsigned NumRTVs, + __in_ecount_opt(NumRTVs) ID3D11RenderTargetView *const *ppRenderTargetViews, + __in_opt ID3D11DepthStencilView *pDepthStencilView, + __in_range(0, D3D11_PS_CS_UAV_REGISTER_COUNT - 1) unsigned UAVStartSlot, + __in unsigned NumUAVs, + __in_ecount_opt(NumUAVs) ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, + __in_ecount_opt(NumUAVs) const unsigned *pUAVInitialCounts) + { + SYNCHRONIZED; + if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) + OMSetRenderTargets(NumRTVs, ppRenderTargetViews, pDepthStencilView); + + if(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS) + { + for(unsigned i = 0; i < NumUAVs; ++i) + { + om_unordered_access_views[UAVStartSlot + i] = ppUnorderedAccessViews[i]; + render_target_views[UAVStartSlot + i] = (ID3D11RenderTargetView*)0; + } + } + } + + virtual void STDMETHODCALLTYPE OMGetRenderTargetsAndUnorderedAccessViews( + __in_range(0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT) unsigned NumRTVs, + __out_ecount_opt(NumRTVs) ID3D11RenderTargetView **ppRenderTargetViews, + __out_opt ID3D11DepthStencilView **ppDepthStencilView, + __in_range(0, D3D11_PS_CS_UAV_REGISTER_COUNT - 1) unsigned UAVStartSlot, + __in_range(0, D3D11_PS_CS_UAV_REGISTER_COUNT - UAVStartSlot) unsigned NumUAVs, + __out_ecount_opt(NumUAVs) ID3D11UnorderedAccessView **ppUnorderedAccessViews) + { + SYNCHRONIZED; + if(ppRenderTargetViews) + OMGetRenderTargets(NumRTVs, ppRenderTargetViews, ppDepthStencilView); + + if(ppUnorderedAccessViews) + { + for(unsigned i = 0; i < NumUAVs; ++i) + ppUnorderedAccessViews[i] = om_unordered_access_views[UAVStartSlot + i].ref(); + } + } +#endif + + virtual void STDMETHODCALLTYPE SOSetTargets( + __in_range(0, D3D11_SO_BUFFER_SLOT_COUNT) unsigned NumBuffers, + __in_ecount_opt(NumBuffers) ID3D11Buffer *const *ppSOTargets, + __in_ecount_opt(NumBuffers) const unsigned *pOffsets) + { + SYNCHRONIZED; + unsigned i; + if(!ppSOTargets) + NumBuffers = 0; + bool changed = false; + for(i = 0; i < NumBuffers; ++i) + { + ID3D11Buffer* buffer = ppSOTargets[i]; + if(buffer != so_targets[i].p || pOffsets[i] != so_offsets[i]) + { + so_buffers[i] = buffer ? ((GalliumD3D11Buffer*)buffer)->resource : 0; + so_targets[i] = buffer; + so_offsets[i] = pOffsets[i]; + changed = true; + } + } + for(; i < D3D11_SO_BUFFER_SLOT_COUNT; ++i) + { + if(so_targets[i].p || so_offsets[i]) + { + changed = true; + so_targets[i] = (ID3D11Buffer*)0; + so_offsets[i] = 0; + } + } + num_so_targets = NumBuffers; + + if(changed && caps.so) + pipe->set_stream_output_buffers(pipe, so_buffers, (int*)so_offsets, num_so_targets); + } + + virtual void STDMETHODCALLTYPE SOGetTargets( + __in_range(0, D3D11_SO_BUFFER_SLOT_COUNT) unsigned NumBuffers, + __out_ecount(NumBuffers) ID3D11Buffer **ppSOTargets +#if API < 11 + , __out_ecount(NumBuffers) UINT *pOffsets +#endif + ) + { + SYNCHRONIZED; + for(unsigned i = 0; i < NumBuffers; ++i) + { + ppSOTargets[i] = so_targets[i].ref(); +#if API < 11 + pOffsets[i] = so_offsets[i]; +#endif + } + } + + virtual void STDMETHODCALLTYPE Begin( + __in ID3D11Asynchronous *pAsync) + { + SYNCHRONIZED; + if(caps.queries) + pipe->begin_query(pipe, ((GalliumD3D11Asynchronous<>*)pAsync)->query); + } + + virtual void STDMETHODCALLTYPE End( + __in ID3D11Asynchronous *pAsync) + { + SYNCHRONIZED; + if(caps.queries) + pipe->end_query(pipe, ((GalliumD3D11Asynchronous<>*)pAsync)->query); + } + + virtual HRESULT STDMETHODCALLTYPE GetData( + __in ID3D11Asynchronous *pAsync, + __out_bcount_opt(DataSize) void *pData, + __in unsigned DataSize, + __in unsigned GetDataFlags) + { + SYNCHRONIZED; + if(!caps.queries) + return E_NOTIMPL; + + GalliumD3D11Asynchronous<>* async = (GalliumD3D11Asynchronous<>*)pAsync; + void* data = alloca(async->data_size); + boolean ret = pipe->get_query_result(pipe, ((GalliumD3D11Asynchronous<>*)pAsync)->query, !(GetDataFlags & D3D11_ASYNC_GETDATA_DONOTFLUSH), data); + if(pData) + memcpy(pData, data, std::min(async->data_size, DataSize)); + return ret ? S_OK : S_FALSE; + } + + void set_render_condition() + { + if(caps.render_condition) + { + if(!render_predicate) + pipe->render_condition(pipe, 0, 0); + else + { + GalliumD3D11Predicate* predicate = (GalliumD3D11Predicate*)render_predicate.p; + if(!render_predicate_value && predicate->desc.Query == D3D11_QUERY_OCCLUSION_PREDICATE) + { + unsigned mode = (predicate->desc.MiscFlags & D3D11_QUERY_MISC_PREDICATEHINT) ? PIPE_RENDER_COND_NO_WAIT : PIPE_RENDER_COND_WAIT; + pipe->render_condition(pipe, predicate->query, mode); + } + else + { + /* TODO: add inverted predication to Gallium*/ + pipe->render_condition(pipe, 0, 0); + } + } + } + } + + virtual void STDMETHODCALLTYPE SetPredication( + __in_opt ID3D11Predicate *pPredicate, + __in BOOL PredicateValue) + { + SYNCHRONIZED; + if(render_predicate.p != pPredicate || render_predicate_value != PredicateValue) + { + render_predicate = pPredicate; + render_predicate_value = PredicateValue; + set_render_condition(); + } + } + + virtual void STDMETHODCALLTYPE GetPredication( + __out_opt ID3D11Predicate **ppPredicate, + __out_opt BOOL *pPredicateValue) + { + SYNCHRONIZED; + if(ppPredicate) + *ppPredicate = render_predicate.ref(); + if(pPredicateValue) + *pPredicateValue = render_predicate_value; + } + + static pipe_subresource d3d11_to_pipe_subresource(struct pipe_resource* resource, unsigned subresource) + { + pipe_subresource sr; + if(subresource <= resource->last_level) + { + sr.level = subresource; + sr.face = 0; + } + else + { + unsigned levels = resource->last_level + 1; + sr.level = subresource % levels; + sr.face = subresource / levels; + } + return sr; + } + + virtual HRESULT STDMETHODCALLTYPE Map( + __in ID3D11Resource *pResource, + __in unsigned Subresource, + __in D3D11_MAP MapType, + __in unsigned MapFlags, + __out D3D11_MAPPED_SUBRESOURCE *pMappedResource) + { + SYNCHRONIZED; + GalliumD3D11Resource<>* resource = (GalliumD3D11Resource<>*)pResource; + if(resource->transfers.count(Subresource)) + return E_FAIL; + pipe_subresource sr = d3d11_to_pipe_subresource(resource->resource, Subresource); + pipe_box box; + d3d11_to_pipe_box(resource->resource, sr.level, 0); + unsigned usage = 0; + if(MapType == D3D11_MAP_READ) + usage = PIPE_TRANSFER_READ; + else if(MapType == D3D11_MAP_WRITE) + usage = PIPE_TRANSFER_WRITE; + else if(MapType == D3D11_MAP_READ_WRITE) + usage = PIPE_TRANSFER_READ_WRITE; + else if(MapType == D3D11_MAP_WRITE_DISCARD) + usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD; + else if(MapType == D3D11_MAP_WRITE_NO_OVERWRITE) + usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_NOOVERWRITE; + else + return E_INVALIDARG; + if(MapType & D3D10_MAP_FLAG_DO_NOT_WAIT) + usage |= PIPE_TRANSFER_DONTBLOCK; + struct pipe_transfer* transfer = pipe->get_transfer(pipe, resource->resource, sr, usage, &box); + if(!transfer) { + if(MapType & D3D10_MAP_FLAG_DO_NOT_WAIT) + return DXGI_ERROR_WAS_STILL_DRAWING; + else + return E_FAIL; + } + resource->transfers[Subresource] = transfer; + pipe->transfer_map(pipe, transfer); + pMappedResource->pData = transfer->data; + pMappedResource->RowPitch = transfer->stride; + pMappedResource->DepthPitch = transfer->slice_stride; + return S_OK; + } + + virtual void STDMETHODCALLTYPE Unmap( + __in ID3D11Resource *pResource, + __in unsigned Subresource) + { + SYNCHRONIZED; + GalliumD3D11Resource<>* resource = (GalliumD3D11Resource<>*)pResource; + std::unordered_map<unsigned, pipe_transfer*>::iterator i = resource->transfers.find(Subresource); + if(i != resource->transfers.end()) + { + pipe->transfer_unmap(pipe, i->second); + pipe->transfer_destroy(pipe, i->second); + resource->transfers.erase(i); + } + } + + virtual void STDMETHODCALLTYPE CopySubresourceRegion( + __in ID3D11Resource *pDstResource, + __in unsigned DstSubresource, + __in unsigned DstX, + __in unsigned DstY, + __in unsigned DstZ, + __in ID3D11Resource *pSrcResource, + __in unsigned SrcSubresource, + __in_opt const D3D11_BOX *pSrcBox) + { + SYNCHRONIZED; + GalliumD3D11Resource<>* dst = (GalliumD3D11Resource<>*)pDstResource; + GalliumD3D11Resource<>* src = (GalliumD3D11Resource<>*)pSrcResource; + pipe_subresource subdst = d3d11_to_pipe_subresource(dst->resource, DstSubresource); + pipe_subresource subsrc = d3d11_to_pipe_subresource(src->resource, SrcSubresource); + pipe_box box = d3d11_to_pipe_box(src->resource, subsrc.level, pSrcBox); + for(unsigned i = 0; i < box.depth; ++i) + { + pipe->resource_copy_region(pipe, + dst->resource, subdst, DstX, DstY, DstZ + i, + src->resource, subsrc, box.x, box.y, box.z + i, + box.width, box.height); + } + } + + virtual void STDMETHODCALLTYPE CopyResource( + __in ID3D11Resource *pDstResource, + __in ID3D11Resource *pSrcResource) + { + SYNCHRONIZED; + GalliumD3D11Resource<>* dst = (GalliumD3D11Resource<>*)pDstResource; + GalliumD3D11Resource<>* src = (GalliumD3D11Resource<>*)pSrcResource; + pipe_subresource sr; + unsigned faces = dst->resource->target == PIPE_TEXTURE_CUBE ? 6 : 1; + + for(sr.face = 0; sr.face < faces; ++sr.face) + { + for(sr.level = 0; sr.level <= dst->resource->last_level; ++sr.level) + { + unsigned w = u_minify(dst->resource->width0, sr.level); + unsigned h = u_minify(dst->resource->height0, sr.level); + unsigned d = u_minify(dst->resource->depth0, sr.level); + for(unsigned i = 0; i < d; ++i) + { + pipe->resource_copy_region(pipe, + dst->resource, sr, 0, 0, i, + src->resource, sr, 0, 0, i, + w, h); + } + } + } + } + + virtual void STDMETHODCALLTYPE UpdateSubresource( + __in ID3D11Resource *pDstResource, + __in unsigned DstSubresource, + __in_opt const D3D11_BOX *pDstBox, + __in const void *pSrcData, + __in unsigned SrcRowPitch, + __in unsigned SrcDepthPitch) + { + SYNCHRONIZED; + GalliumD3D11Resource<>* dst = (GalliumD3D11Resource<>*)pDstResource; + pipe_subresource subdst = d3d11_to_pipe_subresource(dst->resource, DstSubresource); + pipe_box box = d3d11_to_pipe_box(dst->resource, subdst.level, pDstBox); + pipe->transfer_inline_write(pipe, dst->resource, subdst, PIPE_TRANSFER_WRITE, &box, pSrcData, SrcRowPitch, SrcDepthPitch); + } + +#if API >= 11 + virtual void STDMETHODCALLTYPE CopyStructureCount( + __in ID3D11Buffer *pDstBuffer, + __in unsigned DstAlignedByteOffset, + __in ID3D11UnorderedAccessView *pSrcView) + { + SYNCHRONIZED; + } +#endif + + virtual void STDMETHODCALLTYPE ClearRenderTargetView( + __in ID3D11RenderTargetView *pRenderTargetView, + __in const float ColorRGBA[4]) + { + SYNCHRONIZED; + GalliumD3D11RenderTargetView* view = ((GalliumD3D11RenderTargetView*)pRenderTargetView); + pipe->clear_render_target(pipe, view->object, ColorRGBA, 0, 0, view->object->width, view->object->height); + } + + virtual void STDMETHODCALLTYPE ClearDepthStencilView( + __in ID3D11DepthStencilView *pDepthStencilView, + __in unsigned ClearFlags, + __in float Depth, + __in UINT8 Stencil) + { + SYNCHRONIZED; + GalliumD3D11DepthStencilView* view = ((GalliumD3D11DepthStencilView*)pDepthStencilView); + unsigned flags = 0; + if(ClearFlags & D3D11_CLEAR_DEPTH) + flags |= PIPE_CLEAR_DEPTH; + if(ClearFlags & D3D11_CLEAR_STENCIL) + flags |= PIPE_CLEAR_STENCIL; + pipe->clear_depth_stencil(pipe, view->object, flags, Depth, Stencil, 0, 0, view->object->width, view->object->height); + } + +#if API >= 11 + virtual void STDMETHODCALLTYPE ClearUnorderedAccessViewUint( + __in ID3D11UnorderedAccessView *pUnorderedAccessView, + __in const unsigned Values[ 4 ]) + { + SYNCHRONIZED; + } + + virtual void STDMETHODCALLTYPE ClearUnorderedAccessViewFloat( + __in ID3D11UnorderedAccessView *pUnorderedAccessView, + __in const float Values[ 4 ]) + { + SYNCHRONIZED; + } +#endif + + virtual void STDMETHODCALLTYPE RestoreGalliumStateBlitOnly() + { + pipe->bind_blend_state(pipe, blend_state.p ? blend_state.p->object : default_blend); + pipe->bind_depth_stencil_alpha_state(pipe, depth_stencil_state.p ? depth_stencil_state.p->object : default_depth_stencil); + pipe->bind_rasterizer_state(pipe, rasterizer_state.p ? rasterizer_state.p->object : default_rasterizer); + pipe->bind_vertex_elements_state(pipe, input_layout.p ? input_layout.p->object : default_input_layout); + pipe->bind_fs_state(pipe, shaders[D3D11_STAGE_PS].p ? shaders[D3D11_STAGE_PS].p->object : default_shaders[PIPE_SHADER_FRAGMENT]); + pipe->bind_vs_state(pipe, shaders[D3D11_STAGE_VS].p ? shaders[D3D11_STAGE_VS].p->object : default_shaders[PIPE_SHADER_VERTEX]); + if(caps.gs) + pipe->bind_gs_state(pipe, shaders[D3D11_STAGE_GS].p ? shaders[D3D11_STAGE_GS].p->object : default_shaders[PIPE_SHADER_GEOMETRY]); + set_framebuffer(); + set_viewport(); + set_clip(); + set_render_condition(); + // TODO: restore stream output + + update_flags |= UPDATE_VERTEX_BUFFERS | (1 << (UPDATE_SAMPLERS_SHIFT + D3D11_STAGE_PS)) | (1 << (UPDATE_VIEWS_SHIFT + D3D11_STAGE_PS)); + } + + virtual void STDMETHODCALLTYPE GenerateMips( + __in ID3D11ShaderResourceView *pShaderResourceView) + { + SYNCHRONIZED; + + GalliumD3D11ShaderResourceView* view = (GalliumD3D11ShaderResourceView*)pShaderResourceView; + if(caps.gs) + pipe->bind_gs_state(pipe, 0); + if(caps.so) + pipe->bind_stream_output_state(pipe, 0); + if(pipe->render_condition) + pipe->render_condition(pipe, 0, 0); + util_gen_mipmap(gen_mipmap, view->object, 0, 0, view->object->texture->last_level, PIPE_TEX_FILTER_LINEAR); + RestoreGalliumStateBlitOnly(); + } + + virtual void STDMETHODCALLTYPE RestoreGalliumState() + { + SYNCHRONIZED; + RestoreGalliumStateBlitOnly(); + + set_index_buffer(); + set_stencil_ref(); + pipe->set_blend_color(pipe, (struct pipe_blend_color*)blend_color); + pipe->set_sample_mask(pipe, sample_mask); + + for(unsigned s = 0; s < 3; ++s) + { + unsigned num = std::min(caps.constant_buffers[s], (unsigned)D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT); + for(unsigned i = 0; i < num; ++i) + pipe->set_constant_buffer(pipe, s, i, constant_buffers[s][i].p ? constant_buffers[s][i].p->resource : 0); + } + + if(caps.so) + pipe->set_stream_output_buffers(pipe, so_buffers, (int*)so_offsets, num_so_targets); + + update_flags |= (1 << (UPDATE_SAMPLERS_SHIFT + D3D11_STAGE_VS)) | (1 << (UPDATE_VIEWS_SHIFT + D3D11_STAGE_VS)); + update_flags |= (1 << (UPDATE_SAMPLERS_SHIFT + D3D11_STAGE_GS)) | (1 << (UPDATE_VIEWS_SHIFT + D3D11_STAGE_GS)); + + set_scissor(); + } + +#if API >= 11 + /* TODO: hack SRVs or sampler states to handle this, or add to Gallium */ + virtual void STDMETHODCALLTYPE SetResourceMinLOD( + __in ID3D11Resource *pResource, + float MinLOD) + { + SYNCHRONIZED; + GalliumD3D11Resource<>* resource = (GalliumD3D11Resource<>*)pResource; + if(resource->min_lod != MinLOD) + { + // TODO: actually do anything? + resource->min_lod = MinLOD; + } + } + + virtual float STDMETHODCALLTYPE GetResourceMinLOD( + __in ID3D11Resource *pResource) + { + SYNCHRONIZED; + GalliumD3D11Resource<>* resource = (GalliumD3D11Resource<>*)pResource; + return resource->min_lod; + } +#endif + + virtual void STDMETHODCALLTYPE ResolveSubresource( + __in ID3D11Resource *pDstResource, + __in unsigned DstSubresource, + __in ID3D11Resource *pSrcResource, + __in unsigned SrcSubresource, + __in DXGI_FORMAT Format) + { + SYNCHRONIZED; + GalliumD3D11Resource<>* dst = (GalliumD3D11Resource<>*)pDstResource; + GalliumD3D11Resource<>* src = (GalliumD3D11Resource<>*)pSrcResource; + pipe_subresource subdst = d3d11_to_pipe_subresource(dst->resource, DstSubresource); + pipe_subresource subsrc = d3d11_to_pipe_subresource(src->resource, SrcSubresource); + pipe->resource_resolve(pipe, dst->resource, subdst, src->resource, subsrc); + } + +#if API >= 11 + virtual void STDMETHODCALLTYPE ExecuteCommandList( + __in ID3D11CommandList *pCommandList, + BOOL RestoreContextState) + { + SYNCHRONIZED; + } + + virtual HRESULT STDMETHODCALLTYPE FinishCommandList( + BOOL RestoreDeferredContextState, + __out_opt ID3D11CommandList **ppCommandList) + { + SYNCHRONIZED; + return E_NOTIMPL; + } +#endif + + virtual void STDMETHODCALLTYPE ClearState(void) + { + SYNCHRONIZED; + + // we qualify all calls so that we avoid virtual dispatch and might get them inlined + // TODO: make sure all this gets inlined, which might require more compiler flags + // TODO: optimize this +#if API >= 11 + GalliumD3D11DeviceContext::PSSetShader(0, 0, 0); + GalliumD3D11DeviceContext::GSSetShader(0, 0, 0); + GalliumD3D11DeviceContext::VSSetShader(0, 0, 0); + GalliumD3D11DeviceContext::HSSetShader(0, 0, 0); + GalliumD3D11DeviceContext::DSSetShader(0, 0, 0); + GalliumD3D11DeviceContext::CSSetShader(0, 0, 0); +#else + GalliumD3D11DeviceContext::PSSetShader(0); + GalliumD3D11DeviceContext::GSSetShader(0); + GalliumD3D11DeviceContext::VSSetShader(0); +#endif + + GalliumD3D11DeviceContext::IASetInputLayout(0); + GalliumD3D11DeviceContext::IASetIndexBuffer(0, DXGI_FORMAT_UNKNOWN, 0); + GalliumD3D11DeviceContext::RSSetState(0); + GalliumD3D11DeviceContext::OMSetDepthStencilState(0, 0); + GalliumD3D11DeviceContext::OMSetBlendState(0, (float*)zero_data, ~0); + GalliumD3D11DeviceContext::SetPredication(0, 0); + GalliumD3D11DeviceContext::IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED); + + GalliumD3D11DeviceContext::PSSetConstantBuffers(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, (ID3D11Buffer**)zero_data); + GalliumD3D11DeviceContext::GSSetConstantBuffers(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, (ID3D11Buffer**)zero_data); + GalliumD3D11DeviceContext::VSSetConstantBuffers(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, (ID3D11Buffer**)zero_data); +#if API >= 11 + GalliumD3D11DeviceContext::HSSetConstantBuffers(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, (ID3D11Buffer**)zero_data); + GalliumD3D11DeviceContext::DSSetConstantBuffers(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, (ID3D11Buffer**)zero_data); + GalliumD3D11DeviceContext::CSSetConstantBuffers(0, D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT, (ID3D11Buffer**)zero_data); +#endif + + GalliumD3D11DeviceContext::IASetVertexBuffers(0, num_vertex_buffers, (ID3D11Buffer**)zero_data, (unsigned*)zero_data, (unsigned*)zero_data); +#if API >= 11 + GalliumD3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews(0, 0, 0 , 0, 0, 0, 0); +#else + GalliumD3D11DeviceContext::OMSetRenderTargets(0, 0, 0 ); +#endif + GalliumD3D11DeviceContext::SOSetTargets(0, 0, 0); + + GalliumD3D11DeviceContext::PSSetShaderResources(0, num_shader_resource_views[D3D11_STAGE_PS], (ID3D11ShaderResourceView**)zero_data); + GalliumD3D11DeviceContext::GSSetShaderResources(0, num_shader_resource_views[D3D11_STAGE_GS], (ID3D11ShaderResourceView**)zero_data); + GalliumD3D11DeviceContext::VSSetShaderResources(0, num_shader_resource_views[D3D11_STAGE_VS], (ID3D11ShaderResourceView**)zero_data); +#if API >= 11 + GalliumD3D11DeviceContext::HSSetShaderResources(0, num_shader_resource_views[D3D11_STAGE_HS], (ID3D11ShaderResourceView**)zero_data); + GalliumD3D11DeviceContext::DSSetShaderResources(0, num_shader_resource_views[D3D11_STAGE_DS], (ID3D11ShaderResourceView**)zero_data); + GalliumD3D11DeviceContext::CSSetShaderResources(0, num_shader_resource_views[D3D11_STAGE_CS], (ID3D11ShaderResourceView**)zero_data); +#endif + + GalliumD3D11DeviceContext::PSSetSamplers(0, num_shader_resource_views[D3D11_STAGE_PS], (ID3D11SamplerState**)zero_data); + GalliumD3D11DeviceContext::GSSetSamplers(0, num_shader_resource_views[D3D11_STAGE_GS], (ID3D11SamplerState**)zero_data); + GalliumD3D11DeviceContext::VSSetSamplers(0, num_shader_resource_views[D3D11_STAGE_VS], (ID3D11SamplerState**)zero_data); +#if API >= 11 + GalliumD3D11DeviceContext::HSSetSamplers(0, num_shader_resource_views[D3D11_STAGE_HS], (ID3D11SamplerState**)zero_data); + GalliumD3D11DeviceContext::DSSetSamplers(0, num_shader_resource_views[D3D11_STAGE_DS], (ID3D11SamplerState**)zero_data); + GalliumD3D11DeviceContext::CSSetSamplers(0, num_shader_resource_views[D3D11_STAGE_CS], (ID3D11SamplerState**)zero_data); +#endif + + GalliumD3D11DeviceContext::RSSetViewports(0, 0); + GalliumD3D11DeviceContext::RSSetScissorRects(0, 0); + } + + virtual void STDMETHODCALLTYPE Flush(void) + { + SYNCHRONIZED; + pipe->flush(pipe, PIPE_FLUSH_FRAME, 0); + } + + /* In Direct3D 10, if the reference count of an object drops to 0, it is automatically + * cleanly unbound from the pipeline. + * In Direct3D 11, the pipeline holds a reference. + * + * Note that instead of always scanning the pipeline on destruction, we could + * maintain the internal reference count on DirectX 10 and use it to check if an + * object is still bound. + * Presumably, on average, scanning is faster if the application is well written. + */ +#if API < 11 +#define IMPLEMENT_SIMPLE_UNBIND(name, member, gallium, def) \ + void Unbind##name(ID3D11##name* state) \ + { \ + SYNCHRONIZED; \ + if((void*)state == (void*)member.p) \ + { \ + member.p = 0; \ + pipe->bind_##gallium##_state(pipe, default_##def); \ + } \ + } + IMPLEMENT_SIMPLE_UNBIND(BlendState, blend_state, blend, blend) + IMPLEMENT_SIMPLE_UNBIND(RasterizerState, rasterizer_state, rasterizer, rasterizer) + IMPLEMENT_SIMPLE_UNBIND(DepthStencilState, depth_stencil_state, depth_stencil_alpha, depth_stencil) + IMPLEMENT_SIMPLE_UNBIND(InputLayout, input_layout, vertex_elements, input_layout) + IMPLEMENT_SIMPLE_UNBIND(PixelShader, shaders[D3D11_STAGE_PS], fs, shaders[D3D11_STAGE_PS]) + IMPLEMENT_SIMPLE_UNBIND(VertexShader, shaders[D3D11_STAGE_VS], vs, shaders[D3D11_STAGE_VS]) + IMPLEMENT_SIMPLE_UNBIND(GeometryShader, shaders[D3D11_STAGE_GS], gs, shaders[D3D11_STAGE_GS]) + + void UnbindPredicate(ID3D11Predicate* predicate) + { + SYNCHRONIZED; + if(predicate == render_predicate) + { + render_predicate.p = NULL; + render_predicate_value = 0; + pipe->render_condition(pipe, 0, 0); + } + } + + void UnbindSamplerState(ID3D11SamplerState* state) + { + SYNCHRONIZED; + for(unsigned s = 0; s < D3D11_STAGES; ++s) + { + for(unsigned i = 0; i < num_samplers[s]; ++i) + { + if(samplers[s][i] == state) + { + samplers[s][i].p = NULL; + sampler_csos[s].v[i] = NULL; + update_flags |= (1 << (UPDATE_SAMPLERS_SHIFT + s)); + } + } + } + } + + void UnbindBuffer(ID3D11Buffer* buffer) + { + SYNCHRONIZED; + if(buffer == index_buffer) + { + index_buffer.p = 0; + index_format = DXGI_FORMAT_UNKNOWN; + index_offset = 0; + struct pipe_index_buffer ib; + memset(&ib, 0, sizeof(ib)); + pipe->set_index_buffer(pipe, &ib); + } + + for(unsigned i = 0; i < num_vertex_buffers; ++i) + { + if(buffer == input_buffers[i]) + { + input_buffers[i].p = 0; + memset(&vertex_buffers[num_vertex_buffers], 0, sizeof(vertex_buffers[num_vertex_buffers])); + update_flags |= UPDATE_VERTEX_BUFFERS; + } + } + + for(unsigned s = 0; s < D3D11_STAGES; ++s) + { + for(unsigned i = 0; i < sizeof(constant_buffers) / sizeof(constant_buffers[0]); ++i) + { + if(constant_buffers[s][i] == buffer) + { + constant_buffers[s][i] = (ID3D10Buffer*)NULL; + pipe->set_constant_buffer(pipe, s, i, NULL); + } + } + } + } + + void UnbindDepthStencilView(ID3D11DepthStencilView* view) + { + SYNCHRONIZED; + if(view == depth_stencil_view) + { + depth_stencil_view.p = NULL; + set_framebuffer(); + } + } + + void UnbindRenderTargetView(ID3D11RenderTargetView* view) + { + SYNCHRONIZED; + bool any_bound = false; + for(unsigned i = 0; i < num_render_target_views; ++i) + { + if(render_target_views[i] == view) + { + render_target_views[i].p = NULL; + any_bound = true; + } + } + if(any_bound) + set_framebuffer(); + } + + void UnbindShaderResourceView(ID3D11ShaderResourceView* view) + { + SYNCHRONIZED; + for(unsigned s = 0; s < D3D11_STAGES; ++s) + { + for(unsigned i = 0; i < num_shader_resource_views[s]; ++i) + { + if(shader_resource_views[s][i] == view) + { + shader_resource_views[s][i].p = NULL; + sampler_views[s][i] = NULL; + update_flags |= (1 << (UPDATE_VIEWS_SHIFT + s)); + } + } + } + } +#endif + +#undef SYNCHRONIZED +}; + +#if API >= 11 +/* This approach serves two purposes. + * First, we don't want to do an atomic operation to manipulate the reference + * count every time something is bound/unbound to the pipeline, since they are + * expensive. + * Fortunately, the immediate context can only be used by a single thread, so + * we don't have to use them, as long as a separate reference count is used + * (see dual_refcnt_t). + * + * Second, we want to avoid the Device -> DeviceContext -> bound DeviceChild -> Device + * garbage cycle. + * To avoid it, DeviceChild doesn't hold a reference to Device as usual, but adds + * one for each external reference count, while internal nonatomic_add_ref doesn't + * add any. + * + * Note that ideally we would to eliminate the non-atomic op too, but this is more + * complicated, since we would either need to use garbage collection and give up + * deterministic destruction (especially bad for large textures), or scan the whole + * pipeline state every time the reference count of object drops to 0, which risks + * pathological slowdowns. + * + * Since this microoptimization should matter relatively little, let's avoid it for now. + * + * Note that deferred contexts don't use this, since as a whole, they must thread-safe. + * Eliminating the atomic ops for deferred contexts seems substantially harder. + * This might be a problem if they are used in a one-shot multithreaded rendering + * fashion, where SMP cacheline bouncing on the reference count may be visible. + * + * The idea would be to attach a structure of reference counts indexed by deferred + * context id to each object. Ideally, this should be organized like ext2 block pointers. + * + * Every deferred context would get a reference count in its own cacheline. + * The external count is protected by a lock bit, and there is also a "lock bit" in each + * internal count. + * + * When the external count has to be dropped to 0, the lock bit is taken and all internal + * reference counts are scanned, taking a count of them. A flag would also be set on them. + * Deferred context manipulation would notice the flag, and update the count. + * Once the count goes to zero, the object is freed. + * + * The problem of this is that if the external reference count ping-pongs between + * zero and non-zero, the scans will take a lot of time. + * + * The idea to solve this is to compute the scans in a binary-tree like fashion, where + * each binary tree node would have a "determined bit", which would be invalidated + * by manipulations. + * + * However, all this complexity might actually be a loss in most cases, so let's just + * stick to a single atomic refcnt for now. + * + * Also, we don't even support deferred contexts yet, so this can wait. + */ +struct nonatomic_device_child_ptr_traits +{ + static void add_ref(void* p) + { + if(p) + ((GalliumD3D11DeviceChild<>*)p)->nonatomic_add_ref(); + } + + static void release(void* p) + { + if(p) + ((GalliumD3D11DeviceChild<>*)p)->nonatomic_release(); + } +}; + +struct GalliumD3D11ImmediateDeviceContext + : public GalliumD3D11DeviceContext<nonatomic_device_child_ptr_traits> +{ + GalliumD3D11ImmediateDeviceContext(GalliumD3D11Screen* device, pipe_context* pipe, unsigned context_flags = 0) + : GalliumD3D11DeviceContext(device, pipe, context_flags) + { + // not necessary, but tests that the API at least basically works + ClearState(); + } + + /* we do this since otherwise we would have a garbage cycle between this and the device */ + virtual ULONG STDMETHODCALLTYPE AddRef() + { + return this->device->AddRef(); + } + + virtual ULONG STDMETHODCALLTYPE Release() + { + return this->device->Release(); + } + + virtual D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE GetType() + { + return D3D11_DEVICE_CONTEXT_IMMEDIATE; + } +}; + +static ID3D11DeviceContext* GalliumD3D11ImmediateDeviceContext_Create(GalliumD3D11Screen* device, struct pipe_context* pipe, bool owns_pipe) +{ + return new GalliumD3D11ImmediateDeviceContext(device, pipe, owns_pipe); +} + +static void GalliumD3D11ImmediateDeviceContext_RestoreGalliumState(ID3D11DeviceContext* context) +{ + ((GalliumD3D11ImmediateDeviceContext*)context)->RestoreGalliumState(); +} + +static void GalliumD3D11ImmediateDeviceContext_RestoreGalliumStateBlitOnly(ID3D11DeviceContext* context) +{ + ((GalliumD3D11ImmediateDeviceContext*)context)->RestoreGalliumStateBlitOnly(); +} + +static void GalliumD3D11ImmediateDeviceContext_Destroy(ID3D11DeviceContext* context) +{ + delete (GalliumD3D11ImmediateDeviceContext*)context; +} +#endif diff --git a/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_objects.h b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_objects.h new file mode 100644 index 00000000000..ad6b28fceb1 --- /dev/null +++ b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_objects.h @@ -0,0 +1,715 @@ +/************************************************************************** + * + * 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<typename Base = ID3D11DeviceChild> +struct GalliumD3D11DeviceChild : public GalliumPrivateDataComObject<Base, dual_refcnt_t> +{ + 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<Base, dual_refcnt_t>::add_ref(); + } + + inline ULONG release() + { + device->Release(); + return GalliumPrivateDataComObject<Base, dual_refcnt_t>::release(); + } + + virtual ULONG STDMETHODCALLTYPE AddRef() + { + return add_ref(); + } + + virtual ULONG STDMETHODCALLTYPE Release() + { + return release(); + } + + virtual void STDMETHODCALLTYPE GetDevice( + __out ID3D11Device **ppDevice + ) + { + device->AddRef(); + *ppDevice = device; + } +}; + +template<typename Base = ID3D11DeviceChild, typename Object = void> +struct GalliumD3D11Object : public GalliumD3D11DeviceChild<Base> +{ + Object* object; + GalliumD3D11Object(GalliumD3D11Screen* device, Object* object) + : GalliumD3D11DeviceChild<Base>(device), object(object) + {} + + virtual ~GalliumD3D11Object(); +}; + +#define IMPLEMENT_OBJECT_DTOR(name, gallium) \ +template<> \ +GalliumD3D11Object<ID3D11##name, void>::~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<ID3D11##name, struct pipe_##gallium>::~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<typename Base, typename Desc, typename Object = void> +struct GalliumD3D11DescribedObject : public GalliumD3D11Object<Base, Object> +{ + Desc desc; + GalliumD3D11DescribedObject(GalliumD3D11Screen* device, Object* object, const Desc& desc) + : GalliumD3D11Object<Base, Object>(device, object), desc(desc) + {} + + virtual void STDMETHODCALLTYPE GetDesc(Desc *pDesc) + { + memcpy(pDesc, &desc, sizeof(desc)); + } +}; + +typedef GalliumD3D11Object<ID3D11InputLayout> GalliumD3D11InputLayout; +typedef GalliumD3D11DescribedObject<ID3D11DepthStencilState, D3D11_DEPTH_STENCIL_DESC> GalliumD3D11DepthStencilState; +typedef GalliumD3D11DescribedObject<ID3D11RasterizerState, D3D11_RASTERIZER_DESC> GalliumD3D11RasterizerStateBase; +typedef GalliumD3D11DescribedObject<ID3D11SamplerState, D3D11_SAMPLER_DESC> GalliumD3D11SamplerState; + +#if API >= 11 +typedef GalliumD3D11DescribedObject<ID3D11BlendState, D3D11_BLEND_DESC> GalliumD3D11BlendState; +#else +typedef GalliumD3D10DescribedObject<ID3D10BlendState1, D3D10_BLEND_DESC> 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 *pDesc) + { + memcpy(pDesc, &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<typename Base = ID3D11DeviceChild> +struct GalliumD3D11Shader : public GalliumD3D11Object<Base> +{ + std::vector<int> slot_to_resource; + std::vector<int> slot_to_sampler; + + GalliumD3D11Shader(GalliumD3D11Screen* device, void* object) + : GalliumD3D11Object<Base>(device, object) + {} +}; + +typedef GalliumD3D11Shader<ID3D11VertexShader> GalliumD3D11VertexShader; +typedef GalliumD3D11Shader<ID3D11GeometryShader> GalliumD3D11GeometryShader; +typedef GalliumD3D11Shader<ID3D11PixelShader> GalliumD3D11PixelShader; + +#if API >= 11 +/* +typedef GalliumD3D11Shader<ID3D11HullShader> GalliumD3D11HullShader; +typedef GalliumD3D11Shader<ID3D11DomainShader> GalliumD3D11DomainShader; +typedef GalliumD3D11Shader<ID3D11ComputeShader> GalliumD3D11ComputeShader; +*/ +#endif + +template<typename Base = ID3D11Resource> +struct GalliumD3D11ResourceBase : public GalliumD3D11DeviceChild<Base> +{ + unsigned eviction_priority; + + virtual void STDMETHODCALLTYPE SetEvictionPriority( + __in unsigned EvictionPriority) + { + eviction_priority = EvictionPriority; + } + + virtual unsigned STDMETHODCALLTYPE GetEvictionPriority() + { + return eviction_priority; + } +}; + +template<typename Real> +struct GalliumDXGIResource : public IDXGIResource +{ + virtual HRESULT STDMETHODCALLTYPE SetEvictionPriority( + __in unsigned EvictionPriority) + { + static_cast<Real*>(this)->eviction_priority = EvictionPriority; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetEvictionPriority(unsigned* pEvictionPriority) + { + *pEvictionPriority = static_cast<Real*>(this)->eviction_priority; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetDevice( + __in REFIID riid, + __out void **ppParent) + { + if(!static_cast<Real*>(this)->device) + return E_NOINTERFACE; + return static_cast<Real*>(this)->device->QueryInterface(riid, ppParent); + } + + virtual HRESULT STDMETHODCALLTYPE GetParent( + __in REFIID riid, + __out void **ppParent) + { + if(!static_cast<Real*>(this)->device) + return E_NOINTERFACE; + return static_cast<Real*>(this)->device->QueryInterface(riid, ppParent); + } +}; + +template<typename T> +struct com_traits<GalliumDXGIResource<T> > : public com_traits<IDXGIResource> +{}; + +template<typename Base = ID3D11Resource> +struct GalliumD3D11Resource + : public GalliumMultiComObject< + GalliumMultiPrivateDataComObject< + GalliumD3D11ResourceBase<Base>, + GalliumDXGIResource<GalliumD3D11Resource<Base> > + >, + IGalliumResource + > +{ + struct pipe_resource* resource; + std::unordered_map<unsigned, pipe_transfer*> 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( + __out DXGI_USAGE *pUsage + ) + { + *pUsage = this->dxgi_usage; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetSharedHandle(HANDLE *pSharedHandle) + { + return E_NOTIMPL; + } + + virtual struct pipe_resource* STDMETHODCALLTYPE GetGalliumResource() + { + return resource; + } +}; + +template<typename Base, typename Desc, D3D11_RESOURCE_DIMENSION Dim> +struct GalliumD3D11TypedResource : public GalliumD3D11Resource<Base> +{ + Desc desc; + GalliumD3D11TypedResource() {} + GalliumD3D11TypedResource(GalliumD3D11Screen* device, struct pipe_resource* resource, const Desc& desc, unsigned dxgi_usage) + : GalliumD3D11Resource<Base>(device, resource, dxgi_usage), desc(desc) + {} + virtual void STDMETHODCALLTYPE GetType( + __out D3D11_RESOURCE_DIMENSION *pResourceDimension) + { + *pResourceDimension = Dim; + } + virtual void STDMETHODCALLTYPE GetDesc(Desc *pDesc) + { + memcpy(pDesc, &desc, sizeof(desc)); + } +}; + +typedef GalliumD3D11TypedResource<ID3D11Texture1D, D3D11_TEXTURE1D_DESC, D3D11_RESOURCE_DIMENSION_TEXTURE1D> GalliumD3D11Texture1DBase; +typedef GalliumD3D11TypedResource<ID3D11Texture2D, D3D11_TEXTURE2D_DESC, D3D11_RESOURCE_DIMENSION_TEXTURE2D> GalliumD3D11Texture2DBase; +typedef GalliumD3D11TypedResource<ID3D11Texture3D, D3D11_TEXTURE3D_DESC, D3D11_RESOURCE_DIMENSION_TEXTURE3D> GalliumD3D11Texture3DBase; +typedef GalliumD3D11TypedResource<ID3D11Buffer, D3D11_BUFFER_DESC, D3D11_RESOURCE_DIMENSION_BUFFER> 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( + __in D3D10_MAP MapType, + __in unsigned MapFlags, + __out void **ppData) + { + D3D10_MAPPED_SUBRESOURCE msr; + HRESULT hr = device->Map(this, 0, MapType, MapFlags, &msr); + if(!SUCCEEDED(hr)) + return hr; + *ppData = 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( + __in unsigned Subresource, + __in D3D10_MAP MapType, + __in unsigned MapFlags, + __out void **ppData) + { + D3D10_MAPPED_SUBRESOURCE msr; + HRESULT hr = device->Map(this, Subresource, MapType, MapFlags, &msr); + if(!SUCCEEDED(hr)) + return hr; + *ppData = msr.pData; + return S_OK; + } + + virtual void STDMETHODCALLTYPE Unmap( + __in 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( + __in unsigned Subresource, + __in D3D10_MAP MapType, + __in unsigned MapFlags, + __out D3D10_MAPPED_TEXTURE2D *pMappedTex2D) + { + D3D10_MAPPED_SUBRESOURCE msr; + HRESULT hr = device->Map(this, Subresource, MapType, MapFlags, &msr); + if(!SUCCEEDED(hr)) + return hr; + pMappedTex2D->pData = msr.pData; + pMappedTex2D->RowPitch = msr.RowPitch; + return S_OK; + } + + virtual void STDMETHODCALLTYPE Unmap( + __in 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( + __in unsigned Subresource, + __in D3D10_MAP MapType, + __in unsigned MapFlags, + __out D3D10_MAPPED_TEXTURE3D *pMappedTex3D) + { + D3D10_MAPPED_SUBRESOURCE msr; + HRESULT hr = device->Map(this, Subresource, MapType, MapFlags, &msr); + if(!SUCCEEDED(hr)) + return hr; + pMappedTex3D->pData = msr.pData; + pMappedTex3D->RowPitch = msr.RowPitch; + pMappedTex3D->DepthPitch = msr.DepthPitch; + return S_OK; + } + + virtual void STDMETHODCALLTYPE Unmap( + __in unsigned Subresource + ) + { + device->Unmap(this, Subresource); + } +}; +#endif + +struct GalliumD3D11Surface : public GalliumMultiPrivateDataComObject<GalliumD3D11Texture2D, IDXGISurface1> +{ + 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( + __out DXGI_SURFACE_DESC *pDesc) + { + pDesc->Format = this->desc.Format; + pDesc->Width = this->desc.Width; + pDesc->Height = this->desc.Height; + pDesc->SampleDesc = this->desc.SampleDesc; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetParent( + __in REFIID riid, + __out void **ppParent) + { + if(!device) + return E_NOINTERFACE; + return device->QueryInterface(riid, ppParent); + } + + /* TODO: somehow implement these */ + virtual HRESULT STDMETHODCALLTYPE GetDC( + BOOL Discard, + __out HDC *phdc) + { + *phdc = 0; + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE ReleaseDC( + __in_opt RECT *pDirtyRect) + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Map( + __out DXGI_MAPPED_RECT *pLockedRect, + unsigned MapFlags) + { + D3D11_MAP d3d_map; + if(MapFlags & DXGI_MAP_DISCARD) + d3d_map = D3D11_MAP_WRITE_DISCARD; + else + { + if(MapFlags & DXGI_MAP_READ) + { + if(MapFlags & 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); + pLockedRect->pBits = (uint8_t*)d3d_mapped.pData; + pLockedRect->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( + __in REFIID riid, + __out void **ppParent) + { + if(!device) + return E_NOINTERFACE; + return device->QueryInterface(riid, ppParent); + } +}; + +template<typename Base, typename Desc, typename Object> +struct GalliumD3D11View : public GalliumD3D11DescribedObject<Base, Desc, Object> +{ + GalliumD3D11Resource<>* resource; + GalliumD3D11View(GalliumD3D11Screen* device, GalliumD3D11Resource<>* resource, Object* object, const Desc& desc) + : GalliumD3D11DescribedObject<Base, Desc, Object>(device, object, desc), resource(resource) + { + resource->AddRef(); + } + + ~GalliumD3D11View() + { + resource->Release(); + } + + virtual void STDMETHODCALLTYPE GetResource(ID3D11Resource** ppResource) + { + resource->AddRef(); + *ppResource = resource; + } +}; + +typedef GalliumD3D11View<ID3D11DepthStencilView, D3D11_DEPTH_STENCIL_VIEW_DESC, struct pipe_surface> GalliumD3D11DepthStencilView; +typedef GalliumD3D11View<ID3D11RenderTargetView, D3D11_RENDER_TARGET_VIEW_DESC, struct pipe_surface> GalliumD3D11RenderTargetView; + +#if API >= 11 +typedef GalliumD3D11View<ID3D11ShaderResourceView, D3D11_SHADER_RESOURCE_VIEW_DESC, struct pipe_sampler_view> GalliumD3D11ShaderResourceView; +#else +typedef GalliumD3D10View<ID3D10ShaderResourceView1, D3D10_SHADER_RESOURCE_VIEW_DESC1, struct pipe_sampler_view> 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 *pDesc) + { + memcpy(pDesc, &desc, sizeof(*pDesc)); + } + + virtual void STDMETHODCALLTYPE GetDesc(D3D10_SHADER_RESOURCE_VIEW_DESC *pDesc) + { + memcpy(pDesc, &desc, sizeof(*pDesc)); + } +}; +#endif + +template<typename Base = ID3D11Asynchronous> +struct GalliumD3D11Asynchronous : public GalliumD3D11DeviceChild<Base> +{ + struct pipe_query* query; + unsigned data_size; + + GalliumD3D11Asynchronous(GalliumD3D11Screen* device, struct pipe_query* query, unsigned data_size) + : GalliumD3D11DeviceChild<Base>(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( + __out_bcount(DataSize) void *pData, + __in unsigned DataSize, + __in unsigned GetDataFlags) + { + return this->device->GetData(this, pData, DataSize, GetDataFlags); + } +#endif +}; + +template<typename Base = ID3D11Asynchronous> +struct GalliumD3D11QueryOrPredicate : public GalliumD3D11Asynchronous<Base> +{ + D3D11_QUERY_DESC desc; + GalliumD3D11QueryOrPredicate(GalliumD3D11Screen* device, struct pipe_query* query, unsigned data_size, const D3D11_QUERY_DESC& desc) + : GalliumD3D11Asynchronous<Base>(device, query, data_size), desc(desc) + {} + + virtual void STDMETHODCALLTYPE GetDesc( + __out D3D11_QUERY_DESC *pDesc) + { + *pDesc = desc; + } +}; + +struct GalliumD3D11Query : public GalliumD3D11QueryOrPredicate<ID3D11Query> +{ + 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<ID3D11Predicate> +{ + 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<ID3D11Counter> +{ + 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( + __out D3D11_COUNTER_DESC *pDesc) + { + *pDesc = desc; + } +}; diff --git a/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_screen.h b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_screen.h new file mode 100644 index 00000000000..50039e388d5 --- /dev/null +++ b/src/gallium/state_trackers/d3d1x/gd3d11/d3d11_screen.h @@ -0,0 +1,1447 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +/* 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<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_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; + } + + 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); +#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( + __out ID3D11DeviceContext **ppImmediateContext) + { + immediate_context->AddRef(); + *ppImmediateContext = 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( + __in const D3D11_COUNTER_DESC *pDesc, + __out D3D11_COUNTER_TYPE *pType, + __out unsigned *pActiveCounters, + __out_ecount_opt(*pNameLength) LPSTR szName, + __inout_opt unsigned *pNameLength, + __out_ecount_opt(*pUnitsLength) LPSTR szUnits, + __inout_opt unsigned *pUnitsLength, + __out_ecount_opt(*pDescriptionLength) LPSTR szDescription, + __inout_opt unsigned *pDescriptionLength) + { + return E_NOTIMPL; + } + + virtual void STDMETHODCALLTYPE CheckCounterInfo( + __out D3D11_COUNTER_INFO *pCounterInfo) + { + /* none supported at the moment */ + pCounterInfo->LastDeviceDependentCounter = (D3D11_COUNTER)0; + pCounterInfo->NumSimultaneousCounters = 0; + pCounterInfo->NumDetectableParallelUnits = 1; + } + +#if API >= 11 + virtual HRESULT STDMETHODCALLTYPE CheckFeatureSupport( + D3D11_FEATURE Feature, + __out_bcount(FeatureSupportDataSize) void *pFeatureSupportData, + unsigned FeatureSupportDataSize) + { + SYNCHRONIZED; + + switch(Feature) + { + case D3D11_FEATURE_THREADING: + { + D3D11_FEATURE_DATA_THREADING* data = (D3D11_FEATURE_DATA_THREADING*)pFeatureSupportData; + if(FeatureSupportDataSize != 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*)pFeatureSupportData; + if(FeatureSupportDataSize != 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*)pFeatureSupportData; + if(FeatureSupportDataSize != 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*)pFeatureSupportData; + if(FeatureSupportDataSize != 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*)pFeatureSupportData; + if(FeatureSupportDataSize != 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 Format, + unsigned *pFormatSupport + ) + { + SYNCHRONIZED; + + /* TODO: MSAA, advanced features */ + pipe_format format = dxgi_to_pipe_format[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, 0) + || (screen->is_format_supported(screen, format, PIPE_BUFFER, 0, PIPE_BIND_INDEX_BUFFER, 0) + || format == PIPE_FORMAT_R8_UNORM)) + support |= buffer; + if(screen->is_format_supported(screen, format, PIPE_BUFFER, 0, PIPE_BIND_STREAM_OUTPUT, 0)) + support |= buffer | D3D11_FORMAT_SUPPORT_SO_BUFFER; + if(screen->is_format_supported(screen, format, PIPE_TEXTURE_1D, 0, PIPE_BIND_SAMPLER_VIEW, 0)) + support |= D3D11_FORMAT_SUPPORT_TEXTURE1D | sampler_view; + if(screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW, 0)) + support |= D3D11_FORMAT_SUPPORT_TEXTURE2D | sampler_view; + if(screen->is_format_supported(screen, format, PIPE_TEXTURE_CUBE, 0, PIPE_BIND_SAMPLER_VIEW, 0)) + support |= D3D11_FORMAT_SUPPORT_TEXTURE2D | sampler_view; + if(screen->is_format_supported(screen, format, PIPE_TEXTURE_3D, 0, PIPE_BIND_SAMPLER_VIEW, 0)) + support |= D3D11_FORMAT_SUPPORT_TEXTURE3D | sampler_view; + if(screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET, 0)) + 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, 0)) + 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, 0)) + support |= D3D11_FORMAT_SUPPORT_DISPLAY; + format_support[format] = support; + } + *pFormatSupport = support; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CheckMultisampleQualityLevels( + DXGI_FORMAT Format, + unsigned SampleCount, + unsigned *pNumQualityLevels + ) + { + SYNCHRONIZED; + + *pNumQualityLevels = 0; + return S_OK; + } + + template<typename T, typename U> + 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( + __in const D3D11_BLEND_DESC *pBlendStateDesc, + __out_opt ID3D11BlendState **ppBlendState + ) +#else + virtual HRESULT STDMETHODCALLTYPE CreateBlendState1( + __in const D3D10_BLEND_DESC1 *pBlendStateDesc, + __out_opt ID3D10BlendState1 **ppBlendState + ) +#endif + { + SYNCHRONIZED; + + pipe_blend_state state; + memset(&state, 0, sizeof(state)); + state.alpha_to_coverage = !!pBlendStateDesc->AlphaToCoverageEnable; + state.independent_blend_enable = !!pBlendStateDesc->IndependentBlendEnable; + assert(PIPE_MAX_COLOR_BUFS >= 8); + for(unsigned i = 0; i < 8; ++i) + { + if(!convert_blend_state( + state.rt[i], + pBlendStateDesc->RenderTarget[i], + pBlendStateDesc->RenderTarget[i].BlendEnable, + pBlendStateDesc->RenderTarget[i].RenderTargetWriteMask)) + return E_INVALIDARG; + } + + if(!ppBlendState) + return S_FALSE; + + void* object = immediate_pipe->create_blend_state(immediate_pipe, &state); + if(!object) + return E_FAIL; + + *ppBlendState = new GalliumD3D11BlendState(this, object, *pBlendStateDesc); + return S_OK; + } + +#if API < 11 + virtual HRESULT STDMETHODCALLTYPE CreateBlendState( + __in const D3D10_BLEND_DESC *pBlendStateDesc, + __out_opt ID3D10BlendState **ppBlendState + ) + { + SYNCHRONIZED; + + pipe_blend_state state; + memset(&state, 0, sizeof(state)); + state.alpha_to_coverage = !!pBlendStateDesc->AlphaToCoverageEnable; + assert(PIPE_MAX_COLOR_BUFS >= 8); + for(unsigned i = 0; i < 8; ++i) + { + if(!convert_blend_state( + state.rt[i], + *pBlendStateDesc, + pBlendStateDesc->BlendEnable[i], + pBlendStateDesc->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; + + *ppBlendState = new GalliumD3D11BlendState(this, object, *pBlendStateDesc); + return S_OK; + } +#endif + + virtual HRESULT STDMETHODCALLTYPE CreateDepthStencilState( + __in const D3D11_DEPTH_STENCIL_DESC *pDepthStencilStateDesc, + __out_opt ID3D11DepthStencilState **ppDepthStencilState + ) + { + SYNCHRONIZED; + + pipe_depth_stencil_alpha_state state; + memset(&state, 0, sizeof(state)); + state.depth.enabled = !!pDepthStencilStateDesc->DepthEnable; + state.depth.writemask = pDepthStencilStateDesc->DepthWriteMask; + state.depth.func = pDepthStencilStateDesc->DepthFunc - 1; + state.stencil[0].enabled = !!pDepthStencilStateDesc->StencilEnable; + state.stencil[0].writemask = pDepthStencilStateDesc->StencilWriteMask; + state.stencil[0].valuemask = pDepthStencilStateDesc->StencilReadMask; + state.stencil[0].zpass_op = d3d11_to_pipe_stencil_op[pDepthStencilStateDesc->FrontFace.StencilPassOp]; + state.stencil[0].fail_op = d3d11_to_pipe_stencil_op[pDepthStencilStateDesc->FrontFace.StencilFailOp]; + state.stencil[0].zfail_op = d3d11_to_pipe_stencil_op[pDepthStencilStateDesc->FrontFace.StencilDepthFailOp]; + state.stencil[0].func = pDepthStencilStateDesc->FrontFace.StencilFunc - 1; + state.stencil[1].enabled = !!pDepthStencilStateDesc->StencilEnable; + state.stencil[1].writemask = pDepthStencilStateDesc->StencilWriteMask; + state.stencil[1].valuemask = pDepthStencilStateDesc->StencilReadMask; + state.stencil[1].zpass_op = d3d11_to_pipe_stencil_op[pDepthStencilStateDesc->BackFace.StencilPassOp]; + state.stencil[1].fail_op = d3d11_to_pipe_stencil_op[pDepthStencilStateDesc->BackFace.StencilFailOp]; + state.stencil[1].zfail_op = d3d11_to_pipe_stencil_op[pDepthStencilStateDesc->BackFace.StencilDepthFailOp]; + state.stencil[1].func = pDepthStencilStateDesc->BackFace.StencilFunc - 1; + + if(!ppDepthStencilState) + return S_FALSE; + + void* object = immediate_pipe->create_depth_stencil_alpha_state(immediate_pipe, &state); + if(!object) + return E_FAIL; + + *ppDepthStencilState = new GalliumD3D11DepthStencilState(this, object, *pDepthStencilStateDesc); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CreateRasterizerState( + __in const D3D11_RASTERIZER_DESC *pRasterizerDesc, + __out_opt ID3D11RasterizerState **ppRasterizerState) + { + 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 = (pRasterizerDesc->FillMode == D3D11_FILL_WIREFRAME) ? PIPE_POLYGON_MODE_LINE : PIPE_POLYGON_MODE_FILL; + if(pRasterizerDesc->CullMode == D3D11_CULL_FRONT) + state.cull_face = PIPE_FACE_FRONT; + else if(pRasterizerDesc->CullMode == D3D11_CULL_BACK) + state.cull_face = PIPE_FACE_BACK; + else + state.cull_face = PIPE_FACE_NONE; + state.front_ccw = !!pRasterizerDesc->FrontCounterClockwise; + /* TODO: is this correct? */ + /* TODO: we are ignoring DepthBiasClamp! */ + state.offset_tri = state.offset_line = state.offset_point = pRasterizerDesc->SlopeScaledDepthBias || pRasterizerDesc->DepthBias; + state.offset_scale = pRasterizerDesc->SlopeScaledDepthBias; + state.offset_units = pRasterizerDesc->DepthBias; + state.scissor = !!pRasterizerDesc->ScissorEnable; + state.multisample = !!pRasterizerDesc->MultisampleEnable; + state.line_smooth = !!pRasterizerDesc->AntialiasedLineEnable; + + /* TODO: is this correct? */ + state.point_quad_rasterization = 1; + + if(!ppRasterizerState) + return S_FALSE; + + void* object = immediate_pipe->create_rasterizer_state(immediate_pipe, &state); + if(!object) + return E_FAIL; + + *ppRasterizerState = new GalliumD3D11RasterizerState(this, object, *pRasterizerDesc, !pRasterizerDesc->DepthClipEnable); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CreateSamplerState( + __in const D3D11_SAMPLER_DESC *pSamplerDesc, + __out_opt ID3D11SamplerState **ppSamplerState) + { + SYNCHRONIZED; + + pipe_sampler_state state; + memset(&state, 0, sizeof(state)); + state.normalized_coords = 1; + state.min_mip_filter = (pSamplerDesc->Filter & 1); + state.mag_img_filter = ((pSamplerDesc->Filter >> 2) & 1); + state.min_img_filter = ((pSamplerDesc->Filter >> 4) & 1); + if(pSamplerDesc->Filter & 0x40) + state.max_anisotropy = pSamplerDesc->MaxAnisotropy; + if(pSamplerDesc->Filter & 0x80) + { + state.compare_mode = PIPE_TEX_COMPARE_R_TO_TEXTURE; + state.compare_func = pSamplerDesc->ComparisonFunc; + } + state.wrap_s = d3d11_to_pipe_wrap[pSamplerDesc->AddressU]; + state.wrap_t = d3d11_to_pipe_wrap[pSamplerDesc->AddressV]; + state.wrap_r = d3d11_to_pipe_wrap[pSamplerDesc->AddressW]; + state.lod_bias = pSamplerDesc->MipLODBias; + memcpy(state.border_color, pSamplerDesc->BorderColor, sizeof(state.border_color)); + state.min_lod = pSamplerDesc->MinLOD; + state.max_lod = pSamplerDesc->MaxLOD; + + if(!ppSamplerState) + return S_FALSE; + + void* object = immediate_pipe->create_sampler_state(immediate_pipe, &state); + if(!object) + return E_FAIL; + + *ppSamplerState = new GalliumD3D11SamplerState(this, object, *pSamplerDesc); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CreateInputLayout( + __in_ecount(NumElements) const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs, + __in_range(0, D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT) unsigned NumElements, + __in const void *pShaderBytecodeWithInputSignature, + __in SIZE_T BytecodeLength, + __out_opt ID3D11InputLayout **ppInputLayout) + { + SYNCHRONIZED; + + if(NumElements > 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(pShaderBytecodeWithInputSignature, BytecodeLength, false); + D3D11_SIGNATURE_PARAMETER_DESC* params; + unsigned num_params = dxbc_parse_signature(sig, ¶ms); + + 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 < NumElements; ++i) + semantic_to_idx_map[std::make_pair(c_string(pInputElementDescs[i].SemanticName), pInputElementDescs[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[pInputElementDescs[idx].Format]; + elements[i].src_offset = pInputElementDescs[idx].AlignedByteOffset; + elements[i].vertex_buffer_index = pInputElementDescs[idx].InputSlot; + elements[i].instance_divisor = pInputElementDescs[idx].InstanceDataStepRate; + } + } + + free(params); + + if(!ppInputLayout) + return S_FALSE; + + void* object = immediate_pipe->create_vertex_elements_state(immediate_pipe, num_params_to_use, elements); + if(!object) + return E_FAIL; + + *ppInputLayout = new GalliumD3D11InputLayout(this, object); + return S_OK; + } + + static unsigned d3d11_to_pipe_bind_flags(unsigned BindFlags) + { + unsigned bind = 0; + if(BindFlags & D3D11_BIND_VERTEX_BUFFER) + bind |= PIPE_BIND_VERTEX_BUFFER; + if(BindFlags & D3D11_BIND_INDEX_BUFFER) + bind |= PIPE_BIND_INDEX_BUFFER; + if(BindFlags & D3D11_BIND_CONSTANT_BUFFER) + bind |= PIPE_BIND_CONSTANT_BUFFER; + if(BindFlags & D3D11_BIND_SHADER_RESOURCE) + bind |= PIPE_BIND_SAMPLER_VIEW; + if(BindFlags & D3D11_BIND_STREAM_OUTPUT) + bind |= PIPE_BIND_STREAM_OUTPUT; + if(BindFlags & D3D11_BIND_RENDER_TARGET) + bind |= PIPE_BIND_RENDER_TARGET; + if(BindFlags & 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 MipLevels, + unsigned ArraySize, + DXGI_FORMAT Format, + const DXGI_SAMPLE_DESC* SampleDesc, + D3D11_USAGE Usage, + unsigned BindFlags, + unsigned CPUAccessFlags, + unsigned MiscFlags, + const D3D11_SUBRESOURCE_DATA *pInitialData, + DXGI_USAGE dxgi_usage, + struct pipe_resource** ppresource + ) + { + if(invalid(Format >= DXGI_FORMAT_COUNT)) + return E_INVALIDARG; + if(MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) + { + if(target != PIPE_TEXTURE_2D) + return E_INVALIDARG; + target = PIPE_TEXTURE_CUBE; + + if(ArraySize != 6) + return E_NOTIMPL; + } + else + { + if(ArraySize > 1) + return E_NOTIMPL; + ArraySize = 1; + } + /* TODO: msaa */ + struct pipe_resource templat; + memset(&templat, 0, sizeof(templat)); + templat.target = target; + templat.width0 = Width; + templat.height0 = Height; + templat.depth0 = Depth; + templat.last_level = MipLevels ? (MipLevels - 1) : 0; + templat.format = dxgi_to_pipe_format[Format]; + templat.bind = d3d11_to_pipe_bind_flags(BindFlags); + if(CPUAccessFlags & D3D11_CPU_ACCESS_READ) + templat.bind |= PIPE_BIND_TRANSFER_READ; + if(CPUAccessFlags & D3D11_CPU_ACCESS_WRITE) + templat.bind |= PIPE_BIND_TRANSFER_WRITE; + if(MiscFlags & D3D11_RESOURCE_MISC_SHARED) + templat.bind |= PIPE_BIND_SHARED; + if(MiscFlags & 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(pInitialData) + { + for(unsigned slice = 0; slice < ArraySize; ++slice) + { + for(unsigned level = 0; level <= templat.last_level; ++level) + { + struct pipe_subresource sr; + sr.level = level; + sr.face = slice; + struct pipe_box box; + box.x = box.y = box.z = 0; + 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, sr, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD | PIPE_TRANSFER_UNSYNCHRONIZED, &box, pInitialData->pSysMem, pInitialData->SysMemPitch, pInitialData->SysMemSlicePitch); + ++pInitialData; + } + } + } + *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( + __in const D3D11_TEXTURE1D_DESC *pDesc, + __in_xcount_opt(pDesc->MipLevels * pDesc->ArraySize) const D3D11_SUBRESOURCE_DATA *pInitialData, + __out_opt ID3D11Texture1D **ppTexture1D) + { + SYNCHRONIZED; + + struct pipe_resource* resource; + DXGI_USAGE dxgi_usage = d3d_to_dxgi_usage(pDesc->BindFlags, pDesc->MiscFlags); + HRESULT hr = create_resource(PIPE_TEXTURE_1D, pDesc->Width, 1, 1, pDesc->MipLevels, pDesc->ArraySize, pDesc->Format, 0, pDesc->Usage, pDesc->BindFlags, pDesc->CPUAccessFlags, pDesc->MiscFlags, pInitialData, dxgi_usage, ppTexture1D ? &resource : 0); + if(hr != S_OK) + return hr; + *ppTexture1D = new GalliumD3D11Texture1D(this, resource, *pDesc, dxgi_usage); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CreateTexture2D( + __in const D3D11_TEXTURE2D_DESC *pDesc, + __in_xcount_opt(pDesc->MipLevels * pDesc->ArraySize) const D3D11_SUBRESOURCE_DATA *pInitialData, + __out_opt ID3D11Texture2D **ppTexture2D) + { + SYNCHRONIZED; + + struct pipe_resource* resource; + DXGI_USAGE dxgi_usage = d3d_to_dxgi_usage(pDesc->BindFlags, pDesc->MiscFlags); + HRESULT hr = create_resource(PIPE_TEXTURE_2D, pDesc->Width, pDesc->Height, 1, pDesc->MipLevels, pDesc->ArraySize, pDesc->Format, &pDesc->SampleDesc, pDesc->Usage, pDesc->BindFlags, pDesc->CPUAccessFlags, pDesc->MiscFlags, pInitialData, dxgi_usage, ppTexture2D ? &resource : 0); + if(hr != S_OK) + return hr; + if(pDesc->MipLevels == 1 && pDesc->ArraySize == 1) + *ppTexture2D = new GalliumD3D11Surface(this, resource, *pDesc, dxgi_usage); + else + *ppTexture2D = new GalliumD3D11Texture2D(this, resource, *pDesc, dxgi_usage); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CreateTexture3D( + __in const D3D11_TEXTURE3D_DESC *pDesc, + __in_xcount_opt(pDesc->MipLevels) const D3D11_SUBRESOURCE_DATA *pInitialData, + __out_opt ID3D11Texture3D **ppTexture3D) + { + SYNCHRONIZED; + + struct pipe_resource* resource; + DXGI_USAGE dxgi_usage = d3d_to_dxgi_usage(pDesc->BindFlags, pDesc->MiscFlags); + HRESULT hr = create_resource(PIPE_TEXTURE_3D, pDesc->Width, pDesc->Height, pDesc->Depth, pDesc->MipLevels, 1, pDesc->Format, 0, pDesc->Usage, pDesc->BindFlags, pDesc->CPUAccessFlags, pDesc->MiscFlags, pInitialData, dxgi_usage, ppTexture3D ? &resource : 0); + if(hr != S_OK) + return hr; + *ppTexture3D = new GalliumD3D11Texture3D(this, resource, *pDesc, dxgi_usage); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CreateBuffer( + __in const D3D11_BUFFER_DESC *pDesc, + __in_opt const D3D11_SUBRESOURCE_DATA *pInitialData, + __out_opt ID3D11Buffer **ppBuffer) + { + SYNCHRONIZED; + +#if API >= 11 + if(pDesc->StructureByteStride > 1) + return E_NOTIMPL; +#endif + struct pipe_resource* resource; + DXGI_USAGE dxgi_usage = d3d_to_dxgi_usage(pDesc->BindFlags, pDesc->MiscFlags); + HRESULT hr = create_resource(PIPE_BUFFER, pDesc->ByteWidth, 1, 1, 1, 1, DXGI_FORMAT_R8_UNORM, 0, pDesc->Usage, pDesc->BindFlags, pDesc->CPUAccessFlags, pDesc->MiscFlags, pInitialData, dxgi_usage, ppBuffer ? &resource : 0); + if(hr != S_OK) + return hr; + *ppBuffer = new GalliumD3D11Buffer(this, resource, *pDesc, dxgi_usage); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE OpenGalliumResource( + __in struct pipe_resource* resource, + __out 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( + __in const DXGI_SURFACE_DESC *pDesc, + unsigned NumSurfaces, + DXGI_USAGE Usage, + __in_opt const DXGI_SHARED_RESOURCE *pSharedResource, + __out IDXGISurface **ppSurface) + { + SYNCHRONIZED; + + D3D11_TEXTURE2D_DESC desc; + memset(&desc, 0, sizeof(desc)); + + struct pipe_resource* resource; + desc.Width = pDesc->Width; + desc.Height = pDesc->Height; + desc.Format = pDesc->Format; + desc.SampleDesc = pDesc->SampleDesc; + desc.ArraySize = NumSurfaces; + 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, pDesc->Width, pDesc->Height, 1, 1, NumSurfaces, pDesc->Format, &pDesc->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; + *ppSurface = new GalliumD3D11Surface(this, resource, desc, Usage); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CreateShaderResourceView( + __in ID3D11Resource *pResource, + __in_opt const D3D11_SHADER_RESOURCE_VIEW_DESC *pDesc, + __out_opt ID3D11ShaderResourceView **ppSRView) + { +#if API >= 11 + D3D11_SHADER_RESOURCE_VIEW_DESC def_desc; +#else + if(pDesc->ViewDimension == D3D10_1_SRV_DIMENSION_TEXTURECUBEARRAY) + return E_INVALIDARG; + D3D10_SHADER_RESOURCE_VIEW_DESC1 desc1; + memset(&desc1, 0, sizeof(desc1)); + memcpy(&desc1, pDesc, sizeof(*pDesc)); + return CreateShaderResourceView1(pResource, &desc1, (ID3D10ShaderResourceView1**)ppSRView); + } + + virtual HRESULT STDMETHODCALLTYPE CreateShaderResourceView1( + __in ID3D11Resource *pResource, + __in_opt const D3D10_SHADER_RESOURCE_VIEW_DESC1 *pDesc, + __out_opt ID3D10ShaderResourceView1 **ppSRView) + { + D3D10_SHADER_RESOURCE_VIEW_DESC1 def_desc; +#endif + SYNCHRONIZED; + + if(!pDesc) + { + struct pipe_resource* resource = ((GalliumD3D11Resource<>*)pResource)->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 = 1; +#if API >= 11 + def_desc.Buffer.NumElements = resource->width0; +#endif + 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; + } + pDesc = &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[pDesc->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<>*)pResource)->resource; + switch(pDesc->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.first_level = pDesc->Texture1D.MostDetailedMip; + templat.last_level = templat.first_level + pDesc->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(!ppSRView) + return S_FALSE; + + struct pipe_sampler_view* view = immediate_pipe->create_sampler_view(immediate_pipe, templat.texture, &templat); + if(!view) + return E_FAIL; + *ppSRView = new GalliumD3D11ShaderResourceView(this, (GalliumD3D11Resource<>*)pResource, view, *pDesc); + return S_OK; + } + +#if API >= 11 + virtual HRESULT STDMETHODCALLTYPE CreateUnorderedAccessView( + __in ID3D11Resource *pResource, + __in_opt const D3D11_UNORDERED_ACCESS_VIEW_DESC *pDesc, + __out_opt ID3D11UnorderedAccessView **ppUAView) + { + SYNCHRONIZED; + + return E_NOTIMPL; + + // remember to return S_FALSE and not crash if ppUAView == 0 and parameters are valid + } +#endif + + virtual HRESULT STDMETHODCALLTYPE CreateRenderTargetView( + __in ID3D11Resource *pResource, + __in_opt const D3D11_RENDER_TARGET_VIEW_DESC *pDesc, + __out_opt ID3D11RenderTargetView **ppRTView) + { + SYNCHRONIZED; + + D3D11_RENDER_TARGET_VIEW_DESC def_desc; + if(!pDesc) + { + struct pipe_resource* resource = ((GalliumD3D11Resource<>*)pResource)->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 = 1; +#if API >= 11 + def_desc.Buffer.NumElements = resource->width0; +#endif + 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; + } + pDesc = &def_desc; + } + + unsigned zslice = 0; + unsigned face = 0; + unsigned level; + enum pipe_format format; + if(invalid(pDesc->Format >= DXGI_FORMAT_COUNT)) + return E_INVALIDARG; + format = dxgi_to_pipe_format[pDesc->Format]; + if(!format) + return E_NOTIMPL; + + switch(pDesc->ViewDimension) + { + case D3D11_RTV_DIMENSION_TEXTURE1D: + case D3D11_RTV_DIMENSION_TEXTURE2D: + level = pDesc->Texture1D.MipSlice; + break; + case D3D11_RTV_DIMENSION_TEXTURE3D: + level = pDesc->Texture3D.MipSlice; + zslice = pDesc->Texture3D.FirstWSlice; + break; + case D3D11_RTV_DIMENSION_TEXTURE1DARRAY: + case D3D11_RTV_DIMENSION_TEXTURE2DARRAY: + level = pDesc->Texture1DArray.MipSlice; + face = pDesc->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(!ppRTView) + return S_FALSE; + + struct pipe_surface* surface = screen->get_tex_surface(screen, + ((GalliumD3D11Resource<>*)pResource)->resource, + face, level, zslice, PIPE_BIND_RENDER_TARGET); + if(!surface) + return E_FAIL; + /* muhahahahaha, let's hope this actually works */ + surface->format = format; + *ppRTView = new GalliumD3D11RenderTargetView(this, (GalliumD3D11Resource<>*)pResource, surface, *pDesc); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CreateDepthStencilView( + __in ID3D11Resource *pResource, + __in_opt const D3D11_DEPTH_STENCIL_VIEW_DESC *pDesc, + __out_opt ID3D11DepthStencilView **ppDepthStencilView) + { + SYNCHRONIZED; + + D3D11_DEPTH_STENCIL_VIEW_DESC def_desc; + if(!pDesc) + { + struct pipe_resource* resource = ((GalliumD3D11Resource<>*)pResource)->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; + } + pDesc = &def_desc; + } + + unsigned zslice = 0; + unsigned face = 0; + unsigned level; + enum pipe_format format; + if(invalid(pDesc->Format >= DXGI_FORMAT_COUNT)) + return E_INVALIDARG; + format = dxgi_to_pipe_format[pDesc->Format]; + if(!format) + return E_NOTIMPL; + + switch(pDesc->ViewDimension) + { + case D3D11_DSV_DIMENSION_TEXTURE1D: + case D3D11_DSV_DIMENSION_TEXTURE2D: + level = pDesc->Texture1D.MipSlice; + break; + case D3D11_DSV_DIMENSION_TEXTURE1DARRAY: + case D3D11_DSV_DIMENSION_TEXTURE2DARRAY: + level = pDesc->Texture1DArray.MipSlice; + face = pDesc->Texture1DArray.FirstArraySlice; + break; + case D3D11_DSV_DIMENSION_TEXTURE2DMS: + case D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY: + return E_NOTIMPL; + default: + return E_INVALIDARG; + } + + if(!ppDepthStencilView) + return S_FALSE; + + struct pipe_surface* surface = screen->get_tex_surface(screen, + ((GalliumD3D11Resource<>*)pResource)->resource, + face, level, zslice, PIPE_BIND_DEPTH_STENCIL); + if(!surface) + return E_FAIL; + /* muhahahahaha, let's hope this actually works */ + surface->format = format; + *ppDepthStencilView = new GalliumD3D11DepthStencilView(this, (GalliumD3D11Resource<>*)pResource, surface, *pDesc); + return S_OK; + } + + GalliumD3D11Shader<>* create_stage_shader(unsigned type, const void *pShaderBytecode, SIZE_T BytecodeLength +#if API >= 11 + , __in_opt ID3D11ClassLinkage *pClassLinkage +#endif + ) + { + dxbc_chunk_header* tpf_chunk = dxbc_find_shader_bytecode(pShaderBytecode, BytecodeLength); + if(!tpf_chunk) + return 0; + + std::auto_ptr<tpf_program> tpf(tpf_parse(tpf_chunk + 1, bswap_le32(tpf_chunk->size))); + if(!tpf.get()) + return 0; + + struct pipe_shader_state tgsi_shader; + memset(&tgsi_shader, 0, sizeof(tgsi_shader)); + tgsi_shader.tokens = (const tgsi_token*)tpf_to_tgsi(*tpf); + if(!tgsi_shader.tokens) + return 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 = tpf->slot_to_resource; + shader->slot_to_sampler = tpf->slot_to_sampler; + } + + free((void*)tgsi_shader.tokens); + return shader; + } + +#if API >= 11 +#define CREATE_SHADER_ARGS \ + __in const void *pShaderBytecode, \ + __in SIZE_T BytecodeLength, \ + __in_opt ID3D11ClassLinkage *pClassLinkage +#define PASS_SHADER_ARGS pShaderBytecode, BytecodeLength, pClassLinkage +#else +#define CREATE_SHADER_ARGS \ + __in const void *pShaderBytecode, \ + __in SIZE_T BytecodeLength +#define PASS_SHADER_ARGS pShaderBytecode, BytecodeLength +#endif + +#define IMPLEMENT_CREATE_SHADER(Stage, GALLIUM) \ + virtual HRESULT STDMETHODCALLTYPE Create##Stage##Shader( \ + CREATE_SHADER_ARGS, \ + __out_opt ID3D11##Stage##Shader **pp##Stage##Shader) \ + { \ + SYNCHRONIZED; \ + GalliumD3D11##Stage##Shader* shader = (GalliumD3D11##Stage##Shader*)create_stage_shader(PIPE_SHADER_##GALLIUM, PASS_SHADER_ARGS); \ + if(!shader) \ + return E_FAIL; \ + if(pp##Stage##Shader) \ + { \ + *pp##Stage##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, \ + __out_opt ID3D11##Stage##Shader **pp##Stage##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( + __in const void *pShaderBytecode, + __in SIZE_T BytecodeLength, + __in_ecount_opt(NumEntries) const D3D11_SO_DECLARATION_ENTRY *pSODeclaration, + __in_range(0, D3D11_SO_STREAM_COUNT * D3D11_SO_OUTPUT_COMPONENT_COUNT) unsigned NumEntries, +#if API >= 11 + __in_ecount_opt(NumStrides) const unsigned *pBufferStrides, + __in_range(0, D3D11_SO_BUFFER_SLOT_COUNT) unsigned NumStrides, + __in unsigned RasterizedStream, + __in_opt ID3D11ClassLinkage *pClassLinkage, +#else + __in UINT OutputStreamStride, +#endif + __out_opt ID3D11GeometryShader **ppGeometryShader) + { + SYNCHRONIZED; + + if(!ppGeometryShader) + return S_FALSE; + + return E_NOTIMPL; + + // remember to return S_FALSE if ppGeometyShader == NULL and the shader is OK + } + +#if API >= 11 + virtual HRESULT STDMETHODCALLTYPE CreateClassLinkage( + __out ID3D11ClassLinkage **ppLinkage) + { + SYNCHRONIZED; + + if(!ppLinkage) + return S_FALSE; + + return E_NOTIMPL; + } +#endif + + virtual HRESULT STDMETHODCALLTYPE CreateQuery( + __in const D3D11_QUERY_DESC *pQueryDesc, + __out_opt ID3D11Query **ppQuery) + { + SYNCHRONIZED; + + if(invalid(pQueryDesc->Query >= D3D11_QUERY_COUNT)) + return E_INVALIDARG; + unsigned query_type = d3d11_to_pipe_query[pQueryDesc->Query]; + if(!query_type) + return E_NOTIMPL; + + if(ppQuery) + return S_FALSE; + + struct pipe_query* query = immediate_pipe->create_query(immediate_pipe, query_type); + if(!query) + return E_FAIL; + + *ppQuery = new GalliumD3D11Query(this, query, d3d11_query_size[pQueryDesc->Query], *pQueryDesc); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE CreatePredicate( + __in const D3D11_QUERY_DESC *pPredicateDesc, + __out_opt ID3D11Predicate **ppPredicate) + { + SYNCHRONIZED; + + unsigned query_type; + switch(pPredicateDesc->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(ppPredicate) + return S_FALSE; + + struct pipe_query* query = immediate_pipe->create_query(immediate_pipe, query_type); + if(!query) + return E_FAIL; + + *ppPredicate = new GalliumD3D11Predicate(this, query, sizeof(BOOL), *pPredicateDesc); + return S_OK; + } + + + virtual HRESULT STDMETHODCALLTYPE CreateCounter( + __in const D3D11_COUNTER_DESC *pCounterDesc, + __out_opt ID3D11Counter **ppCounter) + { + SYNCHRONIZED; + + return E_NOTIMPL; + + // remember to return S_FALSE if ppCounter == NULL and everything is OK + } + +#if API >= 11 + virtual HRESULT STDMETHODCALLTYPE CreateDeferredContext( + unsigned ContextFlags, + __out_opt ID3D11DeviceContext **ppDeferredContext) + { + SYNCHRONIZED; + + // TODO: this will have to be implemented using a new Gallium util module + return E_NOTIMPL; + + // remember to return S_FALSE if ppCounter == NULL and everything is OK + } +#endif + + virtual HRESULT STDMETHODCALLTYPE OpenSharedResource( + __in HANDLE hResource, + __in REFIID ReturnedInterface, + __out_opt void **ppResource) + { + SYNCHRONIZED; + + // TODO: the problem here is that we need to communicate dimensions somehow + return E_NOTIMPL; + + // remember to return S_FALSE if ppCounter == NULL and everything is OK +#if 0 + struct pipe_resou rce templat; + struct winsys_handle handle; + handle.stride = 0; + handle.handle = hResource; + 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( + __in UINT Width, + __in UINT Height + ) + {} + + virtual void STDMETHODCALLTYPE GetTextFilterSize( + __in UINT *Width, + __in 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 +}; |