• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2 * Copyright (C) 2014-2015 Intel Corporation.   All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * @file tilemgr.cpp
24 *
25 * @brief Implementation for Macro Tile Manager which provides the facilities
26 *        for threads to work on an macro tile.
27 *
28 ******************************************************************************/
29 #include <unordered_map>
30 
31 #include "fifo.hpp"
32 #include "core/tilemgr.h"
33 #include "core/multisample.h"
34 #include "rdtsc_core.h"
35 
36 #define TILE_ID(x,y) ((x << 16 | y))
37 
MacroTileMgr(CachingArena & arena)38 MacroTileMgr::MacroTileMgr(CachingArena& arena) : mArena(arena)
39 {
40 }
41 
enqueue(uint32_t x,uint32_t y,BE_WORK * pWork)42 void MacroTileMgr::enqueue(uint32_t x, uint32_t y, BE_WORK *pWork)
43 {
44     // Should not enqueue more then what we have backing for in the hot tile manager.
45     SWR_ASSERT(x < KNOB_NUM_HOT_TILES_X);
46     SWR_ASSERT(y < KNOB_NUM_HOT_TILES_Y);
47 
48     if ((x & ~(KNOB_NUM_HOT_TILES_X-1)) | (y & ~(KNOB_NUM_HOT_TILES_Y-1)))
49     {
50         return;
51     }
52 
53     uint32_t id = TILE_ID(x, y);
54 
55     MacroTileQueue &tile = mTiles[id];
56     tile.mWorkItemsFE++;
57     tile.mId = id;
58 
59     if (tile.mWorkItemsFE == 1)
60     {
61         tile.clear(mArena);
62         mDirtyTiles.push_back(&tile);
63     }
64 
65     mWorkItemsProduced++;
66     tile.enqueue_try_nosync(mArena, pWork);
67 }
68 
markTileComplete(uint32_t id)69 void MacroTileMgr::markTileComplete(uint32_t id)
70 {
71     SWR_ASSERT(mTiles.find(id) != mTiles.end());
72     MacroTileQueue &tile = mTiles[id];
73     uint32_t numTiles = tile.mWorkItemsFE;
74     InterlockedExchangeAdd(&mWorkItemsConsumed, numTiles);
75 
76     _ReadWriteBarrier();
77     tile.mWorkItemsBE += numTiles;
78     SWR_ASSERT(tile.mWorkItemsFE == tile.mWorkItemsBE);
79 
80     // clear out tile, but defer fifo clear until the next DC first queues to it.
81     // this prevents worker threads from constantly locking a completed macro tile
82     tile.mWorkItemsFE = 0;
83     tile.mWorkItemsBE = 0;
84 }
85 
GetHotTile(SWR_CONTEXT * pContext,DRAW_CONTEXT * pDC,uint32_t macroID,SWR_RENDERTARGET_ATTACHMENT attachment,bool create,uint32_t numSamples,uint32_t renderTargetArrayIndex)86 HOTTILE* HotTileMgr::GetHotTile(SWR_CONTEXT* pContext, DRAW_CONTEXT* pDC, uint32_t macroID, SWR_RENDERTARGET_ATTACHMENT attachment, bool create, uint32_t numSamples,
87     uint32_t renderTargetArrayIndex)
88 {
89     uint32_t x, y;
90     MacroTileMgr::getTileIndices(macroID, x, y);
91 
92     SWR_ASSERT(x < KNOB_NUM_HOT_TILES_X);
93     SWR_ASSERT(y < KNOB_NUM_HOT_TILES_Y);
94 
95     HotTileSet &tile = mHotTiles[x][y];
96     HOTTILE& hotTile = tile.Attachment[attachment];
97     if (hotTile.pBuffer == NULL)
98     {
99         if (create)
100         {
101             uint32_t size = numSamples * mHotTileSize[attachment];
102             uint32_t numaNode = ((x ^ y) & pContext->threadPool.numaMask);
103             hotTile.pBuffer = (uint8_t*)AllocHotTileMem(size, 64, numaNode + pContext->threadInfo.BASE_NUMA_NODE);
104             hotTile.state = HOTTILE_INVALID;
105             hotTile.numSamples = numSamples;
106             hotTile.renderTargetArrayIndex = renderTargetArrayIndex;
107         }
108         else
109         {
110             return NULL;
111         }
112     }
113     else
114     {
115         // free the old tile and create a new one with enough space to hold all samples
116         if (numSamples > hotTile.numSamples)
117         {
118             // tile should be either uninitialized or resolved if we're deleting and switching to a
119             // new sample count
120             SWR_ASSERT((hotTile.state == HOTTILE_INVALID) ||
121                 (hotTile.state == HOTTILE_RESOLVED) ||
122                 (hotTile.state == HOTTILE_CLEAR));
123             FreeHotTileMem(hotTile.pBuffer);
124 
125             uint32_t size = numSamples * mHotTileSize[attachment];
126             uint32_t numaNode = ((x ^ y) & pContext->threadPool.numaMask);
127             hotTile.pBuffer = (uint8_t*)AllocHotTileMem(size, 64, numaNode + pContext->threadInfo.BASE_NUMA_NODE);
128             hotTile.state = HOTTILE_INVALID;
129             hotTile.numSamples = numSamples;
130         }
131 
132         // if requested render target array index isn't currently loaded, need to store out the current hottile
133         // and load the requested array slice
134         if (renderTargetArrayIndex != hotTile.renderTargetArrayIndex)
135         {
136             SWR_FORMAT format;
137             switch (attachment)
138             {
139             case SWR_ATTACHMENT_COLOR0:
140             case SWR_ATTACHMENT_COLOR1:
141             case SWR_ATTACHMENT_COLOR2:
142             case SWR_ATTACHMENT_COLOR3:
143             case SWR_ATTACHMENT_COLOR4:
144             case SWR_ATTACHMENT_COLOR5:
145             case SWR_ATTACHMENT_COLOR6:
146             case SWR_ATTACHMENT_COLOR7: format = KNOB_COLOR_HOT_TILE_FORMAT; break;
147             case SWR_ATTACHMENT_DEPTH: format = KNOB_DEPTH_HOT_TILE_FORMAT; break;
148             case SWR_ATTACHMENT_STENCIL: format = KNOB_STENCIL_HOT_TILE_FORMAT; break;
149             default: SWR_INVALID("Unknown attachment: %d", attachment); format = KNOB_COLOR_HOT_TILE_FORMAT; break;
150             }
151 
152             if (hotTile.state == HOTTILE_CLEAR)
153             {
154                 if (attachment == SWR_ATTACHMENT_STENCIL)
155                     ClearStencilHotTile(&hotTile);
156                 else if (attachment == SWR_ATTACHMENT_DEPTH)
157                     ClearDepthHotTile(&hotTile);
158                 else
159                     ClearColorHotTile(&hotTile);
160 
161                 hotTile.state = HOTTILE_DIRTY;
162             }
163 
164             if (hotTile.state == HOTTILE_DIRTY)
165             {
166                 pContext->pfnStoreTile(GetPrivateState(pDC), format, attachment,
167                     x * KNOB_MACROTILE_X_DIM, y * KNOB_MACROTILE_Y_DIM, hotTile.renderTargetArrayIndex, hotTile.pBuffer);
168             }
169 
170             pContext->pfnLoadTile(GetPrivateState(pDC), format, attachment,
171                 x * KNOB_MACROTILE_X_DIM, y * KNOB_MACROTILE_Y_DIM, renderTargetArrayIndex, hotTile.pBuffer);
172 
173             hotTile.renderTargetArrayIndex = renderTargetArrayIndex;
174             hotTile.state = HOTTILE_DIRTY;
175         }
176     }
177     return &tile.Attachment[attachment];
178 }
179 
GetHotTileNoLoad(SWR_CONTEXT * pContext,DRAW_CONTEXT * pDC,uint32_t macroID,SWR_RENDERTARGET_ATTACHMENT attachment,bool create,uint32_t numSamples)180 HOTTILE* HotTileMgr::GetHotTileNoLoad(
181     SWR_CONTEXT* pContext, DRAW_CONTEXT* pDC, uint32_t macroID,
182     SWR_RENDERTARGET_ATTACHMENT attachment, bool create, uint32_t numSamples)
183 {
184     uint32_t x, y;
185     MacroTileMgr::getTileIndices(macroID, x, y);
186 
187     SWR_ASSERT(x < KNOB_NUM_HOT_TILES_X);
188     SWR_ASSERT(y < KNOB_NUM_HOT_TILES_Y);
189 
190     HotTileSet &tile = mHotTiles[x][y];
191     HOTTILE& hotTile = tile.Attachment[attachment];
192     if (hotTile.pBuffer == NULL)
193     {
194         if (create)
195         {
196             uint32_t size = numSamples * mHotTileSize[attachment];
197             hotTile.pBuffer = (uint8_t*)AlignedMalloc(size, 64);
198             hotTile.state = HOTTILE_INVALID;
199             hotTile.numSamples = numSamples;
200             hotTile.renderTargetArrayIndex = 0;
201         }
202         else
203         {
204             return NULL;
205         }
206     }
207 
208     return &hotTile;
209 }
210 
211 #if USE_8x2_TILE_BACKEND
ClearColorHotTile(const HOTTILE * pHotTile)212 void HotTileMgr::ClearColorHotTile(const HOTTILE* pHotTile)  // clear a macro tile from float4 clear data.
213 {
214     // Load clear color into SIMD register...
215     float *pClearData = (float *)(pHotTile->clearData);
216     simd16scalar valR = _simd16_broadcast_ss(&pClearData[0]);
217     simd16scalar valG = _simd16_broadcast_ss(&pClearData[1]);
218     simd16scalar valB = _simd16_broadcast_ss(&pClearData[2]);
219     simd16scalar valA = _simd16_broadcast_ss(&pClearData[3]);
220 
221     float *pfBuf = (float *)pHotTile->pBuffer;
222     uint32_t numSamples = pHotTile->numSamples;
223 
224     for (uint32_t row = 0; row < KNOB_MACROTILE_Y_DIM; row += KNOB_TILE_Y_DIM)
225     {
226         for (uint32_t col = 0; col < KNOB_MACROTILE_X_DIM; col += KNOB_TILE_X_DIM)
227         {
228             for (uint32_t si = 0; si < (KNOB_TILE_X_DIM * KNOB_TILE_Y_DIM * numSamples); si += SIMD16_TILE_X_DIM * SIMD16_TILE_Y_DIM)
229             {
230                 _simd16_store_ps(pfBuf, valR);
231                 pfBuf += KNOB_SIMD16_WIDTH;
232 
233                 _simd16_store_ps(pfBuf, valG);
234                 pfBuf += KNOB_SIMD16_WIDTH;
235 
236                 _simd16_store_ps(pfBuf, valB);
237                 pfBuf += KNOB_SIMD16_WIDTH;
238 
239                 _simd16_store_ps(pfBuf, valA);
240                 pfBuf += KNOB_SIMD16_WIDTH;
241             }
242         }
243     }
244 }
245 
ClearDepthHotTile(const HOTTILE * pHotTile)246 void HotTileMgr::ClearDepthHotTile(const HOTTILE* pHotTile)  // clear a macro tile from float4 clear data.
247 {
248     // Load clear color into SIMD register...
249     float *pClearData = (float *)(pHotTile->clearData);
250     simd16scalar valZ = _simd16_broadcast_ss(&pClearData[0]);
251 
252     float *pfBuf = (float *)pHotTile->pBuffer;
253     uint32_t numSamples = pHotTile->numSamples;
254 
255     for (uint32_t row = 0; row < KNOB_MACROTILE_Y_DIM; row += KNOB_TILE_Y_DIM)
256     {
257         for (uint32_t col = 0; col < KNOB_MACROTILE_X_DIM; col += KNOB_TILE_X_DIM)
258         {
259             for (uint32_t si = 0; si < (KNOB_TILE_X_DIM * KNOB_TILE_Y_DIM * numSamples); si += SIMD16_TILE_X_DIM * SIMD16_TILE_Y_DIM)
260             {
261                 _simd16_store_ps(pfBuf, valZ);
262                 pfBuf += KNOB_SIMD16_WIDTH;
263             }
264         }
265     }
266 }
267 
ClearStencilHotTile(const HOTTILE * pHotTile)268 void HotTileMgr::ClearStencilHotTile(const HOTTILE* pHotTile)
269 {
270     // convert from F32 to U8.
271     uint8_t clearVal = (uint8_t)(pHotTile->clearData[0]);
272     //broadcast 32x into __m256i...
273     simd16scalari valS = _simd16_set1_epi8(clearVal);
274 
275     simd16scalari *pBuf = (simd16scalari *)pHotTile->pBuffer;
276     uint32_t numSamples = pHotTile->numSamples;
277 
278     for (uint32_t row = 0; row < KNOB_MACROTILE_Y_DIM; row += KNOB_TILE_Y_DIM)
279     {
280         for (uint32_t col = 0; col < KNOB_MACROTILE_X_DIM; col += KNOB_TILE_X_DIM)
281         {
282             // We're putting 4 pixels in each of the 32-bit slots, so increment 4 times as quickly.
283             for (uint32_t si = 0; si < (KNOB_TILE_X_DIM * KNOB_TILE_Y_DIM * numSamples); si += SIMD16_TILE_X_DIM * SIMD16_TILE_Y_DIM * 4)
284             {
285                 _simd16_store_si(pBuf, valS);
286                 pBuf += 1;
287             }
288         }
289     }
290 }
291 
292 #else
ClearColorHotTile(const HOTTILE * pHotTile)293 void HotTileMgr::ClearColorHotTile(const HOTTILE* pHotTile)  // clear a macro tile from float4 clear data.
294 {
295     // Load clear color into SIMD register...
296     float *pClearData = (float*)(pHotTile->clearData);
297     simdscalar valR = _simd_broadcast_ss(&pClearData[0]);
298     simdscalar valG = _simd_broadcast_ss(&pClearData[1]);
299     simdscalar valB = _simd_broadcast_ss(&pClearData[2]);
300     simdscalar valA = _simd_broadcast_ss(&pClearData[3]);
301 
302     float *pfBuf = (float*)pHotTile->pBuffer;
303     uint32_t numSamples = pHotTile->numSamples;
304 
305     for (uint32_t row = 0; row < KNOB_MACROTILE_Y_DIM; row += KNOB_TILE_Y_DIM)
306     {
307         for (uint32_t col = 0; col < KNOB_MACROTILE_X_DIM; col += KNOB_TILE_X_DIM)
308         {
309             for (uint32_t si = 0; si < (KNOB_TILE_X_DIM * KNOB_TILE_Y_DIM * numSamples); si += SIMD_TILE_X_DIM * SIMD_TILE_Y_DIM) //SIMD_TILE_X_DIM * SIMD_TILE_Y_DIM); si++)
310             {
311                 _simd_store_ps(pfBuf, valR);
312                 pfBuf += KNOB_SIMD_WIDTH;
313                 _simd_store_ps(pfBuf, valG);
314                 pfBuf += KNOB_SIMD_WIDTH;
315                 _simd_store_ps(pfBuf, valB);
316                 pfBuf += KNOB_SIMD_WIDTH;
317                 _simd_store_ps(pfBuf, valA);
318                 pfBuf += KNOB_SIMD_WIDTH;
319             }
320         }
321     }
322 }
323 
ClearDepthHotTile(const HOTTILE * pHotTile)324 void HotTileMgr::ClearDepthHotTile(const HOTTILE* pHotTile)  // clear a macro tile from float4 clear data.
325 {
326     // Load clear color into SIMD register...
327     float *pClearData = (float*)(pHotTile->clearData);
328     simdscalar valZ = _simd_broadcast_ss(&pClearData[0]);
329 
330     float *pfBuf = (float*)pHotTile->pBuffer;
331     uint32_t numSamples = pHotTile->numSamples;
332 
333     for (uint32_t row = 0; row < KNOB_MACROTILE_Y_DIM; row += KNOB_TILE_Y_DIM)
334     {
335         for (uint32_t col = 0; col < KNOB_MACROTILE_X_DIM; col += KNOB_TILE_X_DIM)
336         {
337             for (uint32_t si = 0; si < (KNOB_TILE_X_DIM * KNOB_TILE_Y_DIM * numSamples); si += SIMD_TILE_X_DIM * SIMD_TILE_Y_DIM)
338             {
339                 _simd_store_ps(pfBuf, valZ);
340                 pfBuf += KNOB_SIMD_WIDTH;
341             }
342         }
343     }
344 }
345 
ClearStencilHotTile(const HOTTILE * pHotTile)346 void HotTileMgr::ClearStencilHotTile(const HOTTILE* pHotTile)
347 {
348     // convert from F32 to U8.
349     uint8_t clearVal = (uint8_t)(pHotTile->clearData[0]);
350     //broadcast 32x into __m256i...
351     simdscalari valS = _simd_set1_epi8(clearVal);
352 
353     simdscalari* pBuf = (simdscalari*)pHotTile->pBuffer;
354     uint32_t numSamples = pHotTile->numSamples;
355 
356     for (uint32_t row = 0; row < KNOB_MACROTILE_Y_DIM; row += KNOB_TILE_Y_DIM)
357     {
358         for (uint32_t col = 0; col < KNOB_MACROTILE_X_DIM; col += KNOB_TILE_X_DIM)
359         {
360             // We're putting 4 pixels in each of the 32-bit slots, so increment 4 times as quickly.
361             for (uint32_t si = 0; si < (KNOB_TILE_X_DIM * KNOB_TILE_Y_DIM * numSamples); si += SIMD_TILE_X_DIM * SIMD_TILE_Y_DIM * 4)
362             {
363                 _simd_store_si(pBuf, valS);
364                 pBuf += 1;
365             }
366         }
367     }
368 }
369 
370 #endif
371 //////////////////////////////////////////////////////////////////////////
372 /// @brief InitializeHotTiles
373 /// for draw calls, we initialize the active hot tiles and perform deferred
374 /// load on them if tile is in invalid state. we do this in the outer thread
375 /// loop instead of inside the draw routine itself mainly for performance,
376 /// to avoid unnecessary setup every triangle
377 /// @todo support deferred clear
378 /// @param pCreateInfo - pointer to creation info.
InitializeHotTiles(SWR_CONTEXT * pContext,DRAW_CONTEXT * pDC,uint32_t workerId,uint32_t macroID)379 void HotTileMgr::InitializeHotTiles(SWR_CONTEXT* pContext, DRAW_CONTEXT* pDC, uint32_t workerId, uint32_t macroID)
380 {
381     const API_STATE& state = GetApiState(pDC);
382 
383     uint32_t x, y;
384     MacroTileMgr::getTileIndices(macroID, x, y);
385     x *= KNOB_MACROTILE_X_DIM;
386     y *= KNOB_MACROTILE_Y_DIM;
387 
388     uint32_t numSamples = GetNumSamples(state.rastState.sampleCount);
389 
390     // check RT if enabled
391     unsigned long rtSlot = 0;
392     uint32_t colorHottileEnableMask = state.colorHottileEnable;
393     while (_BitScanForward(&rtSlot, colorHottileEnableMask))
394     {
395         HOTTILE* pHotTile = GetHotTile(pContext, pDC, macroID, (SWR_RENDERTARGET_ATTACHMENT)(SWR_ATTACHMENT_COLOR0 + rtSlot), true, numSamples);
396 
397         if (pHotTile->state == HOTTILE_INVALID)
398         {
399             AR_BEGIN(BELoadTiles, pDC->drawId);
400             // invalid hottile before draw requires a load from surface before we can draw to it
401             pContext->pfnLoadTile(GetPrivateState(pDC), KNOB_COLOR_HOT_TILE_FORMAT, (SWR_RENDERTARGET_ATTACHMENT)(SWR_ATTACHMENT_COLOR0 + rtSlot), x, y, pHotTile->renderTargetArrayIndex, pHotTile->pBuffer);
402             pHotTile->state = HOTTILE_DIRTY;
403             AR_END(BELoadTiles, 0);
404         }
405         else if (pHotTile->state == HOTTILE_CLEAR)
406         {
407             AR_BEGIN(BELoadTiles, pDC->drawId);
408             // Clear the tile.
409             ClearColorHotTile(pHotTile);
410             pHotTile->state = HOTTILE_DIRTY;
411             AR_END(BELoadTiles, 0);
412         }
413         colorHottileEnableMask &= ~(1 << rtSlot);
414     }
415 
416     // check depth if enabled
417     if (state.depthHottileEnable)
418     {
419         HOTTILE* pHotTile = GetHotTile(pContext, pDC, macroID, SWR_ATTACHMENT_DEPTH, true, numSamples);
420         if (pHotTile->state == HOTTILE_INVALID)
421         {
422             AR_BEGIN(BELoadTiles, pDC->drawId);
423             // invalid hottile before draw requires a load from surface before we can draw to it
424             pContext->pfnLoadTile(GetPrivateState(pDC), KNOB_DEPTH_HOT_TILE_FORMAT, SWR_ATTACHMENT_DEPTH, x, y, pHotTile->renderTargetArrayIndex, pHotTile->pBuffer);
425             pHotTile->state = HOTTILE_DIRTY;
426             AR_END(BELoadTiles, 0);
427         }
428         else if (pHotTile->state == HOTTILE_CLEAR)
429         {
430             AR_BEGIN(BELoadTiles, pDC->drawId);
431             // Clear the tile.
432             ClearDepthHotTile(pHotTile);
433             pHotTile->state = HOTTILE_DIRTY;
434             AR_END(BELoadTiles, 0);
435         }
436     }
437 
438     // check stencil if enabled
439     if (state.stencilHottileEnable)
440     {
441         HOTTILE* pHotTile = GetHotTile(pContext, pDC, macroID, SWR_ATTACHMENT_STENCIL, true, numSamples);
442         if (pHotTile->state == HOTTILE_INVALID)
443         {
444             AR_BEGIN(BELoadTiles, pDC->drawId);
445             // invalid hottile before draw requires a load from surface before we can draw to it
446             pContext->pfnLoadTile(GetPrivateState(pDC), KNOB_STENCIL_HOT_TILE_FORMAT, SWR_ATTACHMENT_STENCIL, x, y, pHotTile->renderTargetArrayIndex, pHotTile->pBuffer);
447             pHotTile->state = HOTTILE_DIRTY;
448             AR_END(BELoadTiles, 0);
449         }
450         else if (pHotTile->state == HOTTILE_CLEAR)
451         {
452             AR_BEGIN(BELoadTiles, pDC->drawId);
453             // Clear the tile.
454             ClearStencilHotTile(pHotTile);
455             pHotTile->state = HOTTILE_DIRTY;
456             AR_END(BELoadTiles, 0);
457         }
458     }
459 }
460