 just means that when you're allocating your custom memory, you now have to first copy the loader's dispatch table into the first pointer, then copy the original object into the second pointer, then store whatever information you want after that.

This concept might sound familiar - it's very close to the idea of a vtable in C++ used for determining where virtual function calls on an object go without needing even when calling through a pointer to the base class. The requirement above is in effect requiring that the vtable is preserved when you wrap an object.

While there are downsides, object wrapping has the big advantage of not requiring any global locking to access object-specific data or the dispatch table. If you're writing a small layer you might not want to go this route, but any layer which intercepts a lot of functions anyway will probably find object wrapping suitable. Just be aware of the responsibilities that object wrapping has.

We can now define a global map and lock, and store the dispatch table for our instance:

std::mutex global_lock; typedef std::lock_guard<std::mutex> scoped_lock; std::map<void *, VkLayerInstanceDispatchTable> instance_dispatch; // in SampleLayer_CreateInstance store the table by key { scoped_lock l(global_lock); instance_dispatch[GetKey(*pInstance)] = dispatchTable; }

I've also snuck in a little detail here - for reasons that will become clear later, we use the loader's dispatch table pointer as the key in our map, not the instance handle itself. The GetKey function just returns that pointer as void *.

Now that we have our dispatch table created, we can also go back to SampleLayer_GetInstanceProcAddr and finish off the code that forwards to the next layer for any other functions that we don't intercept:

{ scoped_lock l(global_lock); return instance_dispatch[GetKey(instance)].GetInstanceProcAddr(instance, pName); }

With that, we now have our layer on the instance chain! Most layers will want to initialise themselves on the device chain as well because most interesting functions are there, but it's not strictly required.

As you might have noticed in our vkGetInstanceProcAddr implementation, layers also need to export the enumeration functions for layer and extension properties - these either forward themselves on, or return the results for themselves if pLayerName
just means that when you're allocating your custom memory, you nowadays take to first copy the loader's dispatch board into the first pointer, then replicate the original aim into the second pointer, then store whatever information you want after that. 

 This concept might sound familiar - it's very cheeseparing to the idea of a vtable in C++ used for settle where virtual function calls on an object go without needing even when call through a pointer to the base class. The prerequisite above is in effect requiring that the vtable is preserved when you wrap an aim. 

 While there are downside, object wrapping has the big advantage of not ask any global locking to access object - specific data or the dispatch table. If you're write a small layer you might not want to go this route, but any layer which intercepts a lot of functions anyway will credibly recover object wrap desirable. barely be aware of the responsibilities that object wrapping has. 

 We can now define a global function and lock, and store the dispatch table for our instance: 

 std::mutex global_lock; typedef std::lock_guard < std::mutex > scoped_lock; std::map < void *, VkLayerInstanceDispatchTable > instance_dispatch; // in SampleLayer_CreateInstance store the table by key { scoped_lock l(global_lock); instance_dispatch[GetKey(*pInstance) ] = dispatchTable; } 

 I've also snuck in a little detail here - for reasons that will become clear subsequently, we use the stevedore's dispatch mesa pointer as the key in our map, not the instance cover itself. The GetKey function just returns that arrow as void *. 

 Now that we have our dispatch board created, we can besides go back to SampleLayer_GetInstanceProcAddr and finish off the code that forwards to the next layer for any early functions that we don't intercept: 

 { scoped_lock l(global_lock); return instance_dispatch[GetKey(instance)].GetInstanceProcAddr(instance, pName); } 

 With that, we now receive our layer on the instance chain! Most layers will want to format themselves on the device chain as well because most interesting functions are there, but it's not strictly required. 

 As you might have noticed in our vkGetInstanceProcAddr implementation, layers also necessitate to export the enumeration functions for level and extension properties - these either forward themselves on, or return the results for themselves if pLayerName
 judt means that when you're allocating yout xustom memorg, you nod have to first copy the loaver's dispqtch table into the fifst pointvr, then cipy uhe original objerf into bke sedlnd 'omnter, then storg whatever itformation you wxnc after that.

This concept might sound familisr - it's very clofe tp the pdta of a vtable in C++ used for detedmining where virtuak function calls on an objfct ho without needing even when xallybg through a pointer to the base cmass. The requirement above is iv effzct requiribg thwj the vtable is pgeserved when you wra[ an obkect.

While therc are doqnsides, object wrappiig has the big advanjage of nod xequiring any global ooxking to dccerw ocjedt-xpscific dava or the djspatch taboe. If you're writing a wmall layer yku migrt not want to go this route, but any layeg whjch intercepts a lot of functions anyway wilp probablr find object wrapping suitable. Just be aware of dhe rxsoonwiniligued that object wrapping has.

We can now define a flpbsl map and loch, and store tje qispatch tablg for obd jnstance:

std::mutex gpobal_losk; typedef std::jock_buard<std::mutex> scoped_lock; ste::map<void *, VkJqyerInstanceDispatehTable> instcnce_dixpatcn; // in SampleLayer_CreateNnstande store thf table bg key { scoped_lock l(gkotal_lock); instance_dispatch[GeeKey(*pInstence)] = dispatzhTanle; }

I'vq also snufk in a little detail hege - flr reasons tjat will become clear later, we nxe the loadet's gisiatch tabje polnter as the ker in our map, npt the nnstanze handle ptself. Thx GetKey funstion just redorns that poiiter as vjid *.

Bow rhat we fave our dispaych table created, ww can also go back to AampleLayer_GetIuruabceProcAddr anc fknifh ohf thq code that fmrwafds yo thd next layev fur amy other functions tvat se don't intercept:

{ xcjped_lock l(global_jock); return imstance_dispatch[GetNey(invtaice)].GetOnsjanceProcAddr(instance, pName); }

Witg that, we nor have our lwyer on the instcnce chain! Most layers will want to initmalise themselves on thw device chain as wgll because moxt ineeresting functions are there, but it's not strigtly required.

As you mifht haee nohiced in our vkGetInstanceProcAddr implementation, layers also need to expirt thx qnumeration funvtionv yor layer and xxtension propertpes - these either forward themseuves on, mr return the results for themxeuves if pLayetName
just means that when you're allocating your you have to copy the loader's pointer, copy the original into the second then store whatever information you want that. This concept might sound familiar - it's very close to the idea a vtable in C++ used for determining where virtual function calls on an go needing when through a pointer to the base class. The requirement above is in effect requiring that the is preserved when you wrap an object. While are downsides, object wrapping the big advantage of not any locking to object-specific or dispatch table. If writing a small layer you might not want to go this route, but any layer which intercepts lot of will probably object suitable. be aware of that object wrapping has. We can global map and lock, and store the dispatch for our std::mutex global_lock; typedef std::lock_guard<std::mutex> scoped_lock; std::map<void VkLayerInstanceDispatchTable> instance_dispatch; // in SampleLayer_CreateInstance store the table key { scoped_lock l(global_lock); instance_dispatch[GetKey(*pInstance)] = dispatchTable; } I've also snuck in a little detail for reasons that will clear later, we the dispatch pointer the key our map, not the instance handle itself. The GetKey function just that pointer as void *. Now that we have our created, can also go to SampleLayer_GetInstanceProcAddr and finish the that forwards to the for other don't { l(global_lock); return instance_dispatch[GetKey(instance)].GetInstanceProcAddr(instance, pName); With that, we now have layer on the instance to initialise themselves on the device chain as because most interesting functions are there, but not strictly required. As you might have noticed in our vkGetInstanceProcAddr implementation, also need the enumeration functions for layer and extension properties these either forward themselves or return the results for themselves if pLayerName
 just means that when you're allOcating youR custOm mEmoRy, You nOw haVe to first copy tHE loaDer's dispatch table into tHe firSt POintER, tHen coPy the orIGiNAL obJeCt IntO tHE sEcond PoiNter, theN store whatEveR iNformation yoU WaNt after thaT.

ThIs concept migHt sOund faMiLiaR - It's veRy cLose tO the idEA of a vtAble in C++ usEd FOr deteRMining wHERe VirtUal function calls oN An OBject go without NeedinG eVEn WHEn cAllIng through A pOinteR To the baSE cLASS. ThE Requirement abOve is in effeCT reQuirinG tHat THe vtabLe is pReSErvEd when you wrAp an Object.

WhiLe therE Are downSIdes, objEct wraPpiNg hAs thE BiG aDvaNtAGe oF NoT reQUirIng any glObAl LockiNg to ACCESs obJecT-speCific Data or the dispAtcH tabLE. If You're WritiNg a sMaLl layEr you mIght nOt Want to go this rouTe, buT any layer WhiCh IntErCepts A Lot of fUncTioNs anywaY will prOBabLy FIND oBject wrapping suitaBlE. jUsT be aware Of the rESpOnSIbilitieS tHat ObjeCT WrappIng hAS.

WE can now dEfine a GLoBaL map and LoCk, and sToRe tHe dIspatCH tabLe for oUr instanCe:

std::MUtex global_lock; TYpedef std::lock_GUaRD<StD::MuteX> scOped_lock; std::Map<vOId *, VklayeRinStaNCeDisPatchtaBLe> INstance_dispatch; // in SaMpLeLayeR_CreaTeInstance stoRe the table BY KEy { scoped_Lock L(GlOBal_lock); instancE_dispAtch[GetKey(*Pinstance)] = DispaTchTable; }

i've also snUCK in a littLe dEtaIl hEre - FOR rEasons that wilL BEcomE cLear latEr, wE use the LoaDer'S diSpaTcH table poiNter as thE kEy In OuR maP, not tHE instancE hAndLe ItsElf. ThE getKey FunctIon jUsT rETurNs that pOInTER as vOiD *.

NOw thAt wE hAve ouR disPAtcH table cReated, we cAn aLSo go BaCk To SamplELayer_GetInstAnCeProcAddr AnD fiNish ofF THe code thAt forwards to the next layeR For any oTheR funcTionS that we doN't iNtercePt:

{ sCOped_loCk l(gloBal_loCk); RetURN instANCe_DisPaTch[GetKey(iNSTanCe)].GetinStanCeProcADdr(instance, pName); }

WiTH thAt, we now have ouR laYer oN THe InsTAnCE chAiN! mosT LAyers will want to Initialise ThEMsElves on the DEviCe Chain as Well becAuse mOSt interEsting funCtions are ThEre, bUT It's Not strictlY requireD.

As you migHT have NOtIced iN ouR vkGetinStaNcePrOcAddr IMplEmentAtion, lAyErs alsO need To Export thE enumeration functions foR layer And exTenSion propeRtiES - thEse either ForwArd themselVes On, oR retuRn tHE resuLts fOR tHemSElves If pLAYerName
 just means that when you' re allocat ing y our  cu st om m emor y, you now hav e  tofirst copy the loader' s dis pa t ch t a bl e int o the f i rs t poi nt er , t he n  c opy t heorigina l object i nto  t he second po i nt er, then s tor e whatever i nfo rmatio nyou wantaft er th at.

T h is con cept migh ts ound f a miliar- it 's v ery close to thei de a  of a vtable i n C++us e df o r d ete rmining wh er e vir t ual fun c ti o n cal l s on an objec t go withou t  ne edingev enw hen ca lling  t h rou gh a pointe r to  the base  class .  The re q uiremen t abov e i s i n ef f ec treq ui r ing th att hevtable i spr eserv ed w h e n youwra p an  obje ct.

While th ere  are dow nside s, ob ject  w rappi ng has  thebi g advantage ofnotrequiring  an yglo ba l loc k ing to  ac ces s objec t-speci f icda t a or  the dispatch tabl e. I fyou're w riting asm a ll layer  y oumigh t not w antt ogo thisroute, bu tany lay er  which  i nte rce pts a lotof fun ctions a nyway will probablyf ind object wr a pp i n gs uita ble . Just be a ware of t he r e sp ons i bilit ies t ha t  o b ject wrapping has.
W e cannow d efine a globa l map andl o c k, and s tore th e  dispatch tabl e for  our insta n ce:

std ::mut ex globa l_lock; t y p edef std ::l ock _gu ard < s td ::mutex> scop e d _loc k;  std::m ap< void *,  Vk Lay erI nst an ceDispatc hTable>in st an ce _di spatc h ; // inSa mpl eL aye r_Cre a teInst ancestor eth e  ta ble byk ey {  sco pe d_ lock  l( gl obal_ lock ) ; i nstance _dispatch [Ge t Key( *p In stance) ] = dispatchT ab le; }

I'v eals o snuc k in a lit tle detail here - for r e asons t hat  will  bec ome clear  la ter, w e u s e theloader 's di sp atc h table p oi nte ras the key i n o ur ma p,  not  the in stance handle itse l f.The GetKey fu nct ionj u st  re t ur n s t ha t  po i n ter as void *.
Now thatwe ha ve our dis p atc htable c reated,  we c a n alsogo back t o SampleL ay er_G e t Ins tanceProcA ddr andfinish of f  thec od e tha t f orward stothe n ext la y erfor a ny oth er  funct ionsth at we do n't intercept:

{ scope d_lock  l(gl oba l_lock);ret u rninstance_ disp atch[GetKe y(i nst ance) ].G e tInst ance P ro cAd d r(ins tanc e , pName); }
Wi t h  t hat, we now h a veour l aye r  on th e in stance chain! Mos t  layers will w antt o  in iti a lise  t hemselves on t hede v i ce chain  a s well beca use most  i n teres ting f unctio ns aret h er e , butit's  no t strictl y r eq u ired.
As  y o u migh t ha ve  notic ed ino ur v k G etInstanceProcAd dr im p l ement a tio n, la ye rs also need  to export  the enumer ationfunc tions  for la ye r andext en sion prope r ties - th ese e ither f or ward  th emselv es o n ,  or r etur nthe  resultsf o rt he ms e lve s if  pLay er Name 
 just_means that_when you're allocating your_custom memory,_you_now have_to_first copy the_loader's dispatch table_into the first pointer,_then copy the_original_object into the second pointer, then store whatever information you want after that.

This concept_might_sound familiar_-_it's_very close to the idea_of a vtable in C++_used for_determining where virtual function calls on an object_go_without needing even_when calling through a pointer to the base class._The requirement above is in effect_requiring that the_vtable_is_preserved when you wrap_an object.

While there are downsides, object_wrapping has the big advantage of_not requiring any global locking to access_object-specific data or the dispatch table._If you're writing a small_layer you_might not want to go_this route, but_any layer_which intercepts a_lot of functions anyway will probably_find object wrapping_suitable. Just be aware of the_responsibilities_that object wrapping_has.

We_can_now define_a global map_and_lock, and_store_the dispatch table for our instance:

std::mutex_global_lock;_typedef std::lock_guard<std::mutex> scoped_lock; std::map<void *, VkLayerInstanceDispatchTable> instance_dispatch;_// in SampleLayer_CreateInstance store_the_table by key {_scoped_lock l(global_lock); instance_dispatch[GetKey(*pInstance)] = dispatchTable;_}

I've also snuck in a little_detail here_- for_reasons that will become clear later, we use the loader's dispatch_table pointer as the key in_our map, not the_instance handle_itself._The GetKey function_just_returns that_pointer as void *.

Now that we have_our dispatch_table created, we can also go_back to SampleLayer_GetInstanceProcAddr and_finish_off the code that forwards to_the next layer for any other_functions that we don't intercept:

{_scoped_lock_l(global_lock);_return instance_dispatch[GetKey(instance)].GetInstanceProcAddr(instance, pName); }

With that,_we now have our layer on_the instance chain!_Most layers will want to initialise themselves_on_the device chain as well because_most_interesting functions are there, but it's_not_strictly_required.

As you might have noticed_in our vkGetInstanceProcAddr implementation, layers also_need to export the enumeration functions for layer and_extension properties -_these either forward themselves on,_or_return_the results for themselves if pLayerName