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