Let's say I have some shader program in DirectX or OpenGL rendering a full screen quad. And in a pixel/fragment shader I sample some huge textures at random texture coordinates. That is one same texture coordinate for all texture samplings in one shader invocation, but it is various among different shader invocations. These fetch operations produce performance drop, I even think that due to the size of the textures the GPU texture cache is not big enough and is used not efficiently.

Now I have a theoretical question: can I optimize the performance by using some low-resolution like 32x32 mask textures, which are built by mipmapping the large textures, and if a value in a mask texture at given texture coordinate at some higher mip level is not appropriate, then I don't need to perform texture fetches at full-size level 0? Something like this in HLSL (GLSL code is pretty similar, but there is no [branch] attribute):

float2 tc = calculateTexCoordinates();
bool performHeavyComputations = testValue(largeMipmappedTexture.SampleLevel(sampler, tc, 5));

float result = 0;

if (performHeavyComputations)
    result += largeMipmappedTexture.SampleLevel(sampler, tc, 0);

About 50% of texels at mip level 5 will not pass the test. And so a lot of shader invocations should not sample the full-size textures.

But I am introducing branching in the code. May this branching hurt the performance even worse than sampling the full-size texture even if that is not needed? Different GPUs may behave differently, some may not even support branching, will they perform two fetches instead of one?

I can test this code on some machines, but my question is theoretical.

And can you suggest another optimizations, if this won't work properly ?

  • \$\begingroup\$ The very best way to find if this branch is worthwhile is to try it and profile the result. We don't have enough details of what your real shader is doing to make a more comprehensive answer at the moment. \$\endgroup\$ – DMGregory Nov 16 '19 at 20:26
  • \$\begingroup\$ I will run some test on Monday, but results on a couple of machines may be very specific. There are big spatial coherent areas in the large texture, so we can say that a lot of texture samples may be early discarded just looking at the higher mip levels. The question is, may branching save performance or will it hurt it even more. \$\endgroup\$ – Emil Kabirov Nov 16 '19 at 20:51
  • \$\begingroup\$ "results on a couple of machines may be very specific" - yep, that's exactly the issue. It's often hard to say categorically "branching or sampling is more costly" because it depends on the hardware, as well as the specific workload in your context. Your solution might be faster for all NVIDIA cards but slower for AMD cards or vice versa, or faster in synthetic tests but slower when used in the context of your scene's whole rendering workload - stuff we can't easily predict from the summary above. \$\endgroup\$ – DMGregory Nov 16 '19 at 20:55
  • \$\begingroup\$ Thank's for your opinion. I can actually say for extra info, that we talk about big reflection texture. And the fragments which sample the reflection texture are the fragments of the sea. So sea waves reflect very random texels of the texture. However we need to perform some extra computations if the reflected texel is not the sky. Which is determined by sampling the reflection depth buffer. The reflection texture is already smaller than the screen size, but it is still big, especially at 4K screens. \$\endgroup\$ – Emil Kabirov Nov 16 '19 at 21:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.