D3DBook:Resources

From GDWiki
Jump to: navigation, search

Contents

Resources

All the math power of a modern graphic adapter would be useless if the API provides no way to store inputs and results. Direct3D 10 uses a mostly unified resource system for this purpose. Every resource represents a block of memory that can be used for different graphic operations. In some cases theses blocks are divided future in multiple parts called sub resources. Independent from the number of sub resources all resources types share some common properties that need be defined during the creation process. After the resource is created every one of the different interface provides a GetDesc method that fills a structure with the resource configuration.

Data Formats

The format of the stored data is one of them and is defined with the DXGI_FORMAT enumeration. The names of the formats are based on a self description system that defines the size of the different data channels in bits and their data type.


Channel prefix Description
R The red data channel
G The green data channel
B The blue data channel
A The alpha data channel
D Depth information data channel
S Stencil data channel
E A channel with a shared exponent value
X Unused data (padding)

Table: Format channel prefixes

Additional to the size each channel can have its own data type. The underscore separates the size from the type. If multiple channels share the same type it would be only added after the last with the same format.


Data format postfix Description
TYPELESS Unspecified data format
FLOAT Floating point value:

16 bit channels use s10e5

32 bit channels use s23e8

UINT Unsigned Integer
SINT Signed Integer
UNORM Unsigned linear normalized to the range 0 to 1
SNORM Signed linear normalized to range -1 to 1
UNORM_SRGB Unsigned normalized to the range 0 to 1. Stored in non linear sRGB color space
SHAREDEXP Floating point value were the data channels contains the mantises and an additional channel (E) contains the shared exponent

Table: Format data postfix


Formats that share the same channels with identical sizes are part of the same group. Direct3D 10 provides casting options for data formats that share the same group. The type less formats plays a special role here as you can create resources using them. But before this data can be used from any part of the pipeline it needs to be fully typed.

Direct3D 10 requires that the shader work always with 32 bit floating point values. But on the resource side there are more possibilities to store such numbers. The two base formats for floating point use 16 or 32 bit per channel. But with R9G9B9E5_SHAREDEXP and R11G11B10_FLOAT there are two additional representations. Both formats requires 32 bit for a texel and therefore less than other floating point formats with three colors.

Beside of this channel bases formats there are 5 block compression formats. The use BC as prefix followed from a number that define the compression type and end with one of the already know postfixes.


Type Description UNORM SNORM SRGB
BC1 4 channel format Yes No Yes
BC2 4 channel format Yes No Yes
BC3 4 channel format Yes No Yes
BC4 Two channel format Yes Yes No
BC5 Single channel format Yes Yes No

Table: Block compression types.

The block size for these formats is always 4x4 texels and every block need 64 or 128 bit in compressed form. There are three basis compression schemes. The first one encodes a three channel color value. It provides a 4 bit linear interpolation between two 16 bit colors. The first three block compression formats make use of it. As an alternative one bit can be used as alpha value in the first block compression format that doesn't provide an explicit alpha channel.

The alpha channels can be stored either as 4 bit per texel or a 3 bit linear interpolation between two 8 bit values. BC2 use the 4 bit version and BC3 the 3 bit interpolation.

The last two block compression formats doesn't contain a color compression block at all. They use one or two of the linear alpha compression blocks to represent general data.

Based on these generic name conventions Direct3D 10 provides a limited set of valid formats. Additional formats are not part of specification and therefore not supported.


Resource Usage

To create every resource in the right memory area Direct3D 10 expect an indication how it will later used. There are four different predefined cases. A Resource can flag as Immutable if it will never changed it content after creation. For that reason you need to provide the content already as part of the creation process. For a slow rate of change Direct3D knows the Default usage. Dynamic is the right choice if the resource will updated multiple times per frame. If it is used to transfer data back from the GPU Direct3D 10 provides a special Staging usage type. Additional the usage limits the access rights of the CPU and GPU for theses resources.


Usage Description CPU Access GPU Access
D3D10_USAGE_IMMUTABLE Resource content is never updated after creation. None Read
D3D10_USAGE_DEFAULT Resource content change not faster than once per frame. None Read/Write
D3D10_USAGE_DYNAMIC Resource content change multiple times per frame. Write Read
D3D10_USAGE_STAGING Resource is used to transfer data to and from the GPU. Read/Write Only copy

Table: Resource Usage

Resource Binding

Image:D3D10_gif_4.gif


Figure 4: Pipeline Binding Points.

The Direct3D pipeline offers multiple points were resources can connected. While some of them accept only one resource at the same time others provides multiple slots. Depending on the used connection the graphics processor will read, write or do both with the data behind the resource. Although the unified memory system allows connecting most resources at every point it is necessary to define all connection points were a resource would use in advanced during resource creation.


Binding point Slot count Access Bind flag Set-Method Get-Method
Index Buffer 1 Read D3D10_BIND_INDEX_BUFFER IASetIndexBuffer IAGetIndexBuffer
Vertex Buffer 16 Read D3D10_BIND_VERTEX_BUFFER IASetVertexBuffers IAGetVertexBuffers
Vertex ShaderConstant Buffer 16 Read D3D10_BIND_CONSTANT_BUFFER VSSetConstantBuffers VSGetConstantBuffers
Vertex ShaderShader Resource 128 Read D3D10_BIND_SHADER_RESOURCE VSSetShaderResources VSGetShaderResources
Geometry ShaderConstant Buffer 16 Read D3D10_BIND_CONSTANT_BUFFER GSSetConstantBuffers GSGetConstantBuffers
Geometry ShaderShader Resource 128 Read D3D10_BIND_SHADER_RESOURCE GSSetShaderResources GSGetShaderResources
Stream Out Target 4 Write D3D10_BIND_STREAM_OUTPUT SOSetTargets SOGetTargets
Pixel ShaderConstant Buffer 16 Read D3D10_BIND_CONSTANT_BUFFER PSSetConstantBuffers PSGetConstantBuffers
Pixel ShaderShader Resource 128 Read D3D10_BIND_SHADER_RESOURCE PSSetShaderResources PSGetShaderResources
Depth Stencil 1 Read/Write D3D10_BIND_DEPTH_STENCIL OMSetRenderTargets OMGetRenderTargets
Render Target 8 Read/Write D3D10_BIND_RENDER_TARGET OMSetRenderTargets OMGetRenderTargets

All 3 shader stages use the same two binding point types. The constant buffers are used as the primary memory for the uniform shader variables. The shader resource binding points can be used to bind resources like textures.

Beside of D3D10_BIND_CONSTANT_BUFFER multiple bind flags can be combined to allow resources to be used on different bind points. This leads to the potential situation were one resource is connected to multiple different binding points. This is allowed as long as the configuration doesn't cause a read/write hazard on the same memory block. Therefore you can't use a resource as Render Target and Shader Resource or any other read write combination at the same time. It is although not valid to bind the same sub resources to multiple write points for one draw call. If you try to break these rules Direct3D 10 will enforce it by solving the hazard condition. After this you will noticed that some resources are not longer bound.

Another limiting factor for the bind point selection is the usage type. As staging resources could not use form the graphics processor you couldn't define any binding. Immutable and dynamic resources could only used for GPU read only operations.


Default Dynamic Immutable Staging
Index Buffer
OK
OK
OK
Vertex Buffer
OK
OK
OK
Constant Buffer
OK
OK
OK
Shader Resource
OK
OK
OK
Stream Out
OK
Depth Stencil
OK
Render Target
OK

Buffer

The simplest Direct3D 10 resource type is the Buffer. It represents a plain type less block of memory without additional sub resources. Additional to the common properties you need only define the overall buffer size in bytes during creation.

As any other resource the device is responsible to create it. The CreateBuffer method will take the full description that is stored in a D3D10_BUFFER_DESC structure. If you want to create an immutable buffer you have to provide initial data for it. In other cases this is an option. As last parameter you have to provide a pointer to a parameter were Direct3D can store the ID3D10Buffer interface pointer. If you pass a NULL pointer along the runtime would not create the resource but it will validate the creation parameters.

The ID3D10Buffer interface contains only a small count of member functions. GetDesc will fill a D3D10_BUFFER_DESC with the values that were used to create the resource. We will discuss the two other methods Map and UnMap later.

Texture 1D

As the 1D texture is a texture type you have to specify a format for its elements. Like a buffer it requires a width but this time it doesn't specify the size in bytes. Instead it defines the number of elements from the selected format. Direct3D 10 can optional create a mip map chain for you. These elements of this chain are accessible as consecutive sub resources. Another option to create sub resources is the texture array. Instead of adding additional smaller blocks of memory every element in the array will have the same width.

Image:D3D10_gif_5.gif


Figure 5: Texture 1D with mip maps and as array.

Creating a 1d texture is very similar to creating a buffer. You need to take additional care if you want to provide initial data. Like the CreateBuffer method CreateTexture1D takes a pointer to a D3D10_SUBRESOURCE_DATA structure. But this time it needs to point to the first element of an array with one element for every sub resource your texture will contain.

Texture 2D

The 2D texture type adds an additional dimension to its smaller brother. It's although the only resource type that supports multi sampling. But you can't use multi sampling together with arrays or mip maps.

Image:D3D10_gif_6.gif


Figure 6: Texture 2D.

Direct3D 10 doesn't have a dedicated cube texture type. To get one you need to create a Texture 2D array with 6 elements and use the additional D3D10_RESOURCE_MISC_TEXTURECUBE flag. This tells the API that these elements should use as the six faces of a cube. As the array parameter is already blocked you can't create an array of cubes. But mip maps are still supported.

Image:D3D10_gif_7.gif


Figure 7: Texture 2D as Cube.

Again CreateTexture2D works like the other resource creation methods and the ID3D10Texture2D interface offers the same methods.

Texture 3D

The last offered resource type supports three dimensions. The only way to create additional sub resources is mipmaping. There is no support for arrays or multisampling

Image:D3D10_gif_8.gif


Figure 8: Texture 3D with Mip maps.

Resource limitations

Beside the valid combinations of creation parameters Direct3D 10 defines some additional limitations for resources. Each size of a 1D and 2D texture are limited to 8192 elements. For 3D resources only 2048 elements per dimension are allowed. In any case no resources could be requiring more than 128 MB memory.

Sub resources

Every time you want refer to a sub resource you need to now its number. This is easy when a resource have only mip maps or only have array elements of the same size. But if you have both at the same time you need to calculate the number. To do this you have to multiple the numbers of mip maps per element with the element you want and add the mip map level. To make this step easier for you the Direct3D 10 header contains the function D3D10CalcSubresource.

Update Resources

After you have created a resource Direct3D 10 provides different ways to update their content as long as they are not defined as Immutable. With the UpdateSubresource method Direct3D 10 can copy a block of memory to a part or a whole sub resource. In the case your resource was created without CPU write access this is the only way for the CPU to change the content after it have created. As UpdateSubresource can transfer data to any kind of resource it use a box to specify the target position and take to pitch values. These parameters will use depended on the number of real dimension of the resource. UpdateSubresource guaranteed that the Direct3D 10 will not use the system memory after it returns. At the same time it makes sure that it does not stall if the data cannot be copied immediately. In such cases it will make an extra copy to an internal buffer. The final copy to the real resource will be scheduled as part of the regular asynchrony command stream.

Copy between Resources

Instead of a memory block you can use another resource as source for a copy operation. With the CopyResource method a resource with all sub resources will be transferred. CopySubresourceRegion allows copying only a section of a sub resource to another one. Both methods requires that you use resources from the same type as source and destination. If you copy from one texture to another the formats must be part of the same format group. As CopyResource cannot stretch both resources must be same size. CopySubresourceRegion can be used with different size but as its brother it will make only a one to one copy. All copy operations will be executed asynchrony. Therefore you will not get any result. If you try to make an illegal copy it will fail silent. But the debug layer will check all parameters that are part of a copy operation and report such errors.

Some common mistakes when using the CopyResource method are:

// try to copy a resource to itself
device->CopyResource (pBuffer, pBuffer);
 
// use an immutable resource as target 
device->CopyResource (pImmutableBuffer3, pDefaultBuffer); 
 
// Destination and source have different sizes
device->CopyResource (p100ByteBuffer, p200ByteBuffer); 
 
// use different resource typesdevice->CopyResource (pTexture, pBuffer);
 
// use incompatible formats
device->CopyResource (pFloatTexture, pUNormTexture);
 
// use a multisample texture as source or target
device->CopyResource (pMultisampleTexture, pOneSampleTexture);
 
// use resources with different mip map counts
device->CopyResource (pOneMipMapTexture, pFullMipMapsTextzre);

As CopySubresourceRegion allows you to specify a destination position and a source box gives you can work around some of the CopyResource limitations but most of them are still valid. As UpdateResource the method could be used with every kind of resource and therefore not every parameter is always used.

With ResolveSubresource

Direct3D 10 supports another method that can transfer data from one sub resource to another. But this one will do more than a simple copy. During the copy the multiple samples in the source will be reduced to a single sample for the destination. This is necessary to make the content of a multisampled resource accessible as a normal texture for future processing. Beside of the different sample count the two sub resources that are used for the resolve operation need to be compatible. This requires the same size and cast able data formats. As ResolveSubresource works with typeless resources the function let you select the format that should be used to calculate the single sample in the right way. But like the sub resources self this format have to be cast able.

Map Resources

The content of resources that are created as dynamic or staging can be mapped in the CPU memory space for direct access. But reading operations for theses memory blocks are limited to staging resources. Dynamic resources support only different write modes instead. You can either request a new memory block and discard anything that was written to the resource before or map with the promise to not overwrite anything you have already changed since the last discard. As Direct3D 10 has only limited access to mapped resources they need to be unmapped before they can used again.

Since each type of resource has a different memory layout the Map and Unmap methods are part of the resource specific interfaces. Independent from the type each Map method takes the required access level. If the resource is a texture and therefore could contain sub resources you have additional select one of them. Finally each Map method fills a provided variable with details how the data is mapped. If the resource has only one dimension (Buffers, 1D Texture) Direct3D 10 will only return a pointer to the first element. For a 2D Texture it additional delivers the size of each line in bytes. The size for a whole plane is added for 3D textures.


Resource type Sub resource Result type
Buffer (ID3D10Buffer) No void* (data)
1D Texture (ID3D10Texture1D) Yes void* (data)
2D Texture (ID3D10Texture2D) Yes D3D10_MAPPED_TEXTURE2D(row pitch, data)
3D Texture (ID3D10Texture2D) Yes D3D10_MAPPED_TEXTURE3D(row pitch, depth pitch, data)

Table mapping methods

To finish the work with a mapped resource a call to the Unmap method is required. Beside the sub resource identifier for textures it doesn't need any other parameter. If the resource has more than one dimension the mapping methods will return pitch information's. You need these values to calculate the start address of the lines and slices as Direct3D 10 doesn't give you a guaranty that there are no padding bytes used.

D3D10_MAPPED_TEXTURE2D Mapped;
 
if (pTexture2D->Map (0, D3D10_MAP_WRITE_DISCARD, 0, &Mapped) == S_OK)
{
    for<nowiki> (UINT Y = 0 ; Y < height ; Y++)</nowiki>
    {
        BYTE* pLine = &((BYTE*)Mapped.pData)[Y*Mapped.RowPitch];
 
        for (UINT X = 0 ; X < width ; X++)
        {
            // Set the texel using pLine and X
        }
    }
 
    pTexture2D->Unmap (0);
}
D3D10_MAPPED_TEXTURE3D Mapped;
 
if (pTexture3D->Map (0, D3D10_MAP_WRITE_DISCARD, 0, &Mapped) == S_OK)
{
    for (UINT Z = 0 ; Z < depth ; Z++)
    {
        for (UINT Y = 0 ; Y < height ; Y++)
        {
            BYTE* pLine = &((BYTE*)Mapped.pData)[Z*Mapped.DepthPitch + Y*Mapped.RowPitch];
 
            for (UINT X = 0 ; X < width ; X++)
            {
                // Set the texel using pLine and X
            }
        }
    }
 
    pTexture3D->Unmap (0);
}

Views

As a resource and it's subresources are only blocks of memory it is often necessary to give Direct3D 10 more details about how it should be used. This is done with one of three view types. Two of them are only used by the Output Merger to access the depth stencil buffer and the render targets. OMSetRenderTargets will set up to eight render target views and one depth stencil view with one call. Every time you call OMSetRenderTargets it will override everything. If you need to know the currently active views OMGetRenderTargets will give you the answer.

The remaining view type is used for any of the 3 shader stages in the pipeline. Each one have 128 slots that can be Set with XXSetShaderResourceView were the XX stands for the stage that should be accessed. In comparison to the output merger calling this method will not reset the current configuration. Only the selected range of views is updated.

But these slots are only used for resources that are accessed by one of the HLSL read functions. The constant buffers that have a fixed format don't need a view. XXSetConstantBuffer takes buffers that are not encapsulated with a view. Like XXSetShaderResourceViews the 16 slots can be updated individual. The same is true for the vertex and index buffer that are used from the input assembler. IASetVertexBuffers and IASetIndexBuffer use raw buffers without a view. As you can have up to 16 vertex streams but only one index buffer only IASetVertexBuffers allows you to define a start slot and range.

If you need a view it should created in advanced like the resource it reference. As the following table shows there are some limitations which resource types a view can contain. Beside of the base resource type a view although different between resources that store arrays or use multisampling. 2D Textures that are flagged as cube map need special handling too.


Resource type Shader resource view Render target view Depth stencil view
Buffer Yes Yes No
Texture 1D Yes Yes Yes
Texture 1D as Array Yes Yes Yes
Texture 2D Yes Yes Yes
Texture 2D as Array Yes Yes Yes
Texture 2D with Multisampling Yes Yes Yes
Texture 2D with Multisampling as Array Yes Yes Yes
Texture 3D Yes Yes No
Texture 2D as Cube Yes No No

Additional to the view dimension you have to provide a format that should be used to access the resource. It needs to be from the same format group that is used by the raw resource and fully typed. Therefore you can't use any format that contains a TYPELESS in its name. If your raw resources already use a valid view format you can use DXGI_FORMAT_UNKNOWN and it will be used for the view too. In this case you can even provide a NULL as description and Direct3D 10 will create a view to the full resource. In any other case the create methods need depending on the selected view dimension more information's.

As a buffer contains only one sub resource it will be selected automatically but you can define the offset of the first element and the number of elements that the user of the view will see. Both values are specified in elements that are depending on the view format and not in bytes like the size of the buffer resource.

Image:D3D10_gif_9.gif


Figure 9: Buffer View.

1D texture can contain multiple mip maps as sub resource. As render targets and depth stencil buffers can only access one level in the chain the mip map need to specify. When the texture used as shader input a range of accessible mip maps could be selected.

Image:D3D10_gif_10.gif


Figure 10: 1D Texture View.

If the 1D texture contains an array of textures the view can limit the accessible elements.

Image:D3D10_gif_11.gif


Figure 11: 2D Texture View.

As long as a 2D texture is not created with multisample elements it behaves like a 1D textures during the view creation. As 2D textures with multisampling doesn't support mip maps there is no need to specified which mip maps would be part of the view.

A view doesn't care about the additional dimension of the 3D texture and you can select a range of mip maps that should be part of the view.

Shader resource views for cube textures are special cases. Even as an array with 6 elements you can only select the mip map range as all faces are part of the view as default.

But you can although create a view without any description. If you use a NULL pointer instead Direct3D will use a default configuration based on the provided raw resource.

An additional service that the create methods provide is a parameter check. If you don't provide a pointer to store the interface pointer to a newly created view Direct3D 10 will only check if your resource and description match all requirements without create the view.

Personal tools