d3d1xstutil.h revision bb26272beaf1d2bddffaad5341235e70abcf483b
1/************************************************************************** 2 * 3 * Copyright 2010 Luca Barbieri 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial 15 * portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 **************************************************************************/ 26 27#ifndef D3D1XSTUTIL_H_ 28#define D3D1XSTUTIL_H_ 29 30#ifdef _MSC_VER 31#include <unordered_map> 32#include <unordered_set> 33#else 34#include <tr1/unordered_map> 35#include <tr1/unordered_set> 36namespace std 37{ 38 using namespace tr1; 39} 40#endif 41#include <map> 42#include <utility> 43 44#define WIN32_LEAN_AND_MEAN 45#include <objbase.h> 46#include <guiddef.h> 47#include <specstrings.h> 48 49#ifdef __GNUC__ 50#define ATTRIBUTE_UNUSED __attribute__((unused)) 51#else 52#define ATTRIBUTE_UNUSED 53#endif 54 55// just replicate GUIDs in every object file to avoid the hassle of having to pull in a library for them 56#undef DEFINE_GUID 57#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 58 static const GUID name ATTRIBUTE_UNUSED = \ 59 { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } 60 61#include "galliumdxgi.h" 62#include <d3dcommon.h> 63 64extern "C" 65{ 66#include <util/u_atomic.h> 67#include <pipe/p_format.h> 68#include <os/os_thread.h> 69} 70 71#include <assert.h> 72#ifdef min 73#undef min 74#endif 75#ifdef max 76#undef max 77#endif 78 79/* NOTE: this _depends_ on the vtable layout of the C++ compiler to be 80 * binary compatible with Windows. 81 * Furthermore some absurd vtable layout likely won't work at all, since 82 * we perform some casts which are probably not safe by the C++ standard. 83 * 84 * In particular, the GNU/Linux/Itanium/clang ABI and Microsoft ABIs will work, 85 * but others may not. 86 * If in doubt, just switch to the latest version of a widely used C++ compiler. 87 * 88 * DESIGN of the Gallium COM implementation 89 * 90 * This state tracker uses somewhat unusual C++ coding patterns, 91 * to implement the COM interfaces required by Direct3D. 92 * 93 * While it may seem complicated, the effect is that the result 94 * generally behaves as intuitively as possible: in particular pointer 95 * casts very rarely change the pointer value (only for secondary 96 * DXGI/Gallium interfaces) 97 * 98 * Implementing COM is on first sight very easy: after all, it just 99 * consists of a reference count, and a dynamic_cast<> equivalent. 100 * 101 * However, implementing objects with multiple interfaces is actually 102 * quite tricky. 103 * The issue is that the interface pointers can't be equal, since this 104 * would place incompatible constraints on the vtable layout and thus 105 * multiple inheritance (and the subobjects the C++ compiler creates 106 * with it) must be correctly used. 107 * 108 * Furthermore, we must have a single reference count, which means 109 * that a naive implementation won't work, and it's necessary to either 110 * use virtual inheritance, or the "mixin inheritance" model we use. 111 * 112 * This solution aims to achieve the following object layout: 113 * 0: pointer to vtable for primary interface 114 * 1: reference count 115 * ... main class 116 * ... vtable pointers for secondary interfaces 117 * ... implementation of subclasses assuming secondary interfaces 118 * 119 * This allows us to cast pointers by just reinterpreting the value in 120 * almost all cases. 121 * 122 * To achieve this, *all* non-leaf classes must have their parent 123 * or the base COM interface as a template parameter, since derived 124 * classes may need to change that to support an interface derived 125 * from the one implemented by the superclass. 126 * 127 * Note however, that you can cast without regard to the template 128 * parameter, because only the vtable layout depends on it, since 129 * interfaces have no data members. 130 * 131 * For this to work, DON'T USE VIRTUAL FUNCTIONS except to implement 132 * interfaces, since the vtable layouts would otherwise be mismatched. 133 * An exception are virtual functions called only from other virtual functions, 134 * which is currently only used for the virtual destructor. 135 * 136 * The base class is GalliumComObject<IFoo>, which implements the 137 * IUnknown interface, and inherits IFoo. 138 * 139 * To support multiple inheritance, we insert GalliumMultiComObject, 140 * which redirects the secondary interfaces to the GalliumComObject 141 * superclass. 142 * 143 * Gallium(Multi)PrivateDataComObject is like ComObject but also 144 * implements the Get/SetPrivateData functions present on several 145 * D3D/DXGI interfaces. 146 * 147 * Example class hierarchy: 148 * 149 * IUnknown 150 * (pure interface) 151 * | 152 * V 153 * IAnimal 154 * (pure interface) 155 * | 156 * V 157 * IDuck 158 * (pure interface) 159 * | 160 * V 161 * GalliumComObject<IDuck> 162 * (non-instantiable, only implements IUnknown) 163 * | 164 * V 165 * GalliumAnimal<IDuck> 166 * (non-instantiable, only implements IAnimal) 167 * | 168 * V 169 * GalliumDuck 170 * (concrete) 171 * | 172 * V 173 * GalliumMultiComObject<GalliumDuck, IWheeledVehicle> <- IWheeledVehicle <- IVehicle <- IUnknown (second version) 174 * (non-instantiable, only implements IDuck and the IUnknown of IWheeledVehicle) 175 * | 176 * V 177 * GalliumDuckOnWheels 178 * (concrete) 179 * 180 * This will produce the desired layout. 181 * Note that GalliumAnimal<IFoo>* is safely castable to GalliumAnimal<IBar>* 182 * by reinterpreting, as long as non-interface virtual functions are not used, 183 * and that you only call interface functions for the superinterface of IBar 184 * that the object actually implements. 185 * 186 * Instead, if GalliumDuck where to inherit both from GalliumAnimal 187 * and IDuck, then (IDuck*)gallium_duck and (IAnimal*)gallium_duck would 188 * have different pointer values, which the "base class as template parameter" 189 * trick avoids. 190 * 191 * The price we pay is that you MUST NOT have virtual functions other than those 192 * implementing interfaces (except for leaf classes) since the position of these 193 * would depend on the base interface. 194 * As mentioned above, virtual functions only called from interface functions 195 * are an exception, currently used only for the virtual destructor. 196 * If you want virtual functions anyway , put them in a separate interface class, 197 * multiply inherit from that and cast the pointer to that interface. 198 * 199 * You CAN however have virtual functions on any class which does not specify 200 * his base as a template parameter, or where you don't need to change the 201 * template base interface parameter by casting. 202 * 203 * --- The magic QueryInterface "delete this" trick --- 204 * 205 * When the reference count drops to 0, we must delete the class. 206 * The problem is, that we must call the right virtual destructor (i.e. on the right class). 207 * However, we would like to be able to call release() and nonatomic_release() 208 * non-virtually for performance (also, the latter cannot be called virtually at all, since 209 * IUnknown does not offer it). 210 * 211 * The naive solution would be to just add a virtual destructor and rely on it. 212 * However, this doesn't work due to the fact that as described above we perform casets 213 * with are unsafe regarding vtable layout. 214 * In particular, consider the case where we try to delete GalliumComObject<ID3D11Texture2D> 215 * with a pointer to GalliumComObject<ID3D11Resource>. 216 * Since we think that this is a GalliumComObject<ID3D11Resource>, we'll look for the 217 * destructor in the vtable slot immediately after the ID3D11Resource vtable, but this is 218 * actually an ID3D11Texture2D function implemented by the object! 219 * 220 * So, we must put the destructor somewhere else. 221 * We could add it as a data member, but it would be awkward and it would bloat the 222 * class. 223 * Thus, we use this trick: we reuse the vtable slot for QueryInterface, which is always at the 224 * same position. 225 * To do so, we define a special value for the first pointer argument, that triggers a 226 * "delete this". 227 * In addition to that, we add a virtual destructor to GalliumComObject. 228 * That virtual destructor will be called by QueryInterface, and since that is a virtual 229 * function, it will know the correct place for the virtual destructor. 230 * 231 * QueryInterface is already slow due to the need to compare several GUIDs, so the 232 * additional pointer test should not be significant. 233 * 234 * Of course the ideal solution would be telling the C++ compiler to put the 235 * destructor it in a negative vtable slot, but unfortunately GCC doesn't support that 236 * yet, and this method is almost as good as that. 237 */ 238 239template<typename T> 240struct com_traits; 241 242#define COM_INTERFACE(intf, base) \ 243template<> \ 244struct com_traits<intf> \ 245{ \ 246 static REFIID iid() {return IID_##intf;} \ 247 static inline bool is_self_or_ancestor(REFIID riid) {return riid == iid() || com_traits<base>::is_self_or_ancestor(riid);} \ 248}; 249 250template<> 251struct com_traits<IUnknown> 252{ 253 static REFIID iid() {return IID_IUnknown;} 254 static inline bool is_self_or_ancestor(REFIID riid) {return riid == iid();} 255}; 256 257#ifndef _MSC_VER 258#define __uuidof(T) (com_traits<T>::iid()) 259#endif 260 261struct refcnt_t 262{ 263 uint32_t refcnt; 264 265 refcnt_t(unsigned v = 1) 266 : refcnt(v) 267 {} 268 269 unsigned add_ref() 270 { 271 p_atomic_inc((int32_t*)&refcnt); 272 return refcnt; 273 } 274 275 unsigned release() 276 { 277 if(p_atomic_dec_zero((int32_t*)&refcnt)) 278 return 0; 279 return refcnt; 280 } 281 282 void nonatomic_add_ref() 283 { 284 p_atomic_inc((int32_t*)&refcnt); 285 } 286 287 unsigned nonatomic_release() 288 { 289 if(p_atomic_dec_zero((int32_t*)&refcnt)) 290 return 0; 291 else 292 return 1; 293 } 294}; 295 296#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) 297/* this should be safe because atomic ops are full memory barriers, and thus a sequence that does: 298 * ++one_refcnt; 299 * --other_refcnt; 300 * should never be reorderable (as seen from another CPU) to: 301 * --other_refcnt 302 * ++one_refcnt 303 * 304 * since one of the ops is atomic. 305 * If this weren't the case, a CPU could incorrectly destroy an object manipulated in that way by another one. 306 */ 307struct dual_refcnt_t 308{ 309 union 310 { 311 uint64_t refcnt; 312 struct 313 { 314 uint32_t atomic_refcnt; 315 uint32_t nonatomic_refcnt; 316 }; 317 }; 318 319 dual_refcnt_t(unsigned v = 1) 320 { 321 atomic_refcnt = v; 322 nonatomic_refcnt = 0; 323 } 324 325 bool is_zero() 326 { 327 if(sizeof(void*) == 8) 328 return *(volatile uint64_t*)&refcnt == 0ULL; 329 else 330 { 331 uint64_t v; 332 do 333 { 334 v = refcnt; 335 } 336 while(!__sync_bool_compare_and_swap(&refcnt, v, v)); 337 return v == 0ULL; 338 } 339 } 340 341 unsigned add_ref() 342 { 343 //printf("%p add_ref at %u %u\n", this, atomic_refcnt, nonatomic_refcnt); 344 p_atomic_inc((int32_t*)&atomic_refcnt); 345 return atomic_refcnt + nonatomic_refcnt; 346 } 347 348 unsigned release() 349 { 350 //printf("%p release at %u %u\n", this, atomic_refcnt, nonatomic_refcnt); 351 if(p_atomic_dec_zero((int32_t*)&atomic_refcnt) && !nonatomic_refcnt && is_zero()) 352 return 0; 353 unsigned v = atomic_refcnt + nonatomic_refcnt; 354 return v ? v : 1; 355 } 356 357 void nonatomic_add_ref() 358 { 359 //printf("%p nonatomic_add_ref at %u %u\n", this, atomic_refcnt, nonatomic_refcnt); 360 ++nonatomic_refcnt; 361 } 362 363 unsigned nonatomic_release() 364 { 365 //printf("%p nonatomic_release at %u %u\n", this, atomic_refcnt, nonatomic_refcnt); 366 if(!--nonatomic_refcnt && !atomic_refcnt && is_zero()) 367 return 0; 368 return 1; 369 } 370}; 371#else 372// this will result in atomic operations being used while they could have been avoided 373#ifdef __i386__ 374#warning Compile for 586+ using GCC to improve the performance of the Direct3D 10/11 state tracker 375#endif 376typedef refcnt_t dual_refcnt_t; 377#endif 378 379#define IID_MAGIC_DELETE_THIS (*(const IID*)((intptr_t)-(int)(sizeof(IID) - 1))) 380 381template<typename Base = IUnknown, typename RefCnt = refcnt_t> 382struct GalliumComObject : public Base 383{ 384 RefCnt refcnt; 385 386 GalliumComObject() 387 {} 388 389 /* DO NOT CALL this from externally called non-virtual functions in derived classes, since 390 * the vtable position depends on the COM interface being implemented 391 */ 392 virtual ~GalliumComObject() 393 {} 394 395 inline ULONG add_ref() 396 { 397 return refcnt.add_ref(); 398 } 399 400 inline ULONG release() 401 { 402 ULONG v = refcnt.release(); 403 if(!v) 404 { 405 /* this will call execute "delete this", using the correct vtable slot for the destructor */ 406 /* see the initial comment for an explaination of this magic trick */ 407 this->QueryInterface(IID_MAGIC_DELETE_THIS, 0); 408 return 0; 409 } 410 return v; 411 } 412 413 inline void nonatomic_add_ref() 414 { 415 refcnt.nonatomic_add_ref(); 416 } 417 418 inline void nonatomic_release() 419 { 420 if(!refcnt.nonatomic_release()) 421 { 422 /* this will execute "delete this", using the correct vtable slot for the destructor */ 423 /* see the initial comment for an explaination of this magic trick */ 424 this->QueryInterface(IID_MAGIC_DELETE_THIS, 0); 425 } 426 } 427 428 inline HRESULT query_interface(REFIID riid, void **ppvObject) 429 { 430 if(com_traits<Base>::is_self_or_ancestor(riid)) 431 { 432 // must be the virtual AddRef, since it is overridden by some classes 433 this->AddRef(); 434 *ppvObject = this; 435 return S_OK; 436 } 437 else 438 return E_NOINTERFACE; 439 } 440 441 virtual ULONG STDMETHODCALLTYPE AddRef() 442 { 443 return add_ref(); 444 } 445 446 virtual ULONG STDMETHODCALLTYPE Release() 447 { 448 return release(); 449 } 450 451 virtual HRESULT STDMETHODCALLTYPE QueryInterface( 452 REFIID riid, 453 void **ppvObject) 454 { 455 /* see the initial comment for an explaination of this magic trick */ 456 if(&riid == &IID_MAGIC_DELETE_THIS) 457 { 458 delete this; 459 return 0; 460 } 461 if(!this) 462 return E_INVALIDARG; 463 if(!ppvObject) 464 return E_POINTER; 465 return query_interface(riid, ppvObject); 466 } 467}; 468 469template<typename BaseClass, typename SecondaryInterface> 470struct GalliumMultiComObject : public BaseClass, SecondaryInterface 471{ 472 // we could avoid this duplication, but the increased complexity to do so isn't worth it 473 virtual ULONG STDMETHODCALLTYPE AddRef() 474 { 475 return BaseClass::add_ref(); 476 } 477 478 virtual ULONG STDMETHODCALLTYPE Release() 479 { 480 return BaseClass::release(); 481 } 482 483 inline HRESULT query_interface(REFIID riid, void **ppvObject) 484 { 485 HRESULT hr = BaseClass::query_interface(riid, ppvObject); 486 if(SUCCEEDED(hr)) 487 return hr; 488 if(com_traits<SecondaryInterface>::is_self_or_ancestor(riid)) 489 { 490 // must be the virtual AddRef, since it is overridden by some classes 491 this->AddRef(); 492 *ppvObject = (SecondaryInterface*)this; 493 return S_OK; 494 } 495 else 496 return E_NOINTERFACE; 497 } 498 499 virtual HRESULT STDMETHODCALLTYPE QueryInterface( 500 REFIID riid, 501 void **ppvObject) 502 { 503 /* see the initial comment for an explaination of this magic trick */ 504 if(&riid == &IID_MAGIC_DELETE_THIS) 505 { 506 delete this; 507 return 0; 508 } 509 if(!this) 510 return E_INVALIDARG; 511 if(!ppvObject) 512 return E_POINTER; 513 return query_interface(riid, ppvObject); 514 } 515}; 516 517template<typename T, typename Traits> 518struct refcnt_ptr 519{ 520 T* p; 521 522 refcnt_ptr() 523 : p(0) 524 {} 525 526 void add_ref() {Traits::add_ref(p);} 527 void release() {Traits::release(p);} 528 529 template<typename U, typename UTraits> 530 refcnt_ptr(const refcnt_ptr<U, UTraits>& c) 531 { 532 *this = static_cast<U*>(c.ref()); 533 } 534 535 ~refcnt_ptr() 536 { 537 release(); 538 } 539 540 void reset(T* q) 541 { 542 release(); 543 p = q; 544 } 545 546 template<typename U, typename UTraits> 547 refcnt_ptr& operator =(const refcnt_ptr<U, UTraits>& q) 548 { 549 return *this = q.p; 550 } 551 552 template<typename U> 553 refcnt_ptr& operator =(U* q) 554 { 555 release(); 556 p = static_cast<T*>(q); 557 add_ref(); 558 return *this; 559 } 560 561 T* ref() 562 { 563 add_ref(); 564 return p; 565 } 566 567 T* steal() 568 { 569 T* ret = p; 570 p = 0; 571 return ret; 572 } 573 574 T* operator ->() 575 { 576 return p; 577 } 578 579 const T* operator ->() const 580 { 581 return p; 582 } 583 584 T** operator &() 585 { 586 assert(!p); 587 return &p; 588 } 589 590 bool operator !() const 591 { 592 return !p; 593 } 594 595 typedef T* refcnt_ptr::*unspecified_bool_type; 596 597 operator unspecified_bool_type() const 598 { 599 return p ? &refcnt_ptr::p : 0; 600 } 601}; 602 603struct simple_ptr_traits 604{ 605 static void add_ref(void* p) {} 606 static void release(void* p) {} 607}; 608 609struct com_ptr_traits 610{ 611 static void add_ref(void* p) 612 { 613 if(p) 614 ((IUnknown*)p)->AddRef(); 615 } 616 617 static void release(void* p) 618 { 619 if(p) 620 ((IUnknown*)p)->Release(); 621 } 622}; 623 624template<typename T> 625struct ComPtr : public refcnt_ptr<T, com_ptr_traits> 626{ 627 template<typename U, typename UTraits> 628 ComPtr& operator =(const refcnt_ptr<U, UTraits>& q) 629 { 630 return *this = q.p; 631 } 632 633 template<typename U> 634 ComPtr& operator =(U* q) 635 { 636 this->release(); 637 this->p = static_cast<T*>(q); 638 this->add_ref(); 639 return *this; 640 } 641}; 642 643template<typename T, typename TTraits, typename U, typename UTraits> 644bool operator ==(const refcnt_ptr<T, TTraits>& a, const refcnt_ptr<U, UTraits>& b) 645{ 646 return a.p == b.p; 647} 648 649template<typename T, typename TTraits, typename U> 650bool operator ==(const refcnt_ptr<T, TTraits>& a, U* b) 651{ 652 return a.p == b; 653} 654 655template<typename T, typename TTraits, typename U> 656bool operator ==(U* b, const refcnt_ptr<T, TTraits>& a) 657{ 658 return a.p == b; 659} 660 661template<typename T, typename TTraits, typename U, typename UTraits> 662bool operator !=(const refcnt_ptr<T, TTraits>& a, const refcnt_ptr<U, UTraits>& b) 663{ 664 return a.p != b.p; 665} 666 667template<typename T, typename TTraits, typename U> 668bool operator !=(const refcnt_ptr<T, TTraits>& a, U* b) 669{ 670 return a.p != b; 671} 672 673template<typename T, typename TTraits, typename U> 674bool operator !=(U* b, const refcnt_ptr<T, TTraits>& a) 675{ 676 return a.p != b; 677} 678 679template<bool threadsafe> 680struct maybe_mutex_t; 681 682template<> 683struct maybe_mutex_t<true> 684{ 685 pipe_mutex mutex; 686 687 void lock() 688 { 689 pipe_mutex_lock(mutex); 690 } 691 692 void unlock() 693 { 694 pipe_mutex_unlock(mutex); 695 } 696}; 697 698template<> 699struct maybe_mutex_t<false> 700{ 701 void lock() 702 { 703 } 704 705 void unlock() 706 { 707 } 708}; 709 710typedef maybe_mutex_t<true> mutex_t; 711 712template<typename T> 713struct lock_t 714{ 715 T& mutex; 716 lock_t(T& mutex) 717 : mutex(mutex) 718 { 719 mutex.lock(); 720 } 721 722 ~lock_t() 723 { 724 mutex.unlock(); 725 } 726}; 727 728struct c_string 729{ 730 const char* p; 731 c_string(const char* p) 732 : p(p) 733 {} 734 735 operator const char*() const 736 { 737 return p; 738 } 739}; 740 741static inline bool operator ==(const c_string& a, const c_string& b) 742{ 743 return !strcmp(a.p, b.p); 744} 745 746static inline bool operator !=(const c_string& a, const c_string& b) 747{ 748 return strcmp(a.p, b.p); 749} 750 751#ifdef __GLIBCXX__ 752namespace std 753{ 754 namespace tr1 755 { 756 template<> 757 inline size_t hash<GUID>::operator()(GUID __val) const 758 { 759 return _Fnv_hash::hash(__val); 760 } 761 762 template<> 763 inline size_t hash<c_string>::operator()(c_string __val) const 764 { 765 return _Fnv_hash::hash(__val.p, strlen(__val.p)); 766 } 767 768 template<typename T, typename U> 769 struct hash<std::pair<T, U> > : public std::unary_function<std::pair<T, U>, size_t> 770 { 771 size_t operator()(std::pair<T, U> __val) const; 772 }; 773 774 template<typename T, typename U> 775 inline size_t hash<std::pair<T, U> >::operator()(std::pair<T, U> __val) const 776 { 777 std::pair<size_t, size_t> p; 778 p.first = hash<T>()(__val.first); 779 p.second = hash<U>()(__val.second); 780 return _Fnv_hash::hash(p); 781 } 782 } 783} 784#else 785#warning "You probably need to add a pair, C string and GUID hash implementation for your C++ library" 786#endif 787 788template<typename Base, typename RefCnt = refcnt_t> 789struct GalliumPrivateDataComObject : public GalliumComObject<Base, RefCnt> 790{ 791 typedef std::unordered_map<GUID, std::pair<void*, unsigned> > private_data_map_t; 792 private_data_map_t private_data_map; 793 mutex_t private_data_mutex; 794 795 ~GalliumPrivateDataComObject() 796 { 797 for(private_data_map_t::iterator i = private_data_map.begin(), e = private_data_map.end(); i != e; ++i) 798 { 799 if(i->second.second == ~0u) 800 ((IUnknown*)i->second.first)->Release(); 801 else 802 free(i->second.first); 803 } 804 } 805 806 HRESULT get_private_data( 807 __in REFGUID guid, 808 __inout UINT *pDataSize, 809 __out_bcount_opt(*pDataSize) void *pData) 810 { 811 lock_t<mutex_t> lock(private_data_mutex); 812 private_data_map_t::iterator i = private_data_map.find(guid); 813 *pDataSize = 0; 814 if(i == private_data_map.end()) 815 return DXGI_ERROR_NOT_FOUND; 816 if(i->second.second == ~0u) 817 { 818 /* TODO: is GetPrivateData on interface data supposed to do this? */ 819 if(*pDataSize < sizeof(void*)) 820 return E_INVALIDARG; 821 if(pData) 822 { 823 memcpy(pData, &i->second.first, sizeof(void*)); 824 ((IUnknown*)i->second.first)->AddRef(); 825 } 826 *pDataSize = sizeof(void*); 827 } 828 else 829 { 830 unsigned size = std::min(*pDataSize, i->second.second); 831 if(pData) 832 memcpy(pData, i->second.first, size); 833 *pDataSize = size; 834 } 835 return S_OK; 836 } 837 838 HRESULT set_private_data( 839 __in REFGUID guid, 840 __in UINT DataSize, 841 __in_bcount_opt( DataSize ) const void *pData) 842 { 843 void* p = 0; 844 845 if(DataSize && pData) 846 { 847 p = malloc(DataSize); 848 if(!p) 849 return E_OUTOFMEMORY; 850 } 851 852 lock_t<mutex_t> lock(private_data_mutex); 853 std::pair<void*, unsigned>& v = private_data_map[guid]; 854 if(v.first) 855 { 856 if(v.second == ~0u) 857 ((IUnknown*)v.first)->Release(); 858 else 859 free(v.first); 860 } 861 if(DataSize && pData) 862 { 863 memcpy(p, pData, DataSize); 864 v.first = p; 865 v.second = DataSize; 866 } 867 else 868 private_data_map.erase(guid); 869 return S_OK; 870 } 871 872 HRESULT set_private_data_interface( 873 __in REFGUID guid, 874 __in_opt const IUnknown *pData) 875 { 876 lock_t<mutex_t> lock(private_data_mutex); 877 std::pair<void*, unsigned>& v = private_data_map[guid]; 878 if(v.first) 879 { 880 if(v.second == ~0u) 881 ((IUnknown*)v.first)->Release(); 882 else 883 free(v.first); 884 } 885 if(pData) 886 { 887 ((IUnknown*)pData)->AddRef(); 888 v.first = (void*)pData; 889 v.second = ~0; 890 } 891 else 892 private_data_map.erase(guid); 893 return S_OK; 894 } 895 896 virtual HRESULT STDMETHODCALLTYPE GetPrivateData( 897 __in REFGUID guid, 898 __inout UINT *pDataSize, 899 __out_bcount_opt(*pDataSize) void *pData) 900 { 901 return get_private_data(guid, pDataSize, pData); 902 } 903 904 virtual HRESULT STDMETHODCALLTYPE SetPrivateData( 905 __in REFGUID guid, 906 __in UINT DataSize, 907 __in_bcount_opt( DataSize ) const void *pData) 908 { 909 return set_private_data(guid, DataSize, pData); 910 } 911 912 virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( 913 __in REFGUID guid, 914 __in_opt const IUnknown *pData) 915 { 916 return set_private_data_interface(guid, pData); 917 } 918}; 919 920template<typename BaseClass, typename SecondaryInterface> 921struct GalliumMultiPrivateDataComObject : public GalliumMultiComObject<BaseClass, SecondaryInterface> 922{ 923 // we could avoid this duplication, but the increased complexity to do so isn't worth it 924 virtual HRESULT STDMETHODCALLTYPE GetPrivateData( 925 __in REFGUID guid, 926 __inout UINT *pDataSize, 927 __out_bcount_opt(*pDataSize) void *pData) 928 { 929 return BaseClass::get_private_data(guid, pDataSize, pData); 930 } 931 932 virtual HRESULT STDMETHODCALLTYPE SetPrivateData( 933 __in REFGUID guid, 934 __in UINT DataSize, 935 __in_bcount_opt( DataSize ) const void *pData) 936 { 937 return BaseClass::set_private_data(guid, DataSize, pData); 938 } 939 940 virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( 941 __in REFGUID guid, 942 __in_opt const IUnknown *pData) 943 { 944 return BaseClass::set_private_data_interface(guid, pData); 945 } 946}; 947 948#define DXGI_FORMAT_COUNT 100 949extern pipe_format dxgi_to_pipe_format[DXGI_FORMAT_COUNT]; 950extern DXGI_FORMAT pipe_to_dxgi_format[PIPE_FORMAT_COUNT]; 951 952void init_pipe_to_dxgi_format(); 953 954COM_INTERFACE(IGalliumDevice, IUnknown); 955COM_INTERFACE(IGalliumAdapter, IUnknown); 956COM_INTERFACE(IGalliumResource, IUnknown); 957 958// used to make QueryInterface know the IIDs of the interface and its ancestors 959COM_INTERFACE(IDXGIObject, IUnknown) 960COM_INTERFACE(IDXGIDeviceSubObject, IDXGIObject) 961COM_INTERFACE(IDXGISurface, IDXGIDeviceSubObject) 962COM_INTERFACE(IDXGIOutput, IDXGIObject) 963COM_INTERFACE(IDXGIAdapter, IDXGIObject) 964COM_INTERFACE(IDXGISwapChain, IDXGIDeviceSubObject) 965COM_INTERFACE(IDXGIFactory, IDXGIObject) 966COM_INTERFACE(IDXGIDevice, IDXGIObject) 967COM_INTERFACE(IDXGIResource, IDXGIDeviceSubObject) 968COM_INTERFACE(IDXGISurface1, IDXGISurface) 969COM_INTERFACE(IDXGIDevice1, IDXGIDevice) 970COM_INTERFACE(IDXGIAdapter1, IDXGIAdapter) 971COM_INTERFACE(IDXGIFactory1, IDXGIFactory) 972 973template<typename Base> 974struct GalliumDXGIDevice : public GalliumMultiPrivateDataComObject<Base, IDXGIDevice> 975{ 976 ComPtr<IDXGIAdapter> adapter; 977 int priority; 978 unsigned max_latency; 979 980 GalliumDXGIDevice(IDXGIAdapter* p_adapter) 981 { 982 adapter = p_adapter; 983 } 984 985 virtual HRESULT STDMETHODCALLTYPE GetParent( 986 __in REFIID riid, 987 __out void **ppParent) 988 { 989 return adapter.p->QueryInterface(riid, ppParent); 990 } 991 992 virtual HRESULT STDMETHODCALLTYPE GetAdapter( 993 __out IDXGIAdapter **pAdapter) 994 { 995 *pAdapter = adapter.ref(); 996 return S_OK; 997 } 998 999 virtual HRESULT STDMETHODCALLTYPE QueryResourceResidency( 1000 __in_ecount(NumResources) IUnknown *const *ppResources, 1001 __out_ecount(NumResources) DXGI_RESIDENCY *pResidencyStatus, 1002 UINT NumResources) 1003 { 1004 for(unsigned i = 0; i < NumResources; ++i) 1005 pResidencyStatus[i] = DXGI_RESIDENCY_FULLY_RESIDENT; 1006 return S_OK; 1007 } 1008 1009 virtual HRESULT STDMETHODCALLTYPE SetGPUThreadPriority( 1010 INT Priority) 1011 { 1012 priority = Priority; 1013 return S_OK; 1014 } 1015 1016 virtual HRESULT STDMETHODCALLTYPE GetGPUThreadPriority( 1017 __out INT *pPriority) 1018 { 1019 *pPriority = priority; 1020 return S_OK; 1021 } 1022 1023 HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency( 1024 UINT *pMaxLatency 1025 ) 1026 { 1027 *pMaxLatency = max_latency; 1028 return S_OK; 1029 } 1030 1031 virtual HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency( 1032 UINT MaxLatency) 1033 { 1034 max_latency = MaxLatency; 1035 return S_OK; 1036 } 1037}; 1038 1039COM_INTERFACE(ID3D10Blob, IUnknown); 1040 1041/* NOTE: ID3DBlob implementations may come from a Microsoft native DLL 1042 * (e.g. d3dcompiler), or perhaps even from the application itself. 1043 * 1044 * Hence, never try to access the data/size members directly, which is why they are private. 1045 * In internal code, use std::pair<void*, size_t> instead of this class. 1046 */ 1047class GalliumD3DBlob : public GalliumComObject<ID3DBlob> 1048{ 1049 void* data; 1050 size_t size; 1051 1052public: 1053 GalliumD3DBlob(void* data, size_t size) 1054 : data(data), size(size) 1055 {} 1056 1057 ~GalliumD3DBlob() 1058 { 1059 free(data); 1060 } 1061 1062 virtual LPVOID STDMETHODCALLTYPE GetBufferPointer() 1063 { 1064 return data; 1065 } 1066 1067 virtual SIZE_T STDMETHODCALLTYPE GetBufferSize() 1068 { 1069 return size; 1070 } 1071}; 1072 1073#endif /* D3D1XSTUTIL_H_ */ 1074