Direct Compute up/down scaling

Started by
1 comment, last by JulienLebot 12 years, 4 months ago
Hello everyone,

I was wondering how would one go about taking a non-power of two texture and using a compute shader, re-scale it either up or down to the nearest power of two.
I know how to get the nearest power of two, and I know how to initialize DirectX 11 and create the required shaders; however I have never used the compute features of DX11.

I'm not sure what happens when I create my texture (using D3DX11CreateTextureFromFile) with a non-power of 2 texture ? I think it ends up padding the texture which undesirable.
Or should I just create a structured buffer, store all the pixels in there and make an unordered access view of that ? But then I need to figure out how to assign the threads as I cannot split a few pixels in half.

The application has to typically process GB worth of textures, hence why I'm going for Direct Compute.

Any ideas ?
Advertisement
By default, D3DX11CreateTextureFromFile will not rescale the image when creating the texture. The top mip level will have the same dimensions as your image file.

For your compute shader, you'll want one thread per output texel. Each thread can then take any necessary samples from the input texture, and output the scaled texel value to a RWTexture2D. Since you can only dispatch groups of threads, you may end up with more threads than you need. To handle this, you can either do nothing (writes to invalid texel addresses will get ignored) or you can use an if statement to check if the texel address is valid. If you only want linear filtering then your shader can be dead simple:

// Inputs
Texture2D<float4> InputTexture : register(t0);

// Outputs
RWTexture2D<float2> OutputTexture : register(u0);

// Samplers
SamplerState LinearSampler : register(s0);

// Entry point
[numthreads(TGSize_, TGSize_, 1)]
void Rescale(uint3 GroupID : SV_GroupID, uint3 DispatchThreadID : SV_DispatchThreadID,
uint3 GroupThreadID : SV_GroupThreadID, uint GroupIndex : SV_GroupIndex)
{
uint2 samplePos = GroupID.xy * uint2(TGSize_, TGSize_) + GroupThreadID.xy;

uint2 textureSize;
OutputTexture.GetDimensions(textureSize.x, textureSize.y);

[branch]
if(samplePos.x < textureSize.x && samplePos.y < textureSize.y)
{
float2 uv = (samplePos + 0.5f) / textureSize;
OutputTexture[samplePos] = InputTexture(LinearSampler, uv);
}
}
Thank you MJP for this precise and concise answer.
The entire point of using compute shaders is to use much better scaling algorithm, but I can easily do that once I get the linear filtering going.

Hopefully your book "[font=Arial, Helvetica, sans-serif][size=2]Practical Rendering and Computation with Direct3D 11" will arrive soon and I'll be able to learn much more about Direct3D 11 :)[/font]

This topic is closed to new replies.

Advertisement