<?xml version="1.0" encoding="windows-1252"?><feed version="0.3" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns="http://purl.org/atom/ns#" xml:lang="it-it">
	<title>notJustCode.it</title>
	<link rel="alternate" type="text/html" href="http://www.notjustcode.it/dblog/" />
	<tagline type="text/html">notJustCode.it</tagline>
	<id>http://www.notjustcode.it/dblog/</id>
	<generator url="http://www.notjustcode.it/dblog/feedatom.asp" version="notJustCode.it">notJustCode.it 2.0</generator>
	<author>
		<name>notJustCode.it</name>
		<url>http://www.notjustcode.it/dblog/</url>
	</author>
	<modified>2010-06-12T15:00:00+01:00</modified>
	<entry>
		<title><![CDATA[Managed DirectX11]]></title>
		<id>http://www.notjustcode.it/dblog/articolo.asp?articolo=270</id>
		<created>2010-06-12T15:00:00+01:00</created>
		<content type="text/html" mode="escaped"><![CDATA[<p>Ai tempi di DirectX7 Microsoft decise di rilasciare un componente per utilizzare in VB6 le funzionalit&agrave; che erano esclusive per il linguaggio C++. Con la versione 9 le DirectX furono poi portate in .Net ed ottennero un grande successo che port&ograve; alla nascita di uno dei prodotti di maggior successo per il pubblico: XNA. </p>
<p>Tramite il framework XNA i programmatori furono in grado di utilizzare il linguaggio .Net per sviluppare in modo unificato e semplice sia per PC che per XBox 360. Nonostante il successo per&ograve; molti ritennero XNA troppo limitato al settore videoludico (la sua struttura &egrave; infatti studiata per sviluppare giochi da poter condividere sulla piattaforma Live di Microsoft). Le due principali carenze sono infatti che &egrave; troppo restrittitiva per applicazioni non videoludiche e che, per poter essere accessibile alla XBox 360, la tecnologia dovesse essere limitata alla versione DX9.</p>
<p>Sono per&ograve; uscite negli anni le DirectX10 e le DirectX11 e da questo punto di vista Microsoft non ha pubblicato alcun componente .Net. Molti quindi fecero quello che Microsoft fece a quei tempi: creare un componente che portasse le DirectX in ambiente .Net. Esistono diversi gruppi che gi&agrave; portano avanti i loro progetti ed io, per necessit&agrave; personali, ho realizzato il mio componente che ho deciso di mettere a vostra disposizione.</p>
<p>Il Managed DirectX 11 porta tutte le tecnologie incluse nelle DirectX in ambiente .Net 3.5 (quindi Visual Studio 2008 professional o express) permettendovi di utilizzare C# o VB.Net come linguaggio base per giochi e programmi.</p>
<p>Le tecnologie portate sono</p>
<ul>
    <li>DXGI</li>
    <li>D3DX</li>
    <li>XNAMath</li>
    <li>Direct2D</li>
    <li>DirectWrite</li>
    <li>Direct3D10</li>
    <li>Direct3D11</li>
    <li>DirectInput</li>
    <li>XInput</li>
    <li>XAudio</li>
    <li>XAct</li>
</ul>
<p>Ho cercato di mantenere una mappatura 1:1 tra il relativo componente C++ e quello .Net in modo da permettervi di utilizzare con facilit&agrave; le guide ed i tutorial che si trovano in giro per C++. Tra gli esempi c'&egrave; la decisione di non utilizzare costruttori ma, come nella versione nativa, di lasciare ad oggetti come il Device o a funzioni statiche, incluse nella classe che si sta per creare, il compito di creare gli oggetti. </p>
<p>Allo stesso tempo per&ograve; ho eliminato problemi tipici del C++ come l'obbligo di eliminare gli oggetti (compito che ho lasciato alla Garbage Collector) e l'utilizzo di puntatori a memorie (ad esempio la scrittura e lettura &egrave; affidata a comodi metodi generics a cui passare direttamente array di byte o strutture complesse).</p>
<p>Non esiste una guida all'utilizzo di questi componenti ma, al momento della pubblicazione di questa pagina, &egrave; in corso da parte mia la realizzazione di tutorial DirectX11 che utilizzeranno nei sorgenti queste librerie.</p>
<p>Vi lascio i cab con l'unica nota di non spacciarli per vostri ma di fare riferimento sempre a me come ideatore. Per il resto siete liberi di utilizzarli nei vostri progetti come meglio crediate.</p>
<p>Tornate a visitare questa pagina periodicamente per vedere update o bugfix</p>
<p>Release 13/06/2010</p>
<ul>
    <li>Aggiornata alla SDK di Giugno 2010</li>
    <li>Aggiunte le versioni .Net 4.0</li>
</ul>
<p><a href="http://www.notjustcode.it/public/DirectX11Source/MDXLib.zip">Librerie</a> (1600kb)</p>
<p><a href="http://www.notjustcode.it/public/DirectX11Source/MDXLibTutorial.zip">Librerie + Tutorial</a> (10Mb)</p>]]></content>
		<link rel="alternate" type="text/html" href="http://www.notjustcode.it/dblog/articolo.asp?articolo=270"/>
		<issued>2010-06-12T15:00:00+01:00</issued>
		<modified>2010-06-12T15:00:00+01:00</modified>
		<slash:comments>6</slash:comments>
		<wfw:comments>http://www.notjustcode.it/dblog/articolo.asp?articolo=270#commenti</wfw:comments>
	</entry>
	<entry>
		<title><![CDATA[Rilasciata SDK di Giugno]]></title>
		<id>http://www.notjustcode.it/dblog/articolo.asp?articolo=298</id>
		<created>2010-06-10T08:09:52+01:00</created>
		<content type="text/html" mode="escaped"><![CDATA[<p>Vi porto comunicazione dell'ennesimo rilascio della SDK di Giugno 2010 di DirectX. Sono state portate piccole modifiche ad un paio di oggetti. A breve aggiorner&ograve; la mia libreria .Net portandola alla versione di Giugno. </p>
<p>Vi lascio il <a href="http://msdn.microsoft.com/en-us/directx/default.aspx">link</a></p>
<p>&nbsp;</p>]]></content>
		<link rel="alternate" type="text/html" href="http://www.notjustcode.it/dblog/articolo.asp?articolo=298"/>
		<issued>2010-06-10T08:09:52+01:00</issued>
		<modified>2010-06-10T08:09:52+01:00</modified>
		<slash:comments>0</slash:comments>
		<wfw:comments>http://www.notjustcode.it/dblog/articolo.asp?articolo=298#commenti</wfw:comments>
	</entry>
	<entry>
		<title><![CDATA[Geometry Instancing]]></title>
		<id>http://www.notjustcode.it/dblog/articolo.asp?articolo=296</id>
		<created>2010-06-01T21:00:00+01:00</created>
		<content type="text/html" mode="escaped"><![CDATA[<p></p> <p>Il geometry instancing &egrave; una tecnologia che permette di replicare un Vertex Buffer numerose volte in modo da creare copie di un oggetto a video in modo ottimizzato. <p>Tramite il geometry instancing&nbsp;possiamo caricare un soldato ed in un'unica istruzione di draw, mandarne a video migliaia di copie, ognuna con caratteristiche di posizione, colore o texture differenti l'uno dall'altro. <p>La cosa pi&ugrave; interessante &egrave; la totale gestione in memoria video del processo, permettendo delle prestazioni impensabili normalmente. Infatti ogni volta che si esegue una istruzione di draw ci sono dati che passano dalla RAM alla scheda video o tra zone diverse di quest'ultima:&nbsp;sar&agrave; direttamente la GPU ad operare la moltiplicazione dei vertici e degli indici dell'oggetto. <p>Il <strong>geometry instancing</strong> prevede l'utilizzo di 2 vertex buffer: il primo contenente i vertici dell'oggetto, il secondo contenente un array di strutture dati specifiche per ogni copia. Ad esempio se vogliamo rappresentare 1000 oggetti, ognuno con posizione e colore diverso, dovremo creare una struttura contenente posizione e colore e crearne un array di 1000 elementi. La funzionalit&agrave; geometry instancing non far&agrave; altro che fondere ogni vertice con ogni elemento del secondo buffer. Nel vertex shader troveremo una struttura di input che sar&agrave; la somma dei 2 buffer. Dal punto di vista dello shader sar&agrave; quindi sufficiente prevedere dei dati extra da utilizzare per modificare la posizione ed il colore dell'oggetto. Per prima cosa &egrave; necessario creare un buffer per contenere i dati <p><font color="#0000ff">ID3D11Buffer* instanceBuffer;</font> <p><font color="#0000ff">this->stride=stride;<br>this->offset=0;<br>this->vertexCount=vertexCount;<br>D3D11_BUFFER_DESC bd;<br>bd.Usage = D3D11_USAGE_DYNAMIC;<br>bd.ByteWidth = stride * elementCount;<br>bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;<br>bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;<br>bd.MiscFlags = 0; </font> <p><font color="#0000ff">D3D11_SUBRESOURCE_DATA InitData;<br>InitData.pSysMem = data; </font> <p><font color="#0000ff">device->CreateBuffer( &bd, &InitData, &instanceBuffer);</font> <p>Come vedete &egrave; simile a quanto usato per il vertex buffer. Per poter utilizzare l'instancing occorre creare un layout appropriato <p><font color="#0000ff">D3D11_INPUT_ELEMENT_DESC layout[] =<br>{<br>{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, <br>{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, <br>{ "EXTRADATA", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D11_INPUT_PER_INSTANCE_DATA, 1 }, <br>};</font> <p>Nell' instancing il layout &egrave; formato dalla somma dei due formati vertici. Il secondo buffer &egrave; descritto dalla seconda parte dell'array. Si pu&ograve; notare infatti che l'indice &egrave; impostato ad 1 e non a 0 (perch&egrave; sar&agrave; estratto dal secondo buffer), l'offset &egrave; a zero (perch&egrave; si conta l'offset del buffer, non totale del vertice) e si imposta il tipo ad Instance_Data. L'ultimo valore, instance_repetition, va impostato ad 1.  <p>Ora quello che si dovr&ograve; fare in fase di rendering &egrave; passare i 2 vertex buffer contemporaneamente (quello con i dati e quello con i dati per l'instancing).  <p>&nbsp;Ad esempio nel caso del solo Vertex Buffer  <p><font color="#0000ff">device->IASetInputLayout(this->layout);<br>device->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);<br>ID3D11Buffer* buffers[2]={vertexBuffer,instanceVertexBuffer};<br>UINT strideA[2]={stride,instanceStride};<br>UINT offsetA[2]={0,0}; </font> <p><font color="#0000ff">device->IASetVertexBuffers(0,2,buffers,strideA,offsetA);<br>device->DrawInstanced(VertexCount,istanceCount,0,0);</font> <p>O nel caso ci sia anche Index Buffer <p>device->IASetVertexBuffers(0,2,buffers,strideA,offsetA);<br>device->IASetIndexBuffer(indexBuffer,DXGI_FORMAT_R16_UINT,0);<br>device->DrawIndexedInstanced(FaceCount*3,istanceCount,0,0,0); <p>In questo esempio vedete come ho eseguito il rendering. Ho creato un array con due buffer e li ho passati al device insieme ai due stride ed i due offset. Nel mio esempio avr&ograve; uno stride di 20 byte per il primo vertex buffer (POSITION e TEXCOORD) e 16 per il secondo (EXTRADATA). Successivamente passo l'indexbuffer ed utilizzo l'istruzione DrawIndexedInstanced per mandare il rendering (gli si passa alla funzione il numero degli indici ed il numero di istance ossia quante copie dell'oggetto volete). Con la funzione DrawIndexedInstance potrete renderizzare oggetti da un minimo di zero ad un massimo pari al numero di elementi nel buffer dell'instance. <p>Nello shader non noterete differenza <p><font color="#0000ff">struct VS_INPUT<br>{<br>float4 Pos : POSITION;<br>float2 tex:TEXCOORD;<br>float4 posIstance:EXTRADATA;<br>};</font> <p>Ogni vertice del primo buffer sar&agrave; combinato con ogni vertice (anche se in realt&agrave; sono dati anche se gestiti come vertici). Quindi se abbiamo un cubo e 1000 vettori posizione otterremo 8 (vertici del cubo) * 1000 = 8000 vertici e quindi 8000 chiamate allo shader con tutte le combinazioni. Nello shader ad esempio potremo utilizzare il vettore per spostare il cubo in modo da assegnare ad ognuno una posizione diversa. Passando 4 float4 avrete una intera matrice. Potete passare quanti dati volete.  <p>Nella struttura di input potete utilizzare un campo non definito nei due buffer con sintatti <strong>SV_InstanceID</strong> <p><font color="#0000ff">uint indice:SV_InstanceID</font> <p>Questo campo contiene l'indice dell'instanza che stiamo renderizzando (che varier&agrave; quindi da 0 a 999 nell'esempio).  <p>Vi lascio al demo che renderizza fino a 1000 cubi contemporaneamente.  <p><a href="http://www.notjustcode.it/public/DirectX11Source/TutorialCpp12.zip">Demo CPP</a> <p><a href="http://www.notjustcode.it/public/DirectX11Source/TutorialNet12.zip">Demo .Net</a></p>]]></content>
		<link rel="alternate" type="text/html" href="http://www.notjustcode.it/dblog/articolo.asp?articolo=296"/>
		<issued>2010-06-01T21:00:00+01:00</issued>
		<modified>2010-06-01T21:00:00+01:00</modified>
		<slash:comments>0</slash:comments>
		<wfw:comments>http://www.notjustcode.it/dblog/articolo.asp?articolo=296#commenti</wfw:comments>
	</entry>
	<entry>
		<title><![CDATA[Introduzione ai videogiochi]]></title>
		<id>http://www.notjustcode.it/dblog/articolo.asp?articolo=295</id>
		<created>2010-05-12T21:43:50+01:00</created>
		<content type="text/html" mode="escaped"><![CDATA[<p><span new=""><font face="Verdana">Quando ci si avvicina per la prima volta ad un argomento come la programmazione<br />dei videogiochi &egrave; spesso difficile capire realmente cosa fare.<br />Le nozioni con cui si viene a contatto sono molte e capire come si integrano<br />nell'immenso contesto alle volte pu&ograve; rappresentare un ostacolo.<br />Con questo documento ho cercato di riassumere i concetti fondamentali per sapere <br />quello che si sta per affrontare, e fornire le basi per comprendere argomenti pi&ugrave; avanzati.<br />Detto questo vi lascio alla lettura (che spero troviate interessante), restando disponibile <br />per ogni tipo di domanda (l'indirizzo e-mail a cui scrivermi lo trovate nell'ultima diapositiva).<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Black Dragon<br /><br />ps: potete tranquillamente usare questo documento come meglio vi pare. Se <br />lo pubblicate da qualche parte mi piacerebbe saperlo.</font></span></p>
<p><span new=""><a href="http://www.notjustcode.it/public/FanGames/presenazione_lezione_videogiochi.pdf">Download</a></span></p>]]></content>
		<link rel="alternate" type="text/html" href="http://www.notjustcode.it/dblog/articolo.asp?articolo=295"/>
		<issued>2010-05-12T21:43:50+01:00</issued>
		<modified>2010-05-12T21:43:50+01:00</modified>
		<slash:comments>2</slash:comments>
		<wfw:comments>http://www.notjustcode.it/dblog/articolo.asp?articolo=295#commenti</wfw:comments>
	</entry>
	<entry>
		<title><![CDATA[Compute Shader]]></title>
		<id>http://www.notjustcode.it/dblog/articolo.asp?articolo=294</id>
		<created>2010-04-30T20:53:03+01:00</created>
		<content type="text/html" mode="escaped"><![CDATA[<p></p> <p>Con la crescente potenza e versatilit&agrave; delle schede video sono nate negli ultimi anni diverse tecnologie volte ad utilizzare la GPU per operazioni diverse dal rendering di grafica. Tra le tecnologie volte a questo scopo c’&egrave; ad esempio CUDA di nVidia, OpenCL e, nel caso di DirectX11, le Direct Compute.  <p>Sotto il nome di Direct Compute c’&egrave; un sotto insieme di funzioni Direct3D per l’esecuzioni di calcoli matematici tramite l’utilizzo dei Compute Shaders, degli speciali Shader che anzich&eacute; entrare nella pipeline grafica non fanno altro che leggere e scrivere su appositi buffer di memoria. <p>Al termine dell’operazione sar&agrave; sufficiente andare a leggere i dati da tale buffer e farci ci&ograve; che serve. Il vantaggio dei Compute Shader non &egrave; tanto nella potenza di calcolo per singola operazione ma per il fatto che sono ottimizzate per lavorare su vettori e soprattutto lavorano con un elevatissimo numero di processi in parallelo raggiungendo, se utilizzate correttamente, prestazioni irraggiungibili per qualsiasi CPU. Gli utilizzi spaziano dai giochi (esempio per l’intelligenza artificiale) alle applicazioni che con la grafica non c’entrano nulla come ad esempio funzioni statistiche.  <p>Questo articolo introdurr&agrave; l’argomento che &egrave; di fatto vasto ed apre una quantit&agrave; di scenari grandissima. <p>Un Compute Shader presenta molte caratteristiche che lo differenziano dagli altri Shader. Innanzitutto la funzione non restituisce nulla ma lavora attraverso l’uso di speciali buffer chiamati Unordered Access View. Questi buffer, passati al DeviceContext in modo simile ai normali Constant Buffer, permettono di leggere e scrivere all’interno di essi. Dal codice C++ verr&agrave; creato un buffer di tipo UAV (abbreviazione del nome completo) e all’interno dello shader sar&agrave; presente come variabile di una delle tipologie a disposizione. <ul> <li>AppendStructuredBuffer </li> <li>Buffer </li> <li>ByteAddressBuffer </li> <li>ConsumeStructuredBuffer </li> <li>RWByteAddressBuffer </li> <li>RWStructuredBuffer </li> <li>RWTexture1D </li> <li>RWTexture1DArray </li> <li>RWTexture2D </li> <li>RWTexture2DArray </li> <li>RWTexture3D </li></ul> <p>Non tutte supportano sia lettura che scrittura (AppendStructuredBuffer ad esempio permette solo di aggiungere valori come fosse una lista). Alcune inoltre permettono anche il supporto a Template (Generics per i programmatori .Net e Java). <p>Esempio  <p><font color="#0000ff">RWStructuredBuffer<MyStruct> buffer;</font> <p>Dove MyStruct &egrave; una struttura a mio piacere. <p>Tutte queste avranno un unico corrispettivo nel codice, l’oggetto ID3D11UnorderedAccessView che di fatto &egrave; una vista su un ID3D11Buffer. Entrambi andranno gestiti in quanto il primo &egrave; una vista al secondo che sar&agrave; utilizzato per estrarre o inserire dati. Ecco come vengono creati  <p><font color="#0000ff">ID3D11Buffer* viewBuffer; </font> <p><font color="#0000ff">D3D11_BUFFER_DESC sbDesc ;</font> <p><font color="#0000ff">sbDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;</font> <p><font color="#0000ff">sbDesc.Usage = D3D11_USAGE_DEFAULT;</font> <p><font color="#0000ff">sbDesc.CPUAccessFlags = 0;</font> <p><font color="#0000ff">sbDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;</font> <p><font color="#0000ff">sbDesc.StructureByteStride = sizeOfStruct;</font> <p><font color="#0000ff">sbDesc.ByteWidth = sizeOfStruct * size;</font> <p><font color="#0000ff">hr = device->CreateBuffer(&sbDesc,NULL,&viewBuffer);</font> <p><font color="#0000ff">ID3D11UnorderedAccessView* view;</font> <p><font color="#0000ff">D3D11_UNORDERED_ACCESS_VIEW_DESC sbUAVDesc;</font> <p><font color="#0000ff">sbUAVDesc.Buffer.FirstElement=0;</font> <p><font color="#0000ff">sbUAVDesc.Buffer.Flags=0;</font> <p><font color="#0000ff">sbUAVDesc.Buffer.NumElements=TotalSize;</font> <p><font color="#0000ff">sbUAVDesc.Format = DXGI_FORMAT_UNKNOWN;</font> <p><font color="#0000ff">sbUAVDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;</font> <p><font color="#0000ff">hr=device->CreateUnorderedAccessView(viewBuffer,&sbUAVDesc,&view);</font> <p>Non molto diversi dal consueto.  <p>Attenzione: <ol> <li>Le opzioni MiscFlags del Buffer e Flags e Format dell’ UnorderedAccessView vanno impostate in base al tipo di buffer nel codice HLSL. Nell’esempio ho usato un RWStructuredBuffer ma ognuno varia. Consultate l’help per vedere ognuno cosa vuole. </li> <li>La dimensione deve essere multipla di 32bit</li></ol> <p>Ora &egrave; necessario creare l’oggetto ID3D11ComputeShader, cosa che avviene in modo identico agli altri Shader. Quindi passiamo i dati al DeviceContext <p><font color="#0000ff">context->CSSetShader(computeShader,NULL,0);</font> <p>E passiamo i buffer UAV <p><font color="#0000ff">context->CSSetUnorderedAccessViews(start,count,&views,NULL);</font> <p>Il primo element &egrave; l’indice dell’array views di ID3D11UnorderedAccessView e count il numero di elementi da caricare. L’ultimo valore passato a NULL nell’esempio va utilizzato nel caso di buffer di tipo Append o Consume (nel primo caso una lista a cui aggiungere valori, nel secondo valori da cui estrarre dati). In questo caso &egrave; possibile passare un array di interi (uno per ogni buffer) che ci dar&agrave; il numero iniziale di valori (ad esempio una lista append precedentemente riempita di 100 elementi pu&ograve; essere usata una seconda volta sovrascrivendo solo gli ultimi 50 valori e non tutti gli altri). <p>Ora si manda in esecuzione il codice tramite l’istruzione Dispatch che eseguir&agrave; la funzione il numero di volte che decideremo. <p><font color="#0000ff">Context->Dispatch(X,Y,Z);</font> <p>Prima per&ograve; andiamo a spiegare come funziona il parallelismo. Il codice di un Compute Shader &egrave; una funzione HLSL eseguita tantissime volte in parallelo. Il numero di esecuzioni &egrave; indicato in gruppi tramite 3 valori interi XYZ come a rappresentare una scacchiera a 3 dimensioni. Ogni gruppo a sua volta ha 3 valori che indicano il numero Thread per ogni gruppo da eseguire. Il gruppo di Thread &egrave; un concetto importante in quanto un gruppo &egrave; in grado di condividere non solo un buffer UAV, ma anche variabili comuni. <p>Se ad esempio definisco una variabile in questo modo <p><font color="#0000ff">groupshared float4 myVal;</font> <p>Questa sar&agrave; condivisa in lettura e scrittura tra tutti i thread del gruppo come variabile di appoggio.  <p>Ovviamente sar&agrave; impossibile prevedere l’ordine ed i tempi di esecuzione di ogni thread quindi sar&agrave; necessario gestire l’accesso contemporaneo agli oggetti. Ci sono tuttavia delle istruzioni in grado di sincronizzare i thread creando un’attesa finch&egrave; tutte le funzioni di un gruppo non siano arrivate allo stesso punto. Ad esempio GroupMemoryBarrier fa in modo che nessuna funzione di un gruppo non superi questa istruzione finch&egrave; gli altri thread dello stesso gruppo non hanno completato l’accesso alle variabili condivise mentre GroupMemoryBarrierWithGroupSync fa anche in modo che le istruzioni raggiungano esattamente questa funzione prima che tutte proseguino. Allo stesso modo ci sono funzioni che gestiscono l’accesso ai buffer UAV. <p>Il vantaggio delle variabili groupshared &egrave; la maggiore velocit&agrave; e comodit&agrave; di gestione. Thread di gruppi diversi comunicheranno invece solo tramite i buffer UAV e non potranno essere sincronizzati tra loro. <p>L’istruzione Dispatch indicher&agrave; il numero di gruppi da eseguire. Una scheda video DirectX11 gestisce a pieno le funzionalit&agrave; ComputeShader ed &egrave; in grado di eseguire fino a 65536 gruppi per asse ossia quasi 300000 miliardi di gruppi mentre per ogni gruppo si pu&ograve; raggiungere un limite di 1024 thread per l’asse XY e 64 per l’asse Z. Ovviamente &egrave; un limite puramente teorico in quanto qualsiasi scheda video andrebbe in crash ma l’esecuzione di milioni di thread &egrave; un compito estremamente semplice per una scheda di fascia medio alta e tale valore non far&agrave; altro che migliorare nel tempo. <p>Vediamo ora come &egrave; strutturato un Compute Shader <p><font color="#0000ff">Struct MyStruct</font> <p><font color="#0000ff">{</font> <blockquote> <p><font color="#0000ff">Float4 colore;</font></p></blockquote> <p><font color="#0000ff">};</font> <p><font color="#0000ff">RWStructuredBuffer<MyStruct> inOutBuff;</font> <p><font color="#0000ff">[numthreads( thread_group_size_x, thread_group_size_y, 1 )]</font> <p><font color="#0000ff">void CSMain( uint3 int idx = dispatchThreadID.y * </font><font color="#0000ff">threadIDInGroup : SV_GroupThreadID, uint3 groupID : SV_GroupID, uint groupIndex : SV_GroupIndex, uint3 dispatchThreadID : SV_DispatchThreadID ) </font> <p><font color="#0000ff">{ </font> <blockquote> <p><font color="#0000ff">//valori per riga </font></p></blockquote> <blockquote> <p><font color="#0000ff">int stride = thread_group_size_x * N_THREAD_GROUPS_X; </font></p></blockquote> <blockquote> <p><font color="#0000ff">//indice linearizzato</font></p></blockquote> <blockquote> <p><font color="#0000ff">stride + dispatchThreadID.x;</font></p></blockquote> <blockquote> <p><font color="#0000ff">inOutBuff [ idx ].colore= float4(1,1,1,1);</font></p></blockquote> <p><font color="#0000ff">}</font> <p>E’ possibile vedere una funzione CSMain che per semplicit&agrave; non fa altro che valorizzare un RWStructeredBuffer con un float4 contenente tutti 1. L’attributo numthreads indica quanti thread per asse XYZ la scheda eseguir&agrave;.  <p>Vediamo anche che il metodo non restituisce nulla e che ha in ingresso diversi valori. <ul> <li>SV_GroupThreadID: indica il thread del gruppo eseguito. Sono 3 valori che vanno da 0 ai valori passati a numthreads per ogni asse</li> <li>SV_GroupID: restituisce l’ID del gruppo. Sono 3 valori che variano da 0 al valore passato al metodo Dispatch del DeviceContext</li> <li>SV_GroupIndex: indica l’id del gruppo ma come valore unico da 0 ai valori X*Y*Z di numthreads</li> <li>SV_DispatchThreadID: unisce GroupThreadID e GroupID. I valori andranno da 0 al prodotto tra quello di numthreads e Dispatch per ogni asse. Se quindi abbiamo 32 thread per asse e passiamo al metodo Dispatch il valore 4 allora si andr&agrave; da 0 a 127 incluso</li></ul> <p>Questi valori ci permettono di sapere in quale punto ci troviamo. Ecco come ad esempio possiamo ottenere un valore consecutivo unico per ogni thread <p><font color="#0000ff">int stride = numthreadsX * numDispatchX;</font> <p><font color="#0000ff">int idx = dispatchThreadID.y * stride + dispatchThreadID.x;</font> <p>Il valore stride &egrave; il numero di thread totali lungo la X mentre idx &egrave; il valore unico che ci identificher&agrave; il thread. Le costanti numthreadsX e numDispatchX saranno definite da noi in modo che coincidano con quelle definite nello shader e nel metodo Dispatch. <p>Al termine del metodo Dispatch possiamo leggere il risultato facendo una copia del buffer associato all’UAV su uno di tipo Staging e facendo l’operazione di Map.  <p>Attenzione: il metodo Dispatch &egrave; asincrono. Significa che il codice continuer&agrave; a funzionare anche se lo shader non ha terminato il suo compito a meno di funzioni che accedano al buffer come appunto Map. Un’altra istruzione che forza la conclusione del codice compute shader &egrave; il metodo Flush del DeviceContext, usato anche per la demo. Normalmente sar&agrave; invece preferibile andare avanti con il rendering mentre la scheda termina il calcolo. <p>Oltre alla possibilit&agrave; di usare buffer UAV il Compute Shader pu&ograve; usare i normali ConstantBuffer e le Texture. Al contrario i buffer UAV possono essere usati anche nei Pixel Shader.  <p>L’argomento &egrave; tutt’altro che esaurito ma vi lascio ad un primo esempio che esegue 64 x 64 gruppi di threads da 32x32, un totale di quasi 5 milioni di esecuzioni. Il calcolo eseguito &egrave; la formula di Mac Laurin dell’esponenziale. Ai fini del tutorial non &egrave; necessario sapere come funziona ma vi rimando per cultura personale a quello che &egrave; uno dei tanti sgraditi argomenti matematici delle facolt&agrave; universitarie. <p><img alt="\mathrm{e}^{x} = \sum^{\infin}_{n=0} \frac{x^n}{n!}\quad\mbox{ per ogni } x" src="http://www.notjustcode.it/public/ComputeShader_125AC/clip_image001.gif" width="220" height="57"> <p>Il rapporto &egrave; stato di 6-7 secondi quando eseguito dalla CPU a meno di 20 ms quando eseguito dalla scheda video. Il confronto &egrave; quindi impietoso e la CPU ne esce sconfitta.  <p>Come ultimi appunti ricordo che &egrave; possibile usare i compute shader anche su schede che non supportano le DirectX11 con alcune limitazioni quali l’obbligo di usare solo 1 come valore per i Threads sull’asse Z e massimo 768 come valori su XY. Anche la dimensione della memoria condivisa scende da 32kb a 16kb. <p>Vi lascio l’esempio, in futuro ci sar&agrave; modo di approfondire il Compute Shader con esempi di come sfruttarne la potenza. <p>&nbsp; <p><a href="http://www.notjustcode.it/public/DirectX11Source/TutorialCpp11.zip">Demo CPP</a> <p><a href="http://www.notjustcode.it/public/DirectX11Source/TutorialNet11.zip">Demo .Net</a></p>]]></content>
		<link rel="alternate" type="text/html" href="http://www.notjustcode.it/dblog/articolo.asp?articolo=294"/>
		<issued>2010-04-30T20:53:03+01:00</issued>
		<modified>2010-04-30T20:53:03+01:00</modified>
		<slash:comments>0</slash:comments>
		<wfw:comments>http://www.notjustcode.it/dblog/articolo.asp?articolo=294#commenti</wfw:comments>
	</entry>
	<entry>
		<title><![CDATA[Accesso alle risorse]]></title>
		<id>http://www.notjustcode.it/dblog/articolo.asp?articolo=293</id>
		<created>2010-04-20T23:48:46+01:00</created>
		<content type="text/html" mode="escaped"><![CDATA[<p></p> <p>Una delle cose fondamentali utilizzando <b>DirectX</b> &egrave; il poter accedere alle risorse contenute nei buffer, che siano Constant Buffer, Texture o Vertex Buffer.  <p>Ogni risorsa &egrave; creata in modo da poter essere letta o scritta solamente dalla GPU o dalla CPU. Questo ad esempio pu&ograve; significare che una certa risorsa pu&ograve; essere creata per poter essere letta dalla GPU (esempio una texture quando viene mandata a video) e scritta dalla CPU (per poter essere modificata), o viceversa oppure essere gestita completamente solamente dalla GPU o solamente dalla CPU.  <p>In <b>Direct3D11</b> infatti esistono 4 tipi di usage, ossia le caratteristiche di utilizzo:  <ul> <li><b>D3D11_USAGE_DEFAULT</b>&nbsp; : pu&ograve; essere letta e scritta solo dalla GPU (esempio di lettura &egrave; il vertex buffer, mentre quello in scrittura &egrave; un render target, ossia una texture su cui si fa il rendering)  <li><b>D3D11_USAGE_IMMUTABLE</b> : pu&ograve; essere utilizzata solamente in lettura dalla GPU  <li><b>D3D11_USAGE_DYNAMIC</b>&nbsp; : pu&ograve; essere letta dalla GPU e scritta dalla CPU (ad esempio per creare un vertex buffer che deve cambiare continuamente)  <li><b>D3D11_USAGE_STAGING</b>&nbsp; : pu&ograve; essere letta e scritta solo dalla CPU</li></ul> <p>Non tutte le risorse possono essere create in tutte le modalit&agrave;. Ad esempio in Staging non possiamo creare una texture. Questo porterebbe a pensare che solo alcune tipologie di risorse possano essere lette. Inoltre come si vede solo la modalit&agrave; Staging ha funzionalit&agrave; di lettura da CPU e quindi &egrave; l'unica che pu&ograve; essere letta e modificata da codice, ma allo stesso tempo non si pu&ograve; utilizzare per il rendering.  <p>In <b>Direct3D11</b> si utilizzano quindi le funzioni di Copy che permettono di copiare una risorsa tra buffer. Potete quindi copiare risorse da una risorsa di tipo Default, Immutable e Dynamic&nbsp;in una di tipo Staging, modificarla e ricopiarla sul buffer di origine.  <p>L'unica risorsa su cui non si pu&ograve; andare&nbsp;a scrivere &egrave; solo quella definita come Immutable. Per creare una risorsa di staging si utilizza la classica forma di creazione di un buffer con BindFlags impostato a zero, usage a Staging ed CPUAccessFlags in lettura e scrittura.  <p align="left"><font color="#0000ff">D3D11_BUFFER_DESC bd;</font>  <p align="left"><font color="#0000ff">bd.ByteWidth = stride * vertexCount;</font>  <p align="left"><font color="#0000ff">bd.MiscFlags = 0; </font> <p align="left"><font color="#0000ff">bd.BindFlags = 0;</font>  <p align="left"><font color="#0000ff">bd.Usage = D3D10_USAGE_STAGING;</font>  <p align="left"><font color="#0000ff">bd.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;</font>  <p align="left"><font color="#0000ff">ID3D11Buffer* buffer;<br>HRESULT hr=device->CreateBuffer( &bd, NULL, &buffer );</font></p> <p>Per poter utilizzare la funzionalit&agrave; di copia dovete creare una risorsa di dimensione uguale a quella di origine  <p>A questo punto potete utilizzare le funzionalit&agrave; di copia  <p><font color="#0000ff">deviceContext->CopyResource(buffer,vertexBuffer);</font>  <p>Con questa istruzione ho copiato un vertexBuffer su uno staging.  <p>Ora dovrete andare a leggere le risorse. Per farlo si utilizza l'istruzione Map presente nel DeviceContext.  <p>Questa &egrave; la novit&agrave; rispetto a Direct3D10 in quanto ora &egrave; il Context a gestire l’operazione di Map e non il Buffer stesso.  <p><font color="#0000ff">D3D11_MAPPED_SUBRESOURCE mapped;</font>  <p><font color="#0000ff">hr = context->Map(buffer,0,D3D11_MAP_READ,0,&mapped);</font>  <p><font color="#0000ff">//QUI MODIFICHERETE I DATI</font>  <p><font color="#0000ff">context->Unmap(buffer,0);</font>  <p>L'istruzione map restituisce una struttura mapped che contiene un puntatore pData. Su questo puntatore potrete fare tutte le operazioni che vorrete. Nel nostro caso abbiamo usato il parametro D3D11_MAP_READ ma potete usare anche l’opzione WRITE o entrambe. L’importante &egrave; che siano supportate dal tipo di buffer (Staging le supporta entrambe). Alla funzione map vengono passati sia il buffer che altri valori che andr&agrave; a spiegare.  <p>Quando avete finito dovrete utilizzare l'istruzione UnMap per liberare le risorse. Ora la struttura mapped &egrave; sganciata dal buffer ed andarci a leggere o scrivere potr&agrave; generare errori.  <p>A questo punto potete nuovamente copiare il buffer modificato sul buffer originario ed utilizzarlo per il rendering.  <p>Ora i parametri. L’ultimo zero indica i tempi di attesa consentiti. Il valore 0 indica che l’istruzione aspetter&agrave; che la risorsa sia disponibile mentre D3D11_MAP_FLAG_DO_NOT_WAIT potr&agrave; generare errori se andiamo a chiedere una risorsa mentre &egrave; occupata (problemi che si potrebbero generare soprattutto in multithreating). Il secondo parametro invece indica l’indice della subResource. Alcuni buffer sono strutturati in maniera complessa. Ad esempio esistono Texture contenenti pi&ugrave; copie di se stessa (mipmapping) o array di texture o altre combinazioni. Il buffer contiene quindi pi&ugrave; parti e a seconda di quella scelta dovremo variare il parametro.  <p>Vi lascio con un p&ograve; di consigli  <ul> <li>Nel caso di risorse dynamic, non effettuate il CopyResource su quest'ultimo. Le risorse dynamic possono essere scritte direttamente usando Map ed Unmap. Potete quindi bloccare la risorsa in Staging per leggere i dati ma usare il Map del buffer dinamico come destinazione. Questo far&agrave; risparmiare un bel p&ograve; di lavoro alla macchina  <li>Il processo di copia e soprattutto di Map ed Unmap sono eseguite in CPU, quindi non sono veloci quanto le altre operazione DirectX  <li>Per conoscere le caratteristiche dei buffer usate l'istruzione GetDesc  <li>Usate risorse Dynamic per buffer con frequenti scritture, Default per le risorse da mandare a video alla massima velocit&agrave; possibile. Utilizzate Immutable solo per motivi di sicurezza (nel caso non vogliate modificare il contenuto da altre parti del codice)  <li>La copia tra risorse pu&ograve; avvenire solo tra buffer di pari dimensioni e formati (nel caso di texture)</li></ul> <p>Non rilascer&ograve; un esempio vista la semplicit&agrave; dell'operazione</p>]]></content>
		<link rel="alternate" type="text/html" href="http://www.notjustcode.it/dblog/articolo.asp?articolo=293"/>
		<issued>2010-04-20T23:48:46+01:00</issued>
		<modified>2010-04-20T23:48:46+01:00</modified>
		<slash:comments>0</slash:comments>
		<wfw:comments>http://www.notjustcode.it/dblog/articolo.asp?articolo=293#commenti</wfw:comments>
	</entry>
</feed>