summaryrefslogtreecommitdiff
path: root/src/gallium/state_trackers/d3d1x/d3d1xstutil/include/d3d1xstutil.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/state_trackers/d3d1x/d3d1xstutil/include/d3d1xstutil.h')
-rw-r--r--src/gallium/state_trackers/d3d1x/d3d1xstutil/include/d3d1xstutil.h1110
1 files changed, 1110 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/d3d1x/d3d1xstutil/include/d3d1xstutil.h b/src/gallium/state_trackers/d3d1x/d3d1xstutil/include/d3d1xstutil.h
new file mode 100644
index 0000000000..af355f0227
--- /dev/null
+++ b/src/gallium/state_trackers/d3d1x/d3d1xstutil/include/d3d1xstutil.h
@@ -0,0 +1,1110 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#ifndef D3D1XSTUTIL_H_
+#define D3D1XSTUTIL_H_
+
+#ifdef _MSC_VER
+#include <unordered_map>
+#include <unordered_set>
+#else
+#include <tr1/unordered_map>
+#include <tr1/unordered_set>
+namespace std
+{
+ using namespace tr1;
+}
+#endif
+#include <map>
+#include <utility>
+
+#define WIN32_LEAN_AND_MEAN
+#include <objbase.h>
+
+#include "galliumdxgi.h"
+#include <d3dcommon.h>
+
+extern "C"
+{
+#include <util/u_atomic.h>
+#include <pipe/p_format.h>
+#include <os/os_thread.h>
+}
+
+#include <assert.h>
+#ifdef min
+#undef min
+#endif
+#ifdef max
+#undef max
+#endif
+
+#define D3D_PRIMITIVE_TOPOLOGY_COUNT 65
+extern unsigned d3d_to_pipe_prim[D3D_PRIMITIVE_TOPOLOGY_COUNT];
+
+#define D3D_PRIMITIVE_COUNT 40
+extern unsigned d3d_to_pipe_prim_type[D3D_PRIMITIVE_COUNT];
+
+/* NOTE: this _depends_ on the vtable layout of the C++ compiler to be
+ * binary compatible with Windows.
+ * Furthermore some absurd vtable layout likely won't work at all, since
+ * we perform some casts which are probably not safe by the C++ standard.
+ *
+ * In particular, the GNU/Linux/Itanium/clang ABI and Microsoft ABIs will work,
+ * but others may not.
+ * If in doubt, just switch to the latest version of a widely used C++ compiler.
+ *
+ * DESIGN of the Gallium COM implementation
+ *
+ * This state tracker uses somewhat unusual C++ coding patterns,
+ * to implement the COM interfaces required by Direct3D.
+ *
+ * While it may seem complicated, the effect is that the result
+ * generally behaves as intuitively as possible: in particular pointer
+ * casts very rarely change the pointer value (only for secondary
+ * DXGI/Gallium interfaces)
+ *
+ * Implementing COM is on first sight very easy: after all, it just
+ * consists of a reference count, and a dynamic_cast<> equivalent.
+ *
+ * However, implementing objects with multiple interfaces is actually
+ * quite tricky.
+ * The issue is that the interface pointers can't be equal, since this
+ * would place incompatible constraints on the vtable layout and thus
+ * multiple inheritance (and the subobjects the C++ compiler creates
+ * with it) must be correctly used.
+ *
+ * Furthermore, we must have a single reference count, which means
+ * that a naive implementation won't work, and it's necessary to either
+ * use virtual inheritance, or the "mixin inheritance" model we use.
+ *
+ * This solution aims to achieve the following object layout:
+ * 0: pointer to vtable for primary interface
+ * 1: reference count
+ * ... main class
+ * ... vtable pointers for secondary interfaces
+ * ... implementation of subclasses assuming secondary interfaces
+ *
+ * This allows us to cast pointers by just reinterpreting the value in
+ * almost all cases.
+ *
+ * To achieve this, *all* non-leaf classes must have their parent
+ * or the base COM interface as a template parameter, since derived
+ * classes may need to change that to support an interface derived
+ * from the one implemented by the superclass.
+ *
+ * Note however, that you can cast without regard to the template
+ * parameter, because only the vtable layout depends on it, since
+ * interfaces have no data members.
+ *
+ * For this to work, DON'T USE VIRTUAL FUNCTIONS except to implement
+ * interfaces, since the vtable layouts would otherwise be mismatched.
+ * An exception are virtual functions called only from other virtual functions,
+ * which is currently only used for the virtual destructor.
+ *
+ * The base class is GalliumComObject<IFoo>, which implements the
+ * IUnknown interface, and inherits IFoo.
+ *
+ * To support multiple inheritance, we insert GalliumMultiComObject,
+ * which redirects the secondary interfaces to the GalliumComObject
+ * superclass.
+ *
+ * Gallium(Multi)PrivateDataComObject is like ComObject but also
+ * implements the Get/SetPrivateData functions present on several
+ * D3D/DXGI interfaces.
+ *
+ * Example class hierarchy:
+ *
+ * IUnknown
+ * (pure interface)
+ * |
+ * V
+ * IAnimal
+ * (pure interface)
+ * |
+ * V
+ * IDuck
+ * (pure interface)
+ * |
+ * V
+ * GalliumComObject<IDuck>
+ * (non-instantiable, only implements IUnknown)
+ * |
+ * V
+ * GalliumAnimal<IDuck>
+ * (non-instantiable, only implements IAnimal)
+ * |
+ * V
+ * GalliumDuck
+ * (concrete)
+ * |
+ * V
+ * GalliumMultiComObject<GalliumDuck, IWheeledVehicle> <- IWheeledVehicle <- IVehicle <- IUnknown (second version)
+ * (non-instantiable, only implements IDuck and the IUnknown of IWheeledVehicle)
+ * |
+ * V
+ * GalliumDuckOnWheels
+ * (concrete)
+ *
+ * This will produce the desired layout.
+ * Note that GalliumAnimal<IFoo>* is safely castable to GalliumAnimal<IBar>*
+ * by reinterpreting, as long as non-interface virtual functions are not used,
+ * and that you only call interface functions for the superinterface of IBar
+ * that the object actually implements.
+ *
+ * Instead, if GalliumDuck where to inherit both from GalliumAnimal
+ * and IDuck, then (IDuck*)gallium_duck and (IAnimal*)gallium_duck would
+ * have different pointer values, which the "base class as template parameter"
+ * trick avoids.
+ *
+ * The price we pay is that you MUST NOT have virtual functions other than those
+ * implementing interfaces (except for leaf classes) since the position of these
+ * would depend on the base interface.
+ * As mentioned above, virtual functions only called from interface functions
+ * are an exception, currently used only for the virtual destructor.
+ * If you want virtual functions anyway , put them in a separate interface class,
+ * multiply inherit from that and cast the pointer to that interface.
+ *
+ * You CAN however have virtual functions on any class which does not specify
+ * his base as a template parameter, or where you don't need to change the
+ * template base interface parameter by casting.
+ *
+ * --- The magic QueryInterface "delete this" trick ---
+ *
+ * When the reference count drops to 0, we must delete the class.
+ * The problem is, that we must call the right virtual destructor (i.e. on the right class).
+ * However, we would like to be able to call release() and nonatomic_release()
+ * non-virtually for performance (also, the latter cannot be called virtually at all, since
+ * IUnknown does not offer it).
+ *
+ * The naive solution would be to just add a virtual destructor and rely on it.
+ * However, this doesn't work due to the fact that as described above we perform casets
+ * with are unsafe regarding vtable layout.
+ * In particular, consider the case where we try to delete GalliumComObject<ID3D11Texture2D>
+ * with a pointer to GalliumComObject<ID3D11Resource>.
+ * Since we think that this is a GalliumComObject<ID3D11Resource>, we'll look for the
+ * destructor in the vtable slot immediately after the ID3D11Resource vtable, but this is
+ * actually an ID3D11Texture2D function implemented by the object!
+ *
+ * So, we must put the destructor somewhere else.
+ * We could add it as a data member, but it would be awkward and it would bloat the
+ * class.
+ * Thus, we use this trick: we reuse the vtable slot for QueryInterface, which is always at the
+ * same position.
+ * To do so, we define a special value for the first pointer argument, that triggers a
+ * "delete this".
+ * In addition to that, we add a virtual destructor to GalliumComObject.
+ * That virtual destructor will be called by QueryInterface, and since that is a virtual
+ * function, it will know the correct place for the virtual destructor.
+ *
+ * QueryInterface is already slow due to the need to compare several GUIDs, so the
+ * additional pointer test should not be significant.
+ *
+ * Of course the ideal solution would be telling the C++ compiler to put the
+ * destructor it in a negative vtable slot, but unfortunately GCC doesn't support that
+ * yet, and this method is almost as good as that.
+ */
+
+template<typename T>
+struct com_traits;
+
+#define COM_INTERFACE(intf, base) \
+template<> \
+struct com_traits<intf> \
+{ \
+ static REFIID iid() {return IID_##intf;} \
+ static inline bool is_self_or_ancestor(REFIID riid) {return riid == iid() || com_traits<base>::is_self_or_ancestor(riid);} \
+};
+
+template<>
+struct com_traits<IUnknown>
+{
+ static REFIID iid() {return IID_IUnknown;}
+ static inline bool is_self_or_ancestor(REFIID riid) {return riid == iid();}
+};
+
+#ifndef _MSC_VER
+#define __uuidof(T) (com_traits<T>::iid())
+#endif
+
+struct refcnt_t
+{
+ uint32_t refcnt;
+
+ refcnt_t(unsigned v = 1)
+ : refcnt(v)
+ {}
+
+ unsigned add_ref()
+ {
+ p_atomic_inc((int32_t*)&refcnt);
+ return refcnt;
+ }
+
+ unsigned release()
+ {
+ if(p_atomic_dec_zero((int32_t*)&refcnt))
+ return 0;
+ return refcnt;
+ }
+
+ void nonatomic_add_ref()
+ {
+ p_atomic_inc((int32_t*)&refcnt);
+ }
+
+ unsigned nonatomic_release()
+ {
+ if(p_atomic_dec_zero((int32_t*)&refcnt))
+ return 0;
+ else
+ return 1;
+ }
+};
+
+#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
+/* this should be safe because atomic ops are full memory barriers, and thus a sequence that does:
+ * ++one_refcnt;
+ * --other_refcnt;
+ * should never be reorderable (as seen from another CPU) to:
+ * --other_refcnt
+ * ++one_refcnt
+ *
+ * since one of the ops is atomic.
+ * If this weren't the case, a CPU could incorrectly destroy an object manipulated in that way by another one.
+ */
+struct dual_refcnt_t
+{
+ union
+ {
+ uint64_t refcnt;
+ struct
+ {
+ uint32_t atomic_refcnt;
+ uint32_t nonatomic_refcnt;
+ };
+ };
+
+ dual_refcnt_t(unsigned v = 1)
+ {
+ atomic_refcnt = v;
+ nonatomic_refcnt = 0;
+ }
+
+ bool is_zero()
+ {
+ if(sizeof(void*) == 8)
+ return *(volatile uint64_t*)&refcnt == 0ULL;
+ else
+ {
+ uint64_t v;
+ do
+ {
+ v = refcnt;
+ }
+ while(!__sync_bool_compare_and_swap(&refcnt, v, v));
+ return v == 0ULL;
+ }
+ }
+
+ unsigned add_ref()
+ {
+ //printf("%p add_ref at %u %u\n", this, atomic_refcnt, nonatomic_refcnt);
+ p_atomic_inc((int32_t*)&atomic_refcnt);
+ return atomic_refcnt + nonatomic_refcnt;
+ }
+
+ unsigned release()
+ {
+ //printf("%p release at %u %u\n", this, atomic_refcnt, nonatomic_refcnt);
+ if(p_atomic_dec_zero((int32_t*)&atomic_refcnt) && !nonatomic_refcnt && is_zero())
+ return 0;
+ unsigned v = atomic_refcnt + nonatomic_refcnt;
+ return v ? v : 1;
+ }
+
+ void nonatomic_add_ref()
+ {
+ //printf("%p nonatomic_add_ref at %u %u\n", this, atomic_refcnt, nonatomic_refcnt);
+ ++nonatomic_refcnt;
+ }
+
+ unsigned nonatomic_release()
+ {
+ //printf("%p nonatomic_release at %u %u\n", this, atomic_refcnt, nonatomic_refcnt);
+ if(!--nonatomic_refcnt)
+ {
+ __sync_synchronize();
+ if(!atomic_refcnt && is_zero())
+ return 0;
+ }
+ return 1;
+ }
+};
+#else
+// this will result in atomic operations being used while they could have been avoided
+#ifdef __i386__
+#warning Compile for 586+ using GCC to improve the performance of the Direct3D 10/11 state tracker
+#endif
+typedef refcnt_t dual_refcnt_t;
+#endif
+
+#define IID_MAGIC_DELETE_THIS (*(const IID*)((intptr_t)-(int)(sizeof(IID) - 1)))
+
+template<typename Base = IUnknown, typename RefCnt = refcnt_t>
+struct GalliumComObject : public Base
+{
+ RefCnt refcnt;
+
+ GalliumComObject()
+ {}
+
+ /* DO NOT CALL this from externally called non-virtual functions in derived classes, since
+ * the vtable position depends on the COM interface being implemented
+ */
+ virtual ~GalliumComObject()
+ {}
+
+ inline ULONG add_ref()
+ {
+ return refcnt.add_ref();
+ }
+
+ inline ULONG release()
+ {
+ ULONG v = refcnt.release();
+ if(!v)
+ {
+ /* this will call execute "delete this", using the correct vtable slot for the destructor */
+ /* see the initial comment for an explaination of this magic trick */
+ this->QueryInterface(IID_MAGIC_DELETE_THIS, 0);
+ return 0;
+ }
+ return v;
+ }
+
+ inline void nonatomic_add_ref()
+ {
+ refcnt.nonatomic_add_ref();
+ }
+
+ inline void nonatomic_release()
+ {
+ if(!refcnt.nonatomic_release())
+ {
+ /* this will execute "delete this", using the correct vtable slot for the destructor */
+ /* see the initial comment for an explaination of this magic trick */
+ this->QueryInterface(IID_MAGIC_DELETE_THIS, 0);
+ }
+ }
+
+ inline HRESULT query_interface(REFIID riid, void **ppvObject)
+ {
+ if(com_traits<Base>::is_self_or_ancestor(riid))
+ {
+ // must be the virtual AddRef, since it is overridden by some classes
+ this->AddRef();
+ *ppvObject = this;
+ return S_OK;
+ }
+ else
+ return E_NOINTERFACE;
+ }
+
+ virtual ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return add_ref();
+ }
+
+ virtual ULONG STDMETHODCALLTYPE Release()
+ {
+ return release();
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void **ppvObject)
+ {
+ /* see the initial comment for an explaination of this magic trick */
+ if(&riid == &IID_MAGIC_DELETE_THIS)
+ {
+ delete this;
+ return 0;
+ }
+ if(!this)
+ return E_INVALIDARG;
+ if(!ppvObject)
+ return E_POINTER;
+ return query_interface(riid, ppvObject);
+ }
+};
+
+template<typename BaseClass, typename SecondaryInterface>
+struct GalliumMultiComObject : public BaseClass, SecondaryInterface
+{
+ // we could avoid this duplication, but the increased complexity to do so isn't worth it
+ virtual ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return BaseClass::add_ref();
+ }
+
+ virtual ULONG STDMETHODCALLTYPE Release()
+ {
+ return BaseClass::release();
+ }
+
+ inline HRESULT query_interface(REFIID riid, void **ppvObject)
+ {
+ HRESULT hr = BaseClass::query_interface(riid, ppvObject);
+ if(SUCCEEDED(hr))
+ return hr;
+ if(com_traits<SecondaryInterface>::is_self_or_ancestor(riid))
+ {
+ // must be the virtual AddRef, since it is overridden by some classes
+ this->AddRef();
+ *ppvObject = (SecondaryInterface*)this;
+ return S_OK;
+ }
+ else
+ return E_NOINTERFACE;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void **ppvObject)
+ {
+ /* see the initial comment for an explaination of this magic trick */
+ if(&riid == &IID_MAGIC_DELETE_THIS)
+ {
+ delete this;
+ return 0;
+ }
+ if(!this)
+ return E_INVALIDARG;
+ if(!ppvObject)
+ return E_POINTER;
+ return query_interface(riid, ppvObject);
+ }
+};
+
+template<typename T, typename Traits>
+struct refcnt_ptr
+{
+ T* p;
+
+ refcnt_ptr()
+ : p(0)
+ {}
+
+ void add_ref() {Traits::add_ref(p);}
+ void release() {Traits::release(p);}
+
+ template<typename U, typename UTraits>
+ refcnt_ptr(const refcnt_ptr<U, UTraits>& c)
+ {
+ *this = static_cast<U*>(c.ref());
+ }
+
+ ~refcnt_ptr()
+ {
+ release();
+ }
+
+ void reset(T* q)
+ {
+ release();
+ p = q;
+ }
+
+ template<typename U, typename UTraits>
+ refcnt_ptr& operator =(const refcnt_ptr<U, UTraits>& q)
+ {
+ return *this = q.p;
+ }
+
+ template<typename U>
+ refcnt_ptr& operator =(U* q)
+ {
+ release();
+ p = static_cast<T*>(q);
+ add_ref();
+ return *this;
+ }
+
+ T* ref()
+ {
+ add_ref();
+ return p;
+ }
+
+ T* steal()
+ {
+ T* ret = p;
+ p = 0;
+ return ret;
+ }
+
+ T* operator ->()
+ {
+ return p;
+ }
+
+ const T* operator ->() const
+ {
+ return p;
+ }
+
+ T** operator &()
+ {
+ assert(!p);
+ return &p;
+ }
+
+ bool operator !() const
+ {
+ return !p;
+ }
+
+ typedef T* refcnt_ptr::*unspecified_bool_type;
+
+ operator unspecified_bool_type() const
+ {
+ return p ? &refcnt_ptr::p : 0;
+ }
+};
+
+struct simple_ptr_traits
+{
+ static void add_ref(void* p) {}
+ static void release(void* p) {}
+};
+
+struct com_ptr_traits
+{
+ static void add_ref(void* p)
+ {
+ if(p)
+ ((IUnknown*)p)->AddRef();
+ }
+
+ static void release(void* p)
+ {
+ if(p)
+ ((IUnknown*)p)->Release();
+ }
+};
+
+template<typename T>
+struct ComPtr : public refcnt_ptr<T, com_ptr_traits>
+{
+ template<typename U, typename UTraits>
+ ComPtr& operator =(const refcnt_ptr<U, UTraits>& q)
+ {
+ return *this = q.p;
+ }
+
+ template<typename U>
+ ComPtr& operator =(U* q)
+ {
+ this->release();
+ this->p = static_cast<T*>(q);
+ this->add_ref();
+ return *this;
+ }
+};
+
+template<typename T, typename TTraits, typename U, typename UTraits>
+bool operator ==(const refcnt_ptr<T, TTraits>& a, const refcnt_ptr<U, UTraits>& b)
+{
+ return a.p == b.p;
+}
+
+template<typename T, typename TTraits, typename U>
+bool operator ==(const refcnt_ptr<T, TTraits>& a, U* b)
+{
+ return a.p == b;
+}
+
+template<typename T, typename TTraits, typename U>
+bool operator ==(U* b, const refcnt_ptr<T, TTraits>& a)
+{
+ return a.p == b;
+}
+
+template<typename T, typename TTraits, typename U, typename UTraits>
+bool operator !=(const refcnt_ptr<T, TTraits>& a, const refcnt_ptr<U, UTraits>& b)
+{
+ return a.p != b.p;
+}
+
+template<typename T, typename TTraits, typename U>
+bool operator !=(const refcnt_ptr<T, TTraits>& a, U* b)
+{
+ return a.p != b;
+}
+
+template<typename T, typename TTraits, typename U>
+bool operator !=(U* b, const refcnt_ptr<T, TTraits>& a)
+{
+ return a.p != b;
+}
+
+template<bool threadsafe>
+struct maybe_mutex_t;
+
+template<>
+struct maybe_mutex_t<true>
+{
+ pipe_mutex mutex;
+
+ maybe_mutex_t()
+ {
+ pipe_mutex_init(mutex);
+ }
+
+ void lock()
+ {
+ pipe_mutex_lock(mutex);
+ }
+
+ void unlock()
+ {
+ pipe_mutex_unlock(mutex);
+ }
+};
+
+template<>
+struct maybe_mutex_t<false>
+{
+ void lock()
+ {
+ }
+
+ void unlock()
+ {
+ }
+};
+
+typedef maybe_mutex_t<true> mutex_t;
+
+template<typename T>
+struct lock_t
+{
+ T& mutex;
+ lock_t(T& mutex)
+ : mutex(mutex)
+ {
+ mutex.lock();
+ }
+
+ ~lock_t()
+ {
+ mutex.unlock();
+ }
+};
+
+struct c_string
+{
+ const char* p;
+ c_string(const char* p)
+ : p(p)
+ {}
+
+ operator const char*() const
+ {
+ return p;
+ }
+};
+
+static inline bool operator ==(const c_string& a, const c_string& b)
+{
+ return !strcmp(a.p, b.p);
+}
+
+static inline bool operator !=(const c_string& a, const c_string& b)
+{
+ return strcmp(a.p, b.p);
+}
+
+static inline size_t raw_hash(const char* p, size_t size)
+{
+ size_t res;
+ if(sizeof(size_t) >= 8)
+ res = (size_t)14695981039346656037ULL;
+ else
+ res = (size_t)2166136261UL;
+ const char* end = p + size;
+ for(; p != end; ++p)
+ {
+ res ^= (size_t)*p;
+ if(sizeof(size_t) >= 8)
+ res *= (size_t)1099511628211ULL;
+ else
+ res *= (size_t)16777619UL;
+ }
+ return res;
+};
+
+template<typename T>
+static inline size_t raw_hash(const T& t)
+{
+ return raw_hash((const char*)&t, sizeof(t));
+}
+
+// TODO: only tested with the gcc libstdc++, might not work elsewhere
+namespace std
+{
+#ifndef _MSC_VER
+ namespace tr1
+ {
+#endif
+ template<>
+ struct hash<GUID> : public std::unary_function<GUID, size_t>
+ {
+ inline size_t operator()(GUID __val) const;
+ };
+
+ inline size_t hash<GUID>::operator()(GUID __val) const
+ {
+ return raw_hash(__val);
+ }
+
+ template<>
+ struct hash<c_string> : public std::unary_function<c_string, size_t>
+ {
+ inline size_t operator()(c_string __val) const;
+ };
+
+ inline size_t hash<c_string>::operator()(c_string __val) const
+ {
+ return raw_hash(__val.p, strlen(__val.p));
+ }
+
+ template<typename T, typename U>
+ struct hash<std::pair<T, U> > : public std::unary_function<std::pair<T, U>, size_t>
+ {
+ inline size_t operator()(std::pair<T, U> __val) const;
+ };
+
+ template<typename T, typename U>
+ inline size_t hash<std::pair<T, U> >::operator()(std::pair<T, U> __val) const
+ {
+ std::pair<size_t, size_t> p;
+ p.first = hash<T>()(__val.first);
+ p.second = hash<U>()(__val.second);
+ return raw_hash(p);
+ }
+#ifndef _MSC_VER
+ }
+#endif
+}
+
+template<typename Base, typename RefCnt = refcnt_t>
+struct GalliumPrivateDataComObject : public GalliumComObject<Base, RefCnt>
+{
+ typedef std::unordered_map<GUID, std::pair<void*, unsigned> > private_data_map_t;
+ private_data_map_t private_data_map;
+ mutex_t private_data_mutex;
+
+ ~GalliumPrivateDataComObject()
+ {
+ for(private_data_map_t::iterator i = private_data_map.begin(), e = private_data_map.end(); i != e; ++i)
+ {
+ if(i->second.second == ~0u)
+ ((IUnknown*)i->second.first)->Release();
+ else
+ free(i->second.first);
+ }
+ }
+
+ HRESULT get_private_data(
+ REFGUID guid,
+ UINT *pDataSize,
+ void *pData)
+ {
+ lock_t<mutex_t> lock(private_data_mutex);
+ private_data_map_t::iterator i = private_data_map.find(guid);
+ *pDataSize = 0;
+ if(i == private_data_map.end())
+ return DXGI_ERROR_NOT_FOUND;
+ if(i->second.second == ~0u)
+ {
+ /* TODO: is GetPrivateData on interface data supposed to do this? */
+ if(*pDataSize < sizeof(void*))
+ return E_INVALIDARG;
+ if(pData)
+ {
+ memcpy(pData, &i->second.first, sizeof(void*));
+ ((IUnknown*)i->second.first)->AddRef();
+ }
+ *pDataSize = sizeof(void*);
+ }
+ else
+ {
+ unsigned size = std::min(*pDataSize, i->second.second);
+ if(pData)
+ memcpy(pData, i->second.first, size);
+ *pDataSize = size;
+ }
+ return S_OK;
+ }
+
+ HRESULT set_private_data(
+ REFGUID guid,
+ UINT DataSize,
+ const void *pData)
+ {
+ void* p = 0;
+
+ if(DataSize && pData)
+ {
+ p = malloc(DataSize);
+ if(!p)
+ return E_OUTOFMEMORY;
+ }
+
+ lock_t<mutex_t> lock(private_data_mutex);
+ std::pair<void*, unsigned>& v = private_data_map[guid];
+ if(v.first)
+ {
+ if(v.second == ~0u)
+ ((IUnknown*)v.first)->Release();
+ else
+ free(v.first);
+ }
+ if(DataSize && pData)
+ {
+ memcpy(p, pData, DataSize);
+ v.first = p;
+ v.second = DataSize;
+ }
+ else
+ private_data_map.erase(guid);
+ return S_OK;
+ }
+
+ HRESULT set_private_data_interface(
+ REFGUID guid,
+ const IUnknown *pData)
+ {
+ lock_t<mutex_t> lock(private_data_mutex);
+ std::pair<void*, unsigned>& v = private_data_map[guid];
+ if(v.first)
+ {
+ if(v.second == ~0u)
+ ((IUnknown*)v.first)->Release();
+ else
+ free(v.first);
+ }
+ if(pData)
+ {
+ ((IUnknown*)pData)->AddRef();
+ v.first = (void*)pData;
+ v.second = ~0;
+ }
+ else
+ private_data_map.erase(guid);
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT *pDataSize,
+ void *pData)
+ {
+ return get_private_data(guid, pDataSize, pData);
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void *pData)
+ {
+ return set_private_data(guid, DataSize, pData);
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown *pData)
+ {
+ return set_private_data_interface(guid, pData);
+ }
+};
+
+template<typename BaseClass, typename SecondaryInterface>
+struct GalliumMultiPrivateDataComObject : public GalliumMultiComObject<BaseClass, SecondaryInterface>
+{
+ // we could avoid this duplication, but the increased complexity to do so isn't worth it
+ virtual HRESULT STDMETHODCALLTYPE GetPrivateData(
+ REFGUID guid,
+ UINT *pDataSize,
+ void *pData)
+ {
+ return BaseClass::get_private_data(guid, pDataSize, pData);
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE SetPrivateData(
+ REFGUID guid,
+ UINT DataSize,
+ const void *pData)
+ {
+ return BaseClass::set_private_data(guid, DataSize, pData);
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(
+ REFGUID guid,
+ const IUnknown *pData)
+ {
+ return BaseClass::set_private_data_interface(guid, pData);
+ }
+};
+
+#define DXGI_FORMAT_COUNT 100
+extern pipe_format dxgi_to_pipe_format[DXGI_FORMAT_COUNT];
+extern DXGI_FORMAT pipe_to_dxgi_format[PIPE_FORMAT_COUNT];
+
+void init_pipe_to_dxgi_format();
+
+COM_INTERFACE(IGalliumDevice, IUnknown);
+COM_INTERFACE(IGalliumAdapter, IUnknown);
+COM_INTERFACE(IGalliumResource, IUnknown);
+
+// used to make QueryInterface know the IIDs of the interface and its ancestors
+COM_INTERFACE(IDXGIObject, IUnknown)
+COM_INTERFACE(IDXGIDeviceSubObject, IDXGIObject)
+COM_INTERFACE(IDXGISurface, IDXGIDeviceSubObject)
+COM_INTERFACE(IDXGIOutput, IDXGIObject)
+COM_INTERFACE(IDXGIAdapter, IDXGIObject)
+COM_INTERFACE(IDXGISwapChain, IDXGIDeviceSubObject)
+COM_INTERFACE(IDXGIFactory, IDXGIObject)
+COM_INTERFACE(IDXGIDevice, IDXGIObject)
+COM_INTERFACE(IDXGIResource, IDXGIDeviceSubObject)
+COM_INTERFACE(IDXGISurface1, IDXGISurface)
+COM_INTERFACE(IDXGIDevice1, IDXGIDevice)
+COM_INTERFACE(IDXGIAdapter1, IDXGIAdapter)
+COM_INTERFACE(IDXGIFactory1, IDXGIFactory)
+
+template<typename Base>
+struct GalliumDXGIDevice : public GalliumMultiPrivateDataComObject<Base, IDXGIDevice1>
+{
+ ComPtr<IDXGIAdapter> adapter;
+ int priority;
+ unsigned max_latency;
+
+ GalliumDXGIDevice(IDXGIAdapter* p_adapter)
+ {
+ adapter = p_adapter;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetParent(
+ REFIID riid,
+ void **ppParent)
+ {
+ return adapter.p->QueryInterface(riid, ppParent);
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetAdapter(
+ IDXGIAdapter **pAdapter)
+ {
+ *pAdapter = adapter.ref();
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE QueryResourceResidency(
+ IUnknown *const *ppResources,
+ DXGI_RESIDENCY *pResidencyStatus,
+ UINT NumResources)
+ {
+ for(unsigned i = 0; i < NumResources; ++i)
+ pResidencyStatus[i] = DXGI_RESIDENCY_FULLY_RESIDENT;
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE SetGPUThreadPriority(
+ INT Priority)
+ {
+ priority = Priority;
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetGPUThreadPriority(
+ INT *pPriority)
+ {
+ *pPriority = priority;
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency(
+ UINT *pMaxLatency
+ )
+ {
+ *pMaxLatency = max_latency;
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency(
+ UINT MaxLatency)
+ {
+ max_latency = MaxLatency;
+ return S_OK;
+ }
+};
+
+COM_INTERFACE(ID3D10Blob, IUnknown);
+
+/* NOTE: ID3DBlob implementations may come from a Microsoft native DLL
+ * (e.g. d3dcompiler), or perhaps even from the application itself.
+ *
+ * Hence, never try to access the data/size members directly, which is why they are private.
+ * In internal code, use std::pair<void*, size_t> instead of this class.
+ */
+class GalliumD3DBlob : public GalliumComObject<ID3DBlob>
+{
+ void* data;
+ size_t size;
+
+public:
+ GalliumD3DBlob(void* data, size_t size)
+ : data(data), size(size)
+ {}
+
+ ~GalliumD3DBlob()
+ {
+ free(data);
+ }
+
+ virtual LPVOID STDMETHODCALLTYPE GetBufferPointer()
+ {
+ return data;
+ }
+
+ virtual SIZE_T STDMETHODCALLTYPE GetBufferSize()
+ {
+ return size;
+ }
+};
+
+#endif /* D3D1XSTUTIL_H_ */