Tag: directx

Entries for tag "directx", ordered from most recent. Entry count: 57.

Pages: 1 2 3 ... 8 >

# Stencil Test Explained Using Code

20:11
Sun
20
Aug 2017

I must admit I never used stencil buffer in my personal code. I know it's there available in GPUs and all graphics APIs for years and it's useful for many things, but somehow I never had a need to use it. Recently I became aware that I don't fully understand it. There are many descriptions of stencil test on the Internet, but none of them definitely answered my questions in the way I would like them to be answered. I thought that a piece of pseudocode would explain it better than words, so here is my explanation of the stencil test.

Let's choose Direct3D 11 as our graphics API. Other APIs have similar sets of parameters. D3D11 offers following configuration parameters for stencil test:

Structure D3D11_DEPTH_STENCIL_DESC:

BOOL StencilEnable
UINT8 StencilReadMask
UINT8 StencilWriteMask
D3D11_DEPTH_STENCILOP_DESC FrontFace
D3D11_DEPTH_STENCILOP_DESC BackFace

Structure D3D11_DEPTH_STENCILOP_DESC:

D3D11_STENCIL_OP StencilFailOp
D3D11_STENCIL_OP StencilDepthFailOp
D3D11_STENCIL_OP StencilPassOp
D3D11_COMPARISON_FUNC StencilFunc

Parameter passed to ID3D11DeviceContext::OMSetDepthStencilState method:

UINT StencilRef

How do they work? If you render pixel (x, y) and you have current value of stencil buffer available as:

UINT8 Stencil[x, y]

Then pseudocode for stencil test and write could look like below. First, one of two sets of parameters is selected depending on whether current primitive is front-facing or back-facing:

if(StencilEnable)
{
    if(primitive has no front and back face, e.g. points, lines)
      StencilOpDesc = FrontFace
    else
    {
       if(primitive is front facing)
          StencilOpDesc = FrontFace
       else
          StencilOpDesc = BackFace
   }

Then, a test is performed:

    StencilTestPassed =
       (StencilRef & StencilReadMask) StencilOpDesc.StencilFunc
       (Stencil[x, y] & StencilReadMask)

StencilOpDesc.StencilFunc is a comparison operator that can be one of possible enum values: D3D11_COMPARISON_NEVER, LESS, EQUAL, LESS_EQUAL, GREATER, NOT_EQUAL, GREATER_EQUAL, ALWAYS. I think this is quite self-explanatory.

Notice how StencilRef is on the left side of comparison operator and current stencil buffer value is on the right.

Both StencilRef and current stencil buffer value are ANDed with StencilReadMask before comparison.

Next, based on the result of this test, as well as result of depth-test aka Z-test (which is out of scope of this article), an operation is selected:

    if(StencilTestPassed)
    {
       if(DepthTestPassed)
          Op = StencilOpDesc.SencilPassOp
       else
          Op = StencilOpDesc.StencilDepthFailOp
    }
    else
        Op = StencilOpDesc.StencilFailOp

Op is another enum that controls a new value to be written to stencil buffer. It can be one of:

    switch(Op)
    {
    case D3D11_STENCIL_OP_KEEP: NewValue = Stencil[x, y]
    case D3D11_STENCIL_OP_ZERO: NewValue = 0
    case D3D11_STENCIL_OP_REPLACE: NewValue = StencilRef
    case D3D11_STENCIL_OP_INCR_SAT: NewValue = min(Stencil[x, y] + 1, 0xFF)
    case D3D11_STENCIL_OP_DECR_SAT: NewValue = max(Stencil[x, y] - 1, 0)
    case D3D11_STENCIL_OP_INVERT: NewValue = ~Stencil[x, y]
    case D3D11_STENCIL_OP_INCR: NewValue = Stencil[x, y] + 1 // with 8-bit wrap-around
    case D3D11_STENCIL_OP_DECR: NewValue = Stencil[x, y] - 1 // with 8-bit wrap-around
    }

Finally, the new value is written to the stencil buffer. Notice how only those bits are changed that are included in StencilWriteMask. Others remain unchanged.

    Stencil[x, y] =
       (Stencil[x, y] & ~StencilWriteMask) |
       (NewValue & StencilWriteMask)
}

Now as we have all this explained in a very strict way using code, let me answer doubts I had before understanding this, in form of a FAQ.

Q: Are there no separate flags to enable stencil test and stencil write?

A: No. There is only one flag StencilEnable to enable all this functionality.

Q: So how to use only one and not the other?

A: You can find specific set of settings to do that.

To perform only stencil test and not write, set StencilEnable to true, StencilFunc to the comparison function you need and set all *Op to KEEP or alternatively set StencilWriteMask to 0 to disable any modifications to stencil buffer.

To perform only stencil write and not stencil test, set StencilEnable to true, all *Op and StencilWriteMask to values you need and set StencilFunc to ALWAYS to make the stencil test always passing.

Q: Is the StencilRef value also masked by StencilReadMask?

A: Yes. As you can see in the code, it is also ANDed with StencilReadMask, just as the previous value from stencil buffer. You don't need to provide it "pre-masked". (Comparison to "premultipled alpha" comes to my mind...)

In other words, we could say that only bits indicated by StencilReadMask from both sides participate in comparison.

Q: What are stencil value bits replaced to in REPLACE Op mode?

A: They are replaced with StencilRef value - the same that was used in comparison.

Q: Why is it the same StencilRef value as used for comparison, not separate one?

A: I don't know. There is separate StencilReadMask and StencilWriteMask. They could have provided separate "StencilReadRef" and "StencilWriteRef" - but for some reason the didn't :P

Q: What value is incremented/decremented when Op in INCR*, DECR*?

A: It's the original value read from stencil buffer, not masked or shifted in relation to StencilReadMask or StencilWriteMask. Which means it doesn't make much sense to use these ops if your StencilWriteMask looks like e.g. 0xF0 - masks out least significant bits.

Q: Is depth buffer updated when stencil test fails?

A: No. Failing stencil test means that the pixel is discarded, so Z-buffer is not updated and color is not written or blended to render targets.

On the other hand, failing Z-test can cause stencil buffer to be updated when you use StencilDepthFailOp other than KEEP.

If I misunderstood something and some of the information in this article is wrong, please let me know by e-mail or comment below.

Comments | #directx #graphics Share

# ID3D11Device::CreateTexture2D: pInitialData[0].SysMemPitch cannot be 0

17:07
Sat
09
Jan 2016

The concept of "stride" or "pitch" - a step (in bytes) to be taken to proceed to next element of a data structure - is brilliant, because it gives great flexibility. In 3D graphics for example, explicitly specified number of bytes between vertices in a vertex buffer or rows in a texture can be:

  1. Equal to exact size of vertex structure or texture row, when these entries are laid out next to each other.
  2. Greater, so additional padding can exist at the end of each entry or entries can be interleaved with some other data to be skipped in particular case.
  3. Zero, so that the same single entry will be read over and over.

This is a theory, because I just discovered that option 3 doesn't work in Direct3D 11 when passing pInitialData to created texture. I cannot see any reason why specifying D3D11_SUBRESOURCE_DATA::SysMemPitch == 0 should be considered invalid, other than trying to save developer from possibly unintended mistake. I think it is actually pretty useful for initializing a texture with the same data in each row, so it would be enough to allocate and fill the data for just one row, instead of full texture. And still, following code fails on call to CreateTexture2D:

CD3D11_TEXTURE2D_DESC textureDesc = CD3D11_TEXTURE2D_DESC(
    TEXTURE_FORMAT, // format
    (UINT)TEXTURE_SIZE.x, // width
    (UINT)TEXTURE_SIZE.y, // height
    1, // arraySize
    1, // mipLevels
    D3D11_BIND_SHADER_RESOURCE, // bindFlags
    D3D11_USAGE_DYNAMIC, // usage
    D3D11_CPU_ACCESS_WRITE); // cpuaccessFlags
std::vector<uint32_t> initialTextureRow(TEXTURE_SIZE.x);
ZeroMemory(&initialTextureRow[0], TEXTURE_SIZE.x * sizeof(uint32_t));
D3D11_SUBRESOURCE_DATA textureInitialData = {
    &initialTextureRow[0], // pSysMem
    0, // SysMemPitch
    0 }; // SysMemSlicePitch
ID3D11Texture2D *texture = nullptr;
ERR_GUARD_DIRECTX( m_Dev->CreateTexture2D(&textureDesc, &textureInitialData, &texture) );

DirectX debug layer reports error:

D3D11 ERROR: ID3D11Device::CreateTexture2D: pInitialData[0].SysMemPitch cannot be 0 [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA]

Dear Microsoft: Why? :)

Comments | #directx Share

# Direct3D 12 - Watch out for non-uniform resource index!

15:30
Mon
28
Sep 2015

DirectX 12 allows us to use arrays of resources (descriptor tables) and refer to them from a shader code by an index. The index can be constant or variable. But there is a big trap waiting for shader developers doing that! Microsoft just updated their public documentation in this regard (see Resource Binding in HLSL), so now I can talk about it.

In D3D12, resource index is expected to be uniform (convergent) by default. It means the index, even if dynamic, should be the same across whole draw call (all vertices/pixels/etc.). For example, it can be a result of some calculations, which depend on parameters coming from a constant buffer. Example code:

Texture2D<float4> textures[16] : register(t0);
SamplerState samp : register(s0);
struct SConstantBuffer
{
    uint MaterialId;
};
ConstantBuffer<SConstantBuffer> cb : register(b0);

float4 PS(
    in float2 texCoords : TEXCOORD0 ) : SV_Target
{
    uint materialId = cb.MaterialId;
    return textures[materialId].Sample(samp, texCoords);
}

Why is it this way? That is because on low level, GPU-s are made of SIMD processors. Each of its small processors executes shader instructions over multiple "SIMD threads" (or "warps", or "wavefronts", however you call them), not a single (scalar) value. Because of that, knowing that the resource index will always be the same on all SIMD threads can result in some optimizations and more efficient execution.

Resource indices in Direct3D 12 actually can be non-uniform (divergent) - different in every vertex/pixel/etc., like when they are result of some calculations based on vertex attributes or pixel position. But they must be then surrounded by a special, "pseudo"-function in HLSL, called NonUniformResourceIndex. For example:

Texture2D<float4> textures[16] : register(t0);
SamplerState samp : register(s0);

float4 PS(
    in float2 texCoords : TEXCOORD0,
    in uint materialId : MATERIAL_ID ) : SV_Target
{
    return textures[NonUniformResourceIndex(materialId)].Sample(samp, texCoords);
}

This may look a bit unintuitive, so I expect many developers will make the mistake and omit this function. If you use a non-uniform value as resource index, but forget to mark it with NonUniformResourceIndex, HLSL compiler probably won't warn you about it. It may even work in some cases and on some GPU-s, while it will give invalid (undefined) results on others. So similarly to the issue with reduced precision in normalize/length operations in GLSL, this is a thing to be careful with when coding your shaders in HLSL using new Shader Model 5.1.

Comments | #directx Share

# Adventures with Porting Code to Visual Studio 2015 and No DirectX SDK

22:40
Sat
08
Aug 2015

I just installed new Visual Studio 2015 Community Edition and ported my personal project to it. At the same time, I uninstalled old DirectX SDK Jun 2010 and started using new DirectX headers bundled with Windows SDK, which is installed together with Visual Studio. These two transitions are not connected - I could already switch to new DX headers years ago, but I decided to do it now. While transition to VS 2015 was smooth, abandoning DirectX SDK caused some problems, because new DirectX doesn't contain D3DX library. Here is a dump of the problems and solutions that I encountered during this effort:

1. I uninstalled DirectX SDK Jun 2010, Visual Studio 2013 Community Edition and all other components that seemed related to it, like Microsoft SQL. I left all "Microsoft Visual C++ XX Redistributable" though, because these are required by many applications and intended to be installed on target machine, not necessarily as a part of development environment.

Next, I downloaded and installed new Visual Studio 2015 Community Edition. During this long process, I was thinking what should I expect from the new IDE... Whether Microsoft did a good job this time? On one hand, it is suprising that C++ is now an optional installation component, so it seems like native code is in shadow comparing to all these new and trendy cloud/web/mobile/managed technologies. On the other hand, table: C++11/14/17 Features In VS 2015 RTM shows that the new C++ compiler caught up with many features of new C++11/14/17 language, which gives hope that authors still treat native code development seriously.

2. The looks of new IDE is so similar to the previous version it is hard to notice any differences. After launching it, I had to first recompile static libraries that my project depends on. That was zlib 1.2.8 and my CommonLib. Converting project to new version, as well as the build itself went smoothly, without any problems - which is unusual with C/C++ libraries :) Just as in previous version, headers and libs of standard C library, standard C++ library (STL) and WinAPI are already bundled with the Visual Studio, so there is no need to install or configure anything additional before you can use them.

Read full entry > | Comments | #visual studio #directx #c++ Share

# Lower-Level Graphics API - What Does It Mean?

06:51
Sat
06
Jun 2015

They say that the new, upcoming generation of graphics API-s (like DirectX 12 and Vulkan) will be lower-level, closer to the GPU. You may wonder what does it exactly mean or what is the purpose of it? Let me explain that with a picture that I have made few months ago and already shown on my two presentations.

Row 1: Back in the early days of computer graphics (like on Atari, Commodore 64), there were only applications (green rectangle), communicating directly with graphics hardware (e.g. by setting hardware registers).

Row 2: Hardware and software became more complicated. Operating systems started to separate applications from direct access to hardware. To make applications working on variety of devices available on the market, some standards had to be defined. Device drivers appeared as a separate layer (red rectangle).

Graphics API (Application Programming Interface), like every interface, is just the means of communication - standardized, documented definition of functions and other stuff that is used on the application's side and implemented by the driver. Driver translates these calls to commands specific to particular hardware.

Row 3: As games became more complex, it was no longer convenient to call graphics API directly from game logic code. Another layer appeared, called game engine (yellow rectangle). It is essentially a comprehensive library that provides some higher-level objects (like an entity, asset, material, camera, light) and implements them (in its graphical part) using lower-level commands of graphics API (like mesh, texture, shader).

Row 4: This is where we are now. Games, as well as game engines constantly become more complex and expensive to make. Less and less game development studios make their own engine technology, more prefer to use existing, universal engines (like Unity, Unreal Engine) and just focus on gameplay. These engines recently became available for free and on very attractive licenses, so this trend affects both AAA, as well as indie and amateur game developers.

Graphics drivers became incredibly complex programs as well. You may not see it directly, but just take a look at the size of their installers. They are not games - they don't contain tons of graphics and music assets. So guess what is inside? That is a lot of code! They have to implement all API-s (DirectX 9, 10, 11, OpenGL). In addition to that, these API-s have to backward compatible and not necessarily reflect how modern GPU-s work, so additional logic needed for that can introduce some performance overhead or contain some bugs.

Row 5: The future, with new generation of graphics API-s. Note that the sum width of the bars is not smaller than in the previous row. (Maybe it should be a bit smaller - see comment below.) That is because according to the concept of accidental complexity and essential complexity from famous book No Silver Bullet, stuff that is really necessary has to be done somewhere anyway. So lower-level API means just that driver could be smaller and simpler, while upper layers will have more responsibility of manually managing stuff instead of automatic facilities provided by the driver (for example, there is no more DISCARD or NOOVERWRITE flag when mapping a resource in DirectX 12). It also means API is again closer to the actual hardware. Thanks to all that, the usage of GPU can be optimized better by knowing all higher-level details about specific application on the engine level.

Question is: Will that make graphics programming more difficult? Yes, it will, but these days it will affect mostly a small group of programmers working directly on game engines or just passionate about this stuff (like myself) and not the rest of game developers. Similarly, there may be a concern about potential fragmentation. Time will show which API-s will be more successful than the others, but in case none of them will become standard across all platforms (Vulkan is a good candidate) and GPU/OS vendors succeed in convincing developers to use their platform-specific ones, it will also complicate life only for these engine developers. Successful games have to be multiplatform anyway and modern game engines do good job in hiding many of differences between platforms, so they can do the same with graphics.

Comments | #gpu #rendering #directx Share

# DirectX 12: What We Already Know?

20:09
Wed
03
Jun 2015

I am very excited about the upcoming DirectX 12. I have always been standing on the side of PC, Windows and DirectX. Currently I code in DirectX 11 on Windows 7 at home. Upcoming Windows 10 with free upgrade from version 7 and 8 (and the Start menu back on its place) looks like a good system. Together with it, a new version of DirectX will be released. Let us summarize general information about this new graphics API that are publicly available at the moment.

Here are some interesting links:

First and foremost: Direct3D 12 Graphics @ msdn.microsoft.com. Microsoft says "these information relate to pre-released product and may be substantially modified before it's commercially released", but you can already find there all Direct3D 12 Programming Guide and Reference, so basically the whole API is already public and you can start learning it.

Social Media:

General information:

Slides and videos from conferences:

Videos and screenshots from some working applications already shown:

Comments | #windows #directx Share

# Nothing Renders - Why?

00:17
Sun
24
May 2015

"I have a blank screen" or "nothing is rendered" is probably the most frequent bug in graphics programming. It's also quite hard to debug because there are many possible causes. Graphics pipeline is compilated, so there are multiple things that can be wrong at each stage. Few years ago I've written a short article about this, in Polish, titled Nic nie widaŠ. This is translation of that article. It provides a list of questions you should ask yourself while considering the most frequent reasons for why nothing appears on the screen. It is dedicated for Direct3D 9, but it can also be applied to OpenGL (only some things are named differently) and, to some degree, to newer graphics API-s.

It's black

First of all, please clear your background to some color other than black, e.g. gray or blue. Maybe your geometry is rendered, but it is black. It is a frequent bug, especially if you have lighting enabled (and it is enabled by default) while you didn't setup any lights.

Matrices

Are you sure you correctly setup all matrices - world, view and projection? Did you create them using correct functions? Is the camera located in the right place and looks in the desired direction? Maybe your object is in the same position as camera or behind the camera, which is pointing backward?

Position

Is the size and position of your object correct? Is your object too close or too far from the camera, relative to the minimum and maximum Z value set in projection matrix? Isn't it too small to be visible?

Errors

Do all the calls to DirectX functions return a value meaning success? Do you even check that value? Please also launch "DirectX Control Panel", enable Debug Layer for your application and analyze Output for any error or warning messages.

Vertex Format

Do you use correct vertex format? Did you define a structure describing your vertex correctly and compatible with the FVF/vertex declaration that you use? Are all the fields in the correct order and of the right type? Do you tell DirectX what vertex format you want to use by calling SetFVF/SetVertexDeclaration before rendering?

Draw Call

Do you pass correct parameters to the rendering function? In the most basic case, all offsets should be 0 and "stride" is the size of your vertex structure, in bytes, like sizeof(SMyVertex). Do you pass correct number of primitives to render?

Buffers

Do you fill your vertex and (optional) index buffer correctly? Do they have correct number of elements? Do you fill all of them? If you use transformed coordinates XYZRHW, the RHW component should be set to 1.0 and never to 0.0.

Alpha Channel

Maybe your geometry is totally transparent. Is the alpha channel set to maxium (1.0 or 0xFF, depending on type) and not to minimum in all of these: vertices, texture, material (only if you use lighting)?

Backface Culling

Maybe the triangles you want to render are ignored as "back facing" the camera, because they have wrong winding (clockwise or counterclockwise)? Try to disable backface culling to check that.

States

Did you setup blending on all texture stages correctly? Did you correctly setup all rest of the states of graphics pipeline? Maybe the problem appears only when you render some objects in a specific order? That means states set before rendering one object remain in the pipeline and break rendering of the next one.

Advanced Effects

If you use some advanced rendering features, your graphics card may not support them. Set reference software rasterizer during creation of the device object (D3DDEVTYPE_REF instead of HAL). Your program will run very slowly, but everything should be drawn as expected. Query device object for capabilities of your GPU (device caps).

Z-Buffer

If you use depth buffer, remember to clear it as well, together with backbuffer. In 3rd parameter of Clear function bitwise OR following flag: D3DCLEAR_ZBUFFER. Without it, you won't see anything on the screen or you will see artifacts. Value to clear Z-buffer to is 1.0f (not 0.0f).

Finally, there are ways you can actually debug how data and state look like on subsequent stages of the graphics pipeline while this bugged draw call is executed, using Graphics Diagnostics in Visual Sudio or other GPU debugging tool.

See also: How not to render 3D graphics: 40 ways to get a blank black screen

Comments | #directx #rendering Share

# DirectX 11 CheatSheet

21:02
Fri
29
Aug 2014

I've created several cheatsheets: about DXGI Formats, XNA Math, floats, color names in .NET and Direct3D 9. You can see it in Download/Misc. Today I discovered that I didn't publish my DirectX 11 CheatSheet that I've prepared 3 years ago! So here it is:

DirectX_11_CheatSheet.docx
DirectX_11_CheatSheet.pdf

On 15 pages, you will find:

Comments | #directx Share

Pages: 1 2 3 ... 8 >

STAT NO AD
[Stat] [STAT NO AD] [Download] [Dropbox] [pub] [Mirror]
Copyright © 2004-2017