d3d1xstutil.h revision 6c598c78bd17642d731cf57b8369cc794f64ba2f
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 maybe_mutex_t() 679 { 680 pipe_mutex_init(mutex); 681 } 682 683 void lock() 684 { 685 pipe_mutex_lock(mutex); 686 } 687 688 void unlock() 689 { 690 pipe_mutex_unlock(mutex); 691 } 692}; 693 694template<> 695struct maybe_mutex_t<false> 696{ 697 void lock() 698 { 699 } 700 701 void unlock() 702 { 703 } 704}; 705 706typedef maybe_mutex_t<true> mutex_t; 707 708template<typename T> 709struct lock_t 710{ 711 T& mutex; 712 lock_t(T& mutex) 713 : mutex(mutex) 714 { 715 mutex.lock(); 716 } 717 718 ~lock_t() 719 { 720 mutex.unlock(); 721 } 722}; 723 724struct c_string 725{ 726 const char* p; 727 c_string(const char* p) 728 : p(p) 729 {} 730 731 operator const char*() const 732 { 733 return p; 734 } 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 bool operator !=(const c_string& a, const c_string& b) 743{ 744 return strcmp(a.p, b.p); 745} 746 747static inline size_t raw_hash(const char* p, size_t size) 748{ 749 size_t res; 750 if(sizeof(size_t) >= 8) 751 res = (size_t)14695981039346656037ULL; 752 else 753 res = (size_t)2166136261UL; 754 const char* end = p + size; 755 for(; p != end; ++p) 756 { 757 res ^= (size_t)*p; 758 if(sizeof(size_t) >= 8) 759 res *= (size_t)1099511628211ULL; 760 else 761 res *= (size_t)16777619UL; 762 } 763 return res; 764}; 765 766template<typename T> 767static inline size_t raw_hash(const T& t) 768{ 769 return raw_hash((const char*)&t, sizeof(t)); 770} 771 772// TODO: only tested with the gcc libstdc++, might not work elsewhere 773namespace std 774{ 775#ifndef _MSC_VER 776 namespace tr1 777 { 778#endif 779 template<> 780 struct hash<GUID> : public std::unary_function<GUID, size_t> 781 { 782 inline size_t operator()(GUID __val) const; 783 }; 784 785 inline size_t hash<GUID>::operator()(GUID __val) const 786 { 787 return raw_hash(__val); 788 } 789 790 template<> 791 struct hash<c_string> : public std::unary_function<c_string, size_t> 792 { 793 inline size_t operator()(c_string __val) const; 794 }; 795 796 inline size_t hash<c_string>::operator()(c_string __val) const 797 { 798 return raw_hash(__val.p, strlen(__val.p)); 799 } 800 801 template<typename T, typename U> 802 struct hash<std::pair<T, U> > : public std::unary_function<std::pair<T, U>, size_t> 803 { 804 inline size_t operator()(std::pair<T, U> __val) const; 805 }; 806 807 template<typename T, typename U> 808 inline size_t hash<std::pair<T, U> >::operator()(std::pair<T, U> __val) const 809 { 810 std::pair<size_t, size_t> p; 811 p.first = hash<T>()(__val.first); 812 p.second = hash<U>()(__val.second); 813 return raw_hash(p); 814 } 815#ifndef _MSC_VER 816 } 817#endif 818} 819 820template<typename Base, typename RefCnt = refcnt_t> 821struct GalliumPrivateDataComObject : public GalliumComObject<Base, RefCnt> 822{ 823 typedef std::unordered_map<GUID, std::pair<void*, unsigned> > private_data_map_t; 824 private_data_map_t private_data_map; 825 mutex_t private_data_mutex; 826 827 ~GalliumPrivateDataComObject() 828 { 829 for(private_data_map_t::iterator i = private_data_map.begin(), e = private_data_map.end(); i != e; ++i) 830 { 831 if(i->second.second == ~0u) 832 ((IUnknown*)i->second.first)->Release(); 833 else 834 free(i->second.first); 835 } 836 } 837 838 HRESULT get_private_data( 839 __in REFGUID guid, 840 __inout UINT *pDataSize, 841 __out_bcount_opt(*pDataSize) void *pData) 842 { 843 lock_t<mutex_t> lock(private_data_mutex); 844 private_data_map_t::iterator i = private_data_map.find(guid); 845 *pDataSize = 0; 846 if(i == private_data_map.end()) 847 return DXGI_ERROR_NOT_FOUND; 848 if(i->second.second == ~0u) 849 { 850 /* TODO: is GetPrivateData on interface data supposed to do this? */ 851 if(*pDataSize < sizeof(void*)) 852 return E_INVALIDARG; 853 if(pData) 854 { 855 memcpy(pData, &i->second.first, sizeof(void*)); 856 ((IUnknown*)i->second.first)->AddRef(); 857 } 858 *pDataSize = sizeof(void*); 859 } 860 else 861 { 862 unsigned size = std::min(*pDataSize, i->second.second); 863 if(pData) 864 memcpy(pData, i->second.first, size); 865 *pDataSize = size; 866 } 867 return S_OK; 868 } 869 870 HRESULT set_private_data( 871 __in REFGUID guid, 872 __in UINT DataSize, 873 __in_bcount_opt( DataSize ) const void *pData) 874 { 875 void* p = 0; 876 877 if(DataSize && pData) 878 { 879 p = malloc(DataSize); 880 if(!p) 881 return E_OUTOFMEMORY; 882 } 883 884 lock_t<mutex_t> lock(private_data_mutex); 885 std::pair<void*, unsigned>& v = private_data_map[guid]; 886 if(v.first) 887 { 888 if(v.second == ~0u) 889 ((IUnknown*)v.first)->Release(); 890 else 891 free(v.first); 892 } 893 if(DataSize && pData) 894 { 895 memcpy(p, pData, DataSize); 896 v.first = p; 897 v.second = DataSize; 898 } 899 else 900 private_data_map.erase(guid); 901 return S_OK; 902 } 903 904 HRESULT set_private_data_interface( 905 __in REFGUID guid, 906 __in_opt const IUnknown *pData) 907 { 908 lock_t<mutex_t> lock(private_data_mutex); 909 std::pair<void*, unsigned>& v = private_data_map[guid]; 910 if(v.first) 911 { 912 if(v.second == ~0u) 913 ((IUnknown*)v.first)->Release(); 914 else 915 free(v.first); 916 } 917 if(pData) 918 { 919 ((IUnknown*)pData)->AddRef(); 920 v.first = (void*)pData; 921 v.second = ~0; 922 } 923 else 924 private_data_map.erase(guid); 925 return S_OK; 926 } 927 928 virtual HRESULT STDMETHODCALLTYPE GetPrivateData( 929 __in REFGUID guid, 930 __inout UINT *pDataSize, 931 __out_bcount_opt(*pDataSize) void *pData) 932 { 933 return get_private_data(guid, pDataSize, pData); 934 } 935 936 virtual HRESULT STDMETHODCALLTYPE SetPrivateData( 937 __in REFGUID guid, 938 __in UINT DataSize, 939 __in_bcount_opt( DataSize ) const void *pData) 940 { 941 return set_private_data(guid, DataSize, pData); 942 } 943 944 virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( 945 __in REFGUID guid, 946 __in_opt const IUnknown *pData) 947 { 948 return set_private_data_interface(guid, pData); 949 } 950}; 951 952template<typename BaseClass, typename SecondaryInterface> 953struct GalliumMultiPrivateDataComObject : public GalliumMultiComObject<BaseClass, SecondaryInterface> 954{ 955 // we could avoid this duplication, but the increased complexity to do so isn't worth it 956 virtual HRESULT STDMETHODCALLTYPE GetPrivateData( 957 __in REFGUID guid, 958 __inout UINT *pDataSize, 959 __out_bcount_opt(*pDataSize) void *pData) 960 { 961 return BaseClass::get_private_data(guid, pDataSize, pData); 962 } 963 964 virtual HRESULT STDMETHODCALLTYPE SetPrivateData( 965 __in REFGUID guid, 966 __in UINT DataSize, 967 __in_bcount_opt( DataSize ) const void *pData) 968 { 969 return BaseClass::set_private_data(guid, DataSize, pData); 970 } 971 972 virtual HRESULT STDMETHODCALLTYPE SetPrivateDataInterface( 973 __in REFGUID guid, 974 __in_opt const IUnknown *pData) 975 { 976 return BaseClass::set_private_data_interface(guid, pData); 977 } 978}; 979 980#define DXGI_FORMAT_COUNT 100 981extern pipe_format dxgi_to_pipe_format[DXGI_FORMAT_COUNT]; 982extern DXGI_FORMAT pipe_to_dxgi_format[PIPE_FORMAT_COUNT]; 983 984void init_pipe_to_dxgi_format(); 985 986COM_INTERFACE(IGalliumDevice, IUnknown); 987COM_INTERFACE(IGalliumAdapter, IUnknown); 988COM_INTERFACE(IGalliumResource, IUnknown); 989 990// used to make QueryInterface know the IIDs of the interface and its ancestors 991COM_INTERFACE(IDXGIObject, IUnknown) 992COM_INTERFACE(IDXGIDeviceSubObject, IDXGIObject) 993COM_INTERFACE(IDXGISurface, IDXGIDeviceSubObject) 994COM_INTERFACE(IDXGIOutput, IDXGIObject) 995COM_INTERFACE(IDXGIAdapter, IDXGIObject) 996COM_INTERFACE(IDXGISwapChain, IDXGIDeviceSubObject) 997COM_INTERFACE(IDXGIFactory, IDXGIObject) 998COM_INTERFACE(IDXGIDevice, IDXGIObject) 999COM_INTERFACE(IDXGIResource, IDXGIDeviceSubObject) 1000COM_INTERFACE(IDXGISurface1, IDXGISurface) 1001COM_INTERFACE(IDXGIDevice1, IDXGIDevice) 1002COM_INTERFACE(IDXGIAdapter1, IDXGIAdapter) 1003COM_INTERFACE(IDXGIFactory1, IDXGIFactory) 1004 1005template<typename Base> 1006struct GalliumDXGIDevice : public GalliumMultiPrivateDataComObject<Base, IDXGIDevice> 1007{ 1008 ComPtr<IDXGIAdapter> adapter; 1009 int priority; 1010 unsigned max_latency; 1011 1012 GalliumDXGIDevice(IDXGIAdapter* p_adapter) 1013 { 1014 adapter = p_adapter; 1015 } 1016 1017 virtual HRESULT STDMETHODCALLTYPE GetParent( 1018 __in REFIID riid, 1019 __out void **ppParent) 1020 { 1021 return adapter.p->QueryInterface(riid, ppParent); 1022 } 1023 1024 virtual HRESULT STDMETHODCALLTYPE GetAdapter( 1025 __out IDXGIAdapter **pAdapter) 1026 { 1027 *pAdapter = adapter.ref(); 1028 return S_OK; 1029 } 1030 1031 virtual HRESULT STDMETHODCALLTYPE QueryResourceResidency( 1032 __in_ecount(NumResources) IUnknown *const *ppResources, 1033 __out_ecount(NumResources) DXGI_RESIDENCY *pResidencyStatus, 1034 UINT NumResources) 1035 { 1036 for(unsigned i = 0; i < NumResources; ++i) 1037 pResidencyStatus[i] = DXGI_RESIDENCY_FULLY_RESIDENT; 1038 return S_OK; 1039 } 1040 1041 virtual HRESULT STDMETHODCALLTYPE SetGPUThreadPriority( 1042 INT Priority) 1043 { 1044 priority = Priority; 1045 return S_OK; 1046 } 1047 1048 virtual HRESULT STDMETHODCALLTYPE GetGPUThreadPriority( 1049 __out INT *pPriority) 1050 { 1051 *pPriority = priority; 1052 return S_OK; 1053 } 1054 1055 HRESULT STDMETHODCALLTYPE GetMaximumFrameLatency( 1056 UINT *pMaxLatency 1057 ) 1058 { 1059 *pMaxLatency = max_latency; 1060 return S_OK; 1061 } 1062 1063 virtual HRESULT STDMETHODCALLTYPE SetMaximumFrameLatency( 1064 UINT MaxLatency) 1065 { 1066 max_latency = MaxLatency; 1067 return S_OK; 1068 } 1069}; 1070 1071COM_INTERFACE(ID3D10Blob, IUnknown); 1072 1073/* NOTE: ID3DBlob implementations may come from a Microsoft native DLL 1074 * (e.g. d3dcompiler), or perhaps even from the application itself. 1075 * 1076 * Hence, never try to access the data/size members directly, which is why they are private. 1077 * In internal code, use std::pair<void*, size_t> instead of this class. 1078 */ 1079class GalliumD3DBlob : public GalliumComObject<ID3DBlob> 1080{ 1081 void* data; 1082 size_t size; 1083 1084public: 1085 GalliumD3DBlob(void* data, size_t size) 1086 : data(data), size(size) 1087 {} 1088 1089 ~GalliumD3DBlob() 1090 { 1091 free(data); 1092 } 1093 1094 virtual LPVOID STDMETHODCALLTYPE GetBufferPointer() 1095 { 1096 return data; 1097 } 1098 1099 virtual SIZE_T STDMETHODCALLTYPE GetBufferSize() 1100 { 1101 return size; 1102 } 1103}; 1104 1105#endif /* D3D1XSTUTIL_H_ */ 1106