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