Advertisement

Scale Texture2D DirectX11

Started by May 23, 2017 05:20 PM
4 comments, last by DevAndroid 7 years, 8 months ago

I'm using Desktop Duplication API. After I call AcquireNextFrame I get a Texture2D from the API in Full HD resolution. I would like to resize it and make it smaller (like 1280x720 for example) before drawing it. Here is my code :


if (texture2D != NULL)
{
    D3D11_TEXTURE2D_DESC description;
    texture2D->GetDesc(&description);
    description.BindFlags = 0;
    description.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    description.Usage = D3D11_USAGE_STAGING;
    description.MiscFlags = 0;
    description.Width = 1280;
    description.Height = 720;

    ID3D11Texture2D *texTemp = NULL;
    HRESULT hr = m_Device->CreateTexture2D(&description, NULL, &texTemp);
    if (FAILED(hr))
    {
        if (texTemp)
        {
            texTemp->Release();
            texTemp = NULL;
        }
        return NULL;
    }
    m_DeviceContext->CopyResource(texTemp, texture2D);

    D3D11_MAPPED_SUBRESOURCE mapped;
    hr = m_DeviceContext->Map(texTemp, 0, D3D11_MAP_READ, 0, &mapped);
    if (FAILED(hr))
    {
        texTemp->Release();
        texTemp = NULL;
        return NULL;
    }
    unsigned char *source = static_cast<unsigned char*>(mapped.pData);
    //here the source has no values. If I remove description.Width = 1280;
    //description.Height = 720; I get values
}

Can someone help ? Thanks

I'm using Desktop Duplication API. After I call AcquireNextFrame I get a Texture2D from the API in Full HD resolution. I would like to resize it and make it smaller (like 1280x720 for example) before drawing it. Here is my code :


if (texture2D != NULL)
{
    D3D11_TEXTURE2D_DESC description;
    texture2D->GetDesc(&description);
    description.BindFlags = 0;
    description.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
    description.Usage = D3D11_USAGE_STAGING;
    description.MiscFlags = 0;
    description.Width = 1280;
    description.Height = 720;

    ID3D11Texture2D *texTemp = NULL;
    HRESULT hr = m_Device->CreateTexture2D(&description, NULL, &texTemp);
    if (FAILED(hr))
    {
        if (texTemp)
        {
            texTemp->Release();
            texTemp = NULL;
        }
        return NULL;
    }
    m_DeviceContext->CopyResource(texTemp, texture2D);

    D3D11_MAPPED_SUBRESOURCE mapped;
    hr = m_DeviceContext->Map(texTemp, 0, D3D11_MAP_READ, 0, &mapped);
    if (FAILED(hr))
    {
        texTemp->Release();
        texTemp = NULL;
        return NULL;
    }
    unsigned char *source = static_cast<unsigned char*>(mapped.pData);
    //here the source has no values. If I remove description.Width = 1280;
    //description.Height = 720; I get values
}

Can someone help ? Thanks

You can create a SRV for the source image from your Desktop API to bind the texture for a shader.

Then use your smaller target texture as rendertarget and draw a fullscreen quad on it. You don't even need a index or vertexbuffer when using this vertexshader


struct Output
{
	float4 position_cs : SV_POSITION;
	float2 texcoord : TEXCOORD;
};

Output main(uint id: SV_VertexID)
{
	Output output;

	output.texcoord = float2((id << 1) & 2, id & 2);
	output.position_cs = float4(output.texcoord * float2(2, -2) + float2(-1, 1), 0, 1);

	return output;
}

You only have to use Draw(3,0);

The pixelshader is also a no brainer, just sample the sourcetexture and you are done.

Advertisement

Hello Auskennfuchs

I was mistaken in what I wanted to do.

​I don't want to draw it on a DirectX Surface. I would like to get the buffer of pixels smaller directly from DirectX.

As you can see in my code I'm copying the Texture2D obtained from AcquireNextFrame to a staging temporary texture to get the pixel buffer data.

I would like to scale the pixel buffer data because I need to send a frame over network and I would like to decrease the resolution.

Thank you very much

I'm not sure if you can achieve it by just copying the data to a texture with a smaller dimension. I guess your current result looks something like this:


original image
aaaaaa
bbbbbb
cccccc

smaller image
aaaa
aabb
bbbb

last line is completely missing

So with my solution the scaling is done in the pixelshader, like if you look on a quad from a further distance in 3D. After drawing on the smaller destination texture you can use the Map function to read the smaller image.

As an alternative you can use GDI+ functions to scale a bitmap and don't have to deal with DirectX.

If you need it in say, half size it's quite easy:

1) Map your source, and memcpy the data to a buffer you've allocated, and unmap

2) loop through the buffer with a xy stepsize of 2, copying data into a half-sized buffer

Edit: Will have to say I would definitely go for the shader approach, much faster ^^

.:vinterberg:.

Hello Auskennfuchs

Sorry for the late response...

Thank you for your help. But I think I need more explanation how to use correctly the pixel shader you gave me from my code I show at top.

How to pass the texture2D acquired to the shader with a custom resolution and then grab it again and get the buffer ?

I created a PixelShader.hlsl where I put this code :


struct Output
{
	float4 position_cs : SV_POSITION;
	float2 texcoord : TEXCOORD;
};

[numthreads(1, 1, 1)]
Output main(uint id: SV_VertexID)
{
	Output output;

	output.texcoord = float2((id << 1) & 2, id & 2);
	output.position_cs = float4(output.texcoord * float2(2, -2) + float2(-1, 1), 0, 1);

	return output;
}

I got an error on compilation : Error X3507 'main': Compute shaders can't return values, outputs must be written in writable resources (UAVs)

Thank you!

This topic is closed to new replies.

Advertisement