Resources, Buffers, and Textures

Xbox Graphics (XG) is used for subresource management, including allocating graphics memory; specifying fast ESRAM memory for a buffer or texture; resource placement in memory for buffers and textures; using DMA engines for rapid compression/decompression; and multisampling and antialiasing.

Xbox Graphics (XG) for Subresource Management

The Xbox Graphics library (XG) is an auxiliary graphics library that is used for preparing resources and other graphics-related tasks that are performed outside the bounds of the Direct3D runtime interfaces. XG is similar to XGraphics on 360 XDK.

The XG library provides several APIs that allow you to interact with the Xbox One hardware. XG contains APIs to do the following:

Use xg.dll.

See also XG Reference.

Allocating Graphics Memory

To allocate graphics memory, from the February 2014 XDK onwards, use XMemAlloc or VirtualAlloc instead of D3DAllocateGraphicsMemory.

To free graphics memory, from the February 2014 XDK onwards, use XMemFree or VirtualFree instead of D3DFreeGraphicsMemory. Pass-in the address that was returned by XMemAlloc or VirtualAlloc.

D3DFlushCpuCache flushes a CPU cache, using a CPU virtual address that points to graphics memory or committed CPU memory.

Specifying Fast ESRAM Memory for a Buffer or Texture

You can specify that ESRAM will be used for a buffer or texture, so that your buffer or texture resource will be used in the fastest possible memory.

In some situations, the SetPlacement APIs can eliminate the need for this technique (refer to Optimizing Monolithic Driver Performance).

ESRAM can be used for the following:

ESRAM cannot be used for the following:

To specify that ESRAM will be used for a buffer or texture:

  1. In the relevant structure (D3D11_BUFFER_DESC, D3D11_TEXTURE1D_DESC, D3D11_TEXTURE2D_DESC, or D3D11_TEXTURE3D_DESC), in the MiscFlags member, set the flag D3D11X_RESOURCE_MISC_ESRAM_RESIDENT.
  2. In that same structure, set the ESRAMOffsetBytes member, specifying an offset in bytes. You can specify (as a request) 0-32 MB, as a multiple of 4 KB.
  3. Pass that populated structure into the relevant method (ID3D11Device::CreateBuffer, ID3D11Device::CreateTexture1D, ID3D11Device::CreateTexture2D, or ID3D11Device::CreateTexture3D). If the resource doesn’t fit in available ESRAM, the method returns an E_OUTOFMEMORY error.

Example code to create a color and depth texture in ESRAM.

//
// Create our ESRAM color texture
//
D3D11_TEXTURE2D_DESC colorDesc = {0};
colorDesc.Width = 1920;
colorDesc.Height = 1080;
colorDesc.MipLevels = 1;
colorDesc.ArraySize = 1;
colorDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
colorDesc.SampleDesc.Count = 1;
colorDesc.SampleDesc.Quality = 0;
colorDesc.Usage = D3D11_USAGE_DEFAULT;
colorDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
colorDesc.CPUAccessFlags = 0;
colorDesc.MiscFlags = D3D11X_RESOURCE_MISC_ESRAM_RESIDENT;
colorDesc.ESRAMOffsetBytes = (UINT)-1;
XSF_ERROR_IF_FAILED( pDev->CreateTexture2D( &colorDesc, nullptr, &m_pEsramColorTexture ) );
XSF_ERROR_IF_FAILED( pDev->CreateRenderTargetView( m_pEsramColorTexture, nullptr, &m_pEsramColorRTV ) );
XSF_ERROR_IF_FAILED( pDev->CreateShaderResourceView( m_pEsramColorTexture, nullptr, &m_pEsramColorSRV ) );
//
// Create our ESRAM depth texture
//
D3D11_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = 1920;
depthStencilDesc.Height = 1080;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;
depthStencilDesc.SampleDesc.Count = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = D3D11X_RESOURCE_MISC_ESRAM_RESIDENT;
depthStencilDesc.ESRAMOffsetBytes = (UINT)-1;
XSF_ERROR_IF_FAILED( pDev->CreateTexture2D( &depthStencilDesc, nullptr, &m_pEsramDepthStencilTexture ) );
XSF_ERROR_IF_FAILED( pDev->CreateDepthStencilView( m_pEsramDepthStencilTexture, nullptr, &m_pEsramDepthStencilDSV ) );  

ESRAM should not be confused with XMemAlloc or VirtualAlloc: these are for managing GPU access to main memory.

Note that surfaces do not have to fit entirely in ESRAM. You can have surfaces spill off the end of ESRAM, or you can have portions of your ESRAM frame-buffer that get little overdraw still live in DDR3 memory. Refer to the ESRAM sample for an example of how to do this.

Resource Placement in Memory for Buffers and Textures

To create the offline/placement resources at runtime that you pre-process using the XG library, call these methods of ID3D11DeviceX:

D3D11X_RENDERABLE_TEXTURE_ADDRESSES is a structure that is used with the CreatePlacementRenderableTexture2D method. This method is similar to CreatePlacementTexture2D, but allows the title to specify up to three separate virtual addresses representing the individual pieces of the resource.

In some situations, the SetPlacement APIs can eliminate the need for this technique (refer to Optimizing Monolithic Driver Performance).

Using DMA Engines for Rapid Compression/Decompression

There are four hardware DMA engines on the Xbox One GPU, three of which are available for use by Game OS titles. You can access the three DMA engines by using the System Direct Memory Access (SDMA) methods in the ID3D11DmaEngineContextX interface. These DMA engines can be used to move data rapidly, and compress and decompress the data. Typically this data would be packed resources (such as textures or images), but not audio or video data.

ID3D11DmaEngineContextX is a very simple wrapper on top of the DMA engine hardware registers, which means only a single context at a time can be created for each DMA engine. The DMA context methods are not thread safe. DMA engine operations are asynchronous: the CPU and GPU can perform other work in parallel while a DMA operation is in progress.

The ID3D11DmaEngineContextX::CopyLastErrorCodeToBuffer and ID3D11DmaEngineContextX::CopyLastErrorCodeToMemory instruct the DMA engine to copy the last operation’s error code to the given destination. The error code is a 32-bit unsigned integer. The operations that can return error codes are JPEG decompression, LZ compress, and LZ decompress. If the copy operation succeeds, a zero value is written as the error code. Other copy operations do not generate error codes, and do not overwrite the last error code with a zero.

For example:

void* pErrorCodeBuffer = VirtualAlloc( NULL, 64 * 1024, MEM_GRAPHICS | MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE | PAGE_GPU_COHERENT );
pDmaEngineContext->JPEGDecode( ... );
pDmaEngineContext->CopyLastErrorCodeToMemory( pErrorCodeBuffer );
pDmaEngineContext->LZDecode( ... );
pDmaEngineContext->CopyLastErrorCodeToMemory( (void*)( (UINT32*)pErrorCodeBuffer + 1 ) );
pDmaEngineContext->Submit();  

In the example, after the DMA operations complete, two error codes will be written to the first 8 bytes of pErrorCodeBuffer (one error code for each of the two decode operations). It is up to the title to properly synchronize the error code destination locations with their overlapped DMA engine work.

The D3D11X_DMA_JPEG_ERROR_FLAGS enumeration provides flags that can be combined together to form a complete DMA JPEG error code. The similar D3D11X_DMA_LZ_ERROR enumeration provides mutually exclusive error values that can be returned by the LZ decompression engine. Both sets of errors are returned via the CopyLastErrorCodeToBuffer and CopyLastErrorCodeToMemory calls.

Multisampling and Antialiasing

For good quality antialiasing consider using EQAA (enhanced quality antialiasing). There are several levels of EQAA, determined by setting the sampleCount and sampleQuality parameters in the constructor for CD3D11_TEXTURE2D_DESC. Setting low values can invoke EQAA and have a small performance and memory overhead. Setting higher values increases quality but at a higher performance and memory cost.

For an example implementation of multisampling and EQAA, see the Multisampling sample in the XDK Samples at XGD.

A more complex option is to enable 4x multisampling with the first two fragments of every pixel in ESRAM, and with the last two fragments of every pixel in DDR3. The last two fragments are infrequently accessed, due to compression, so the GPU overhead is typically quite low.

See also

DirectX

Fast Semantics