Изменить IDirect3DSurface9 * с помощью шейдера

Я получил IDirect3DSurface9 * от видеодекодера DXVA2. Я хотел бы изменить эту поверхность с помощью шейдера. Я могу рендерить видеокадры без шейдеров, «рисуя» поверхность в заднем буфере.
Я использую следующий код для рендеринга кадров без шейдера:

void Draw(Example* exps){

IDirect3DSurface9* backbuffer;
hwctx->d3d9device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
hwctx->d3d9device->BeginScene();
hwctx->swap_chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);

hwctx->d3d9device->StretchRect(videoSurface, NULL, backbuffer, NULL, D3DTEXF_LINEAR);

hwctx->d3d9device->EndScene();
hwctx->swap_chain->Present(0, 0, 0, 0, 0);
backbuffer->Release();
}

До тех пор, пока здесь, все работает.
Я бы изменил функцию Draw для рендеринга видеокадров с помощью следующего шейдера:

uniform extern float4x4 gWVP;
uniform extern texture  gTexRGB;
uniform extern texture  gTexAlpha;

sampler TexRGB = sampler_state
{
Texture = <gTexRGB>;
AddressU  = WRAP;
AddressV  = WRAP;
};

sampler TexAlpha = sampler_state
{
Texture = <gTexAlpha>;
AddressU = WRAP;
AddressV = WRAP;
};

struct OutputVS
{
float4 posH    : POSITION0;
float2 tex0    : TEXCOORD0;
};

OutputVS DirLightTexVS(float3 posL : POSITION0, float3 normalL : NORMAL0, float2 tex0: TEXCOORD0)
{
// Zero out our output.
OutputVS outVS = (OutputVS)0;

// Transform to homogeneous clip space.
outVS.posH = mul(float4(posL, 1.0f), gWVP);

// Pass on texture coordinates to be interpolated in rasterization.
outVS.tex0 = tex0;

// Done--return the output.
return outVS;
}

float4 DirLightTexPS(float4 c : COLOR0, float4 spec : COLOR1, float2 tex0 : TEXCOORD0) : COLOR
{
float3  rgb = tex2D(TexRGB, tex0).rgb;
float   alpha = tex2D(TexAlpha, tex0).g;
return float4(rgb, alpha);
}

technique DirLightTexTech
{
pass P0
{
// Specify the vertex and pixel shader associated with this pass.
vertexShader = compile vs_2_0 DirLightTexVS();
pixelShader  = compile ps_2_0 DirLightTexPS();

}
}

где TexRGB — это текстура, связанная с видеокадром, а TexAlpha — это другая текстура, которая содержит альфа-значения.
Как передать декодированную поверхность шейдеру? Я никогда не использовал Directx9, поэтому пример ценен и может помочь мне решить проблему.

ОБНОВЛЕНИЕ 1:
Я создал функцию InitEffect для загрузки эффекта из файла

void InitEffect(Example* ctx) {
auto hwctx = ctx->decoder->stream->HWAccelCtx;

// Create the FX from a .fx file.
ID3DXBuffer* errors = 0;
D3DXCreateEffectFromFile(hwctx->d3d9device, "basicEffect.fx", 0, 0, D3DXSHADER_DEBUG, 0, &ctx->mFX, &errors);

if (errors)
MessageBox(0, (LPCSTR)errors->GetBufferPointer(), 0, 0);

// Obtain handles.
ctx->mhTech = ctx->mFX->GetTechniqueByName("DirLightTexTech");
ctx->mhWVP = ctx->mFX->GetParameterByName(0, "gWVP");
ctx->mhTexAlpha = ctx->mFX->GetParameterByName(0, "gTexAlpha");
ctx->mhTexRGB = ctx->mFX->GetParameterByName(0, "gTexRGB");
}

и изменил функцию рендеринга на:

void Draw(Example* ctx) {
InitMatrices(ctx);

IDirect3DSurface9* backbuffer;

hwctx->d3d9device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffeeeeee, 1.0f, 0);
hwctx->d3d9device->BeginScene();

ctx->mFX->SetTechnique(ctx->mhTech);
ctx->mFX->SetMatrix(ctx->mhWVP, &(ctx->mCrateWorld*ctx->mView*ctx->mProj));

ctx->texRGB->GetSurfaceLevel(0, &ctx->surfRGB);
hwctx->d3d9device->SetRenderTarget(0, ctx->surfRGB);
hwctx->d3d9device->StretchRect((IDirect3DSurface9*)s->frame->data[3], NULL, ctx->surfRGB, NULL, D3DTEXF_LINEAR);

ctx->mFX->SetTexture(ctx->mhTexAlpha, ctx->texAlpha);
ctx->mFX->SetTexture(ctx->mhTexRGB, ctx->texRGB);

// Enable alpha blending.
hwctx->d3d9device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
hwctx->d3d9device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
hwctx->d3d9device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

hwctx->d3d9device->SetVertexDeclaration(VertexPNT::Decl);
hwctx->d3d9device->SetStreamSource(0, ctx->mBoxVB, 0, sizeof(VertexPNT));
hwctx->d3d9device->SetIndices(ctx->mBoxIB);

UINT numPasses = 0;
ctx->mFX->Begin(&numPasses, 0);
for (UINT i = 0; i < numPasses; ++i){
ctx->mFX->BeginPass(i);
hwctx->d3d9device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12);
ctx->mFX->EndPass();
}
ctx->mFX->End();

hwctx->d3d9device->EndScene();
hwctx->swap_chain->Present(0, 0, 0, 0, 0);

backbuffer->Release();

// Disable alpha blending.
hwctx->d3d9device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
}

но это все еще не работает.

ОБНОВЛЕНИЕ 2
Я изменил код, следуя коду Ашеша. В функцию InitEffect я добавил следующие строки для создания целевой поверхности рендеринга:

ctx->texRGB->GetSurfaceLevel(0, &ctx->surfRGB);
// store orginal rendertarget
hwctx->d3d9device->GetRenderTarget(0, &ctx->origTarget_);
D3DSURFACE_DESC desc;
ctx->origTarget_->GetDesc(&desc);

// create our surface as render target
hwctx->d3d9device->CreateRenderTarget(1920, 1080, D3DFMT_X8R8G8B8,
desc.MultiSampleType, desc.MultiSampleQuality,
false, &ctx->surfRGB, NULL);

функция рисования:

void drawScene(Example* ctx) {
InitMatrices(ctx);

auto hwctx = ctx->decoder->stream->HWAccelCtx;
auto s = (VdrStreamContext*)ctx->decoder->stream->vdrCodecCtx->opaque;

IDirect3DSurface9* backbuffer;
hwctx->d3d9device->SetRenderTarget(0, ctx->surfRGB);
hwctx->d3d9device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffeeeeee, 1.0f, 0);
hwctx->d3d9device->BeginScene();hwctx->d3d9device->StretchRect((IDirect3DSurface9*)s->vdrFrame->data[3], NULL, ctx->surfRGB, NULL, D3DTEXF_NONE);
hwctx->d3d9device->SetRenderTarget(0, ctx->origTarget_);

if (!hwctx->d3d9device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer)) {
hwctx->d3d9device->StretchRect(ctx->surfRGB, NULL, backbuffer, NULL, D3DTEXF_NONE);
}

ctx->mFX->SetTechnique(ctx->mhTech);
ctx->mFX->SetMatrix(ctx->mhWVP, &(ctx->mCrateWorld*ctx->mView*ctx->mProj));

ctx->mFX->SetTexture(ctx->mhTexAlpha, ctx->texAlpha);
ctx->mFX->SetTexture(ctx->mhTexRGB, ctx->texRGB);

// Enable alpha blending.
hwctx->d3d9device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
hwctx->d3d9device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
hwctx->d3d9device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

hwctx->d3d9device->SetVertexDeclaration(VertexPNT::Decl);
hwctx->d3d9device->SetStreamSource(0, ctx->mBoxVB, 0, sizeof(VertexPNT));
hwctx->d3d9device->SetIndices(ctx->mBoxIB);

UINT numPasses = 0;
ctx->mFX->Begin(&numPasses, 0);
for (UINT i = 0; i < numPasses; ++i){
ctx->mFX->BeginPass(i);
hwctx->d3d9device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12);
ctx->mFX->EndPass();
}

ctx->mFX->End();

hwctx->d3d9device->EndScene();
hwctx->d3d9device->Present(0, 0, 0, 0);

backbuffer->Release();

// Disable alpha blending.
hwctx->d3d9device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
}

рисуя в буферном hwctx-> d3d9device-> StretchRect (ctx-> surfRGB, NULL, backbuffer, NULL, D3DTEXF_NONE); даже если ctx-> surfRGB связан с текстурой, передаваемой шейдеру, видеокадр отображается на экране, но альфа-смешение не применяется. Если я удалю hwctx-> d3d9device-> StretchRect (ctx-> surfRGB, NULL, backbuffer, NULL, D3DTEXF_NONE); видеокадр не отображается, даже если ctx-> surfRGB не пуст.

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]