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