[host] DXGI: initial implementation of RGB24 support

This commit breaks damage tracking and the dx12 backend and is not in
a state where it should be used by the general public.
This commit is contained in:
Geoffrey McRae
2023-10-30 08:42:08 +11:00
parent b3879ff1d7
commit 578d98fd22
16 changed files with 559 additions and 232 deletions

View File

@@ -10,6 +10,7 @@ add_library(capture_DXGI STATIC
src/com_ref.c
src/pp/sdrwhitelevel.c
src/pp/rgb24.c
)
add_definitions("-DCOBJMACROS -DINITGUID")

View File

@@ -35,9 +35,7 @@ struct D3D11Backend
struct D3D11TexImpl
{
ID3D11Texture2D ** gpu;
ID3D11Texture2D ** cpu;
ID3D11ShaderResourceView ** srv;
ID3D11Texture2D ** cpu;
};
#define TEXIMPL(x) ((struct D3D11TexImpl *)(x).impl)
@@ -49,7 +47,6 @@ static void d3d11_free(void);
static bool d3d11_create(struct DXGIInterface * intf)
{
HRESULT status;
dxgi = intf;
DEBUG_ASSERT(!this);
@@ -61,32 +58,24 @@ static bool d3d11_create(struct DXGIInterface * intf)
}
this->avgMapTime = runningavg_new(10);
return true;
}
D3D11_TEXTURE2D_DESC gpuTexDesc =
{
.Width = dxgi->width,
.Height = dxgi->height,
.MipLevels = dxgi->downsampleLevel + 1,
.ArraySize = 1,
.SampleDesc.Count = 1,
.SampleDesc.Quality = 0,
.Usage = D3D11_USAGE_DEFAULT,
.Format = dxgi->dxgiFormat,
.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE,
.CPUAccessFlags = 0,
.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS
};
static bool d3d11_configure(unsigned width, unsigned height, DXGI_FORMAT format,
unsigned * pitch)
{
HRESULT status;
D3D11_TEXTURE2D_DESC cpuTexDesc =
{
.Width = dxgi->targetWidth,
.Height = dxgi->targetHeight,
.Width = width,
.Height = height,
.MipLevels = 1,
.ArraySize = 1,
.SampleDesc.Count = 1,
.SampleDesc.Quality = 0,
.Usage = D3D11_USAGE_STAGING,
.Format = dxgi->dxgiFormat,
.Format = format,
.BindFlags = 0,
.CPUAccessFlags = D3D11_CPU_ACCESS_READ,
.MiscFlags = 0
@@ -111,22 +100,6 @@ static bool d3d11_create(struct DXGIInterface * intf)
DEBUG_WINERROR("Failed to create CPU texture", status);
goto fail;
}
if (!dxgi->downsampleLevel)
continue;
status = ID3D11Device_CreateTexture2D(*dxgi->device, &gpuTexDesc, NULL,
(ID3D11Texture2D **)comRef_newGlobal(&teximpl->gpu));
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create GPU texture", status);
goto fail;
}
ID3D11Device_CreateShaderResourceView(*dxgi->device,
*(ID3D11Resource **)teximpl->gpu, NULL,
(ID3D11ShaderResourceView **)comRef_newGlobal(&teximpl->srv));
}
// map the texture simply to get the pitch and stride
@@ -141,16 +114,13 @@ static bool d3d11_create(struct DXGIInterface * intf)
goto fail;
}
dxgi->pitch = mapping.RowPitch;
dxgi->stride = mapping.RowPitch / dxgi->bpp;
ID3D11DeviceContext_Unmap(*dxgi->deviceContext,
*(ID3D11Resource **)TEXIMPL(dxgi->texture[0])->cpu, 0);
*pitch = mapping.RowPitch;
return true;
fail:
d3d11_free();
return false;
}
@@ -199,76 +169,12 @@ static void copyFrameFull(Texture * tex, ID3D11Texture2D * src)
}
}
static void copyFrameDownsampled(Texture * tex, ID3D11Texture2D * src)
{
struct D3D11TexImpl * teximpl = TEXIMPL(*tex);
ID3D11Texture2D * dst = *teximpl->gpu;
if (tex->texDamageCount < 0)
ID3D11DeviceContext_ResolveSubresource(*dxgi->deviceContext,
(ID3D11Resource *)dst, 0,
(ID3D11Resource *)src, 0,
dxgi->dxgiFormat);
else
{
for (int i = 0; i < tex->texDamageCount; ++i)
{
FrameDamageRect * rect = tex->texDamageRects + i;
D3D11_BOX box =
{
.left = rect->x << dxgi->downsampleLevel,
.top = rect->y << dxgi->downsampleLevel,
.front = 0,
.back = 1,
.right = (rect->x + rect->width ) << dxgi->downsampleLevel,
.bottom = (rect->y + rect->height) << dxgi->downsampleLevel,
};
ID3D11DeviceContext_CopySubresourceRegion(*dxgi->deviceContext,
(ID3D11Resource *)dst, 0, box.left, box.top, 0,
(ID3D11Resource *)src, 0, &box);
}
}
ID3D11DeviceContext_GenerateMips(*dxgi->deviceContext, *teximpl->srv);
if (tex->texDamageCount < 0)
ID3D11DeviceContext_CopySubresourceRegion(*dxgi->deviceContext,
*(ID3D11Resource **)teximpl->cpu, 0, 0, 0, 0,
(ID3D11Resource * )dst , dxgi->downsampleLevel, NULL);
else
{
for (int i = 0; i < tex->texDamageCount; ++i)
{
FrameDamageRect * rect = tex->texDamageRects + i;
D3D11_BOX box =
{
.left = rect->x,
.top = rect->y,
.front = 0,
.back = 1,
.right = rect->x + rect->width ,
.bottom = rect->y + rect->height,
};
ID3D11DeviceContext_CopySubresourceRegion(*dxgi->deviceContext,
*(ID3D11Resource **)teximpl->cpu, 0, box.left, box.top, 0,
(ID3D11Resource * )dst , dxgi->downsampleLevel, &box);
}
}
}
static bool d3d11_copyFrame(Texture * tex, ID3D11Texture2D * src)
{
struct D3D11TexImpl * teximpl = TEXIMPL(*tex);
INTERLOCKED_SECTION(dxgi->deviceContextLock,
{
tex->copyTime = microtime();
if (teximpl->gpu && *teximpl->gpu)
copyFrameDownsampled(tex, src);
else
copyFrameFull(tex, src);
copyFrameFull(tex, src);
ID3D11DeviceContext_Flush(*dxgi->deviceContext);
});
return true;
@@ -339,6 +245,7 @@ struct DXGICopyBackend copyBackendD3D11 = {
.name = "Direct3D 11",
.code = "d3d11",
.create = d3d11_create,
.configure = d3d11_configure,
.free = d3d11_free,
.copyFrame = d3d11_copyFrame,
.mapTexture = d3d11_mapTexture,

View File

@@ -95,8 +95,8 @@ static bool d3d12_create(struct DXGIInterface * intf)
{
DEBUG_WARN("The D3D12 backend does not support downsampling yet");
dxgi->downsampleLevel = 0;
dxgi->targetWidth = dxgi->width;
dxgi->targetHeight = dxgi->height;
dxgi->outputWidth = dxgi->width;
dxgi->outputHeight = dxgi->height;
}
if (dxgi->debug)

View File

@@ -51,6 +51,7 @@
//post processers
extern const DXGIPostProcess DXGIPP_SDRWhiteLevel;
extern const DXGIPostProcess DXGIPP_RGB24;
typedef struct
{
@@ -58,6 +59,9 @@ typedef struct
ID3D11ShaderResourceView * srv;
const DXGIPostProcess * pp;
void * opaque;
bool configured;
int rows, cols;
}
PostProcessInstance;
@@ -89,7 +93,10 @@ static bool dxgi_deinit(void);
static CaptureResult dxgi_releaseFrame(void);
static bool ppInit(const DXGIPostProcess * pp, bool shareable);
static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src);
static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src,
int * width, int * height,
int * rows , int * cols,
CaptureFormat * format);
static void ppFreeAll(void);
// implementation
@@ -301,7 +308,7 @@ static bool initVertexShader(void)
// compile and create the vertex shader
comRef_defineLocal(ID3DBlob, byteCode);
if (!compileShader(byteCode, "main", "vs_5_0", vshaderSrc))
if (!compileShader(byteCode, "main", "vs_5_0", vshaderSrc, NULL))
return false;
comRef_defineLocal(ID3D11VertexShader, vshader);
@@ -530,7 +537,8 @@ static bool dxgi_init(void)
*tmp,
D3D_DRIVER_TYPE_UNKNOWN,
NULL,
D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
D3D11_CREATE_DEVICE_VIDEO_SUPPORT |
(this->debug ? D3D11_CREATE_DEVICE_DEBUG : 0),
featureLevels, featureLevelCount,
D3D11_SDK_VERSION,
(ID3D11Device **)comRef_newGlobal(&this->device),
@@ -729,7 +737,7 @@ static bool dxgi_init(void)
this->hdr = this->dxgiColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
}
this->bpp = 4;
// set the initial format
switch(this->dxgiFormat)
{
case DXGI_FORMAT_B8G8R8A8_UNORM:
@@ -740,10 +748,12 @@ static bool dxgi_init(void)
this->format = CAPTURE_FMT_RGBA;
break;
// we convert to HDR10 to save bandwidth
case DXGI_FORMAT_R10G10B10A2_UNORM:
this->format = CAPTURE_FMT_RGBA10;
break;
case DXGI_FORMAT_R16G16B16A16_FLOAT:
this->dxgiFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
this->format = CAPTURE_FMT_RGBA10;
this->format = CAPTURE_FMT_RGBA16F;
break;
default:
@@ -752,8 +762,8 @@ static bool dxgi_init(void)
}
this->downsampleLevel = 0;
this->targetWidth = this->width;
this->targetHeight = this->height;
this->outputWidth = this->width;
this->outputHeight = this->height;
DownsampleRule * rule, * match = NULL;
vector_forEachRef(rule, &downsampleRules)
@@ -770,11 +780,11 @@ static bool dxgi_init(void)
{
DEBUG_INFO("Matched downsample rule %d", rule->id);
this->downsampleLevel = match->level;
this->targetWidth >>= match->level;
this->targetHeight >>= match->level;
this->outputWidth >>= match->level;
this->outputHeight >>= match->level;
}
DEBUG_INFO("Request Size : %u x %u", this->targetWidth, this->targetHeight);
DEBUG_INFO("Request Size : %u x %u", this->outputWidth, this->outputHeight);
const char * copyBackend = option_get_string("dxgi", "copyBackend");
for (int i = 0; i < ARRAY_LENGTH(backends); ++i)
@@ -792,7 +802,7 @@ static bool dxgi_init(void)
}
}
DEBUG_INFO("Output Size : %u x %u", this->targetWidth, this->targetHeight);
DEBUG_INFO("Output Size : %u x %u", this->outputWidth, this->outputHeight);
if (!this->backend)
{
@@ -812,23 +822,21 @@ static bool dxgi_init(void)
if (!initVertexShader())
goto fail;
const D3D11_VIEWPORT vp =
{
.TopLeftX = 0.0f,
.TopLeftY = 0.0f,
.Width = this->width,
.Height = this->height,
.MinDepth = 0.0f,
.MaxDepth = 1.0f,
};
ID3D11DeviceContext_RSSetViewports(*this->deviceContext, 1, &vp);
// if HDR add the SDRWhiteLevel post processor to correct the output
if (this->hdr && !ppInit(&DXGIPP_SDRWhiteLevel,
this->backend != &copyBackendD3D11))
if (this->hdr)
{
DEBUG_ERROR("Failed to initialize the SDRWhiteLevel post processor");
goto fail;
if (!ppInit(&DXGIPP_SDRWhiteLevel, this->backend != &copyBackendD3D11))
{
DEBUG_ERROR("Failed to initialize the SDRWhiteLevel post processor");
goto fail;
}
}
else
{
// only support DX11 for this atm
if (this->backend == &copyBackendD3D11)
if (!ppInit(&DXGIPP_RGB24, false))
DEBUG_WARN("Failed to initialize the RGB24 post processor");
}
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
@@ -874,6 +882,7 @@ static bool dxgi_deinit(void)
ppFreeAll();
if (this->backend)
{
this->backendConfigured = false;
this->backend->free();
this->backend = NULL;
}
@@ -1121,9 +1130,75 @@ static CaptureResult dxgi_capture(void)
computeFrameDamage(tex);
computeTexDamage(tex);
ID3D11Texture2D * dst = ppRun(tex, *src);
if (dst != *src)
ID3D11DeviceContext_Flush(*this->deviceContext);
// run any postprocessors
int width = this->width;
int height = this->height;
int cols = this->width;
int rows = this->height;
CaptureFormat format = this->format;
ID3D11Texture2D *dst = ppRun(
tex, *src, &width, &height, &cols, &rows, &format);
if (!this->backendConfigured)
{
switch(format)
{
case CAPTURE_FMT_RGBA:
this->bpp = 4;
this->dxgiFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
case CAPTURE_FMT_BGRA:
this->bpp = 4;
this->dxgiFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
break;
case CAPTURE_FMT_RGBA10:
this->bpp = 4;
this->dxgiFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
break;
case CAPTURE_FMT_RGBA16F:
this->bpp = 8;
this->dxgiFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
break;
case CAPTURE_FMT_BGR:
this->bpp = 4;
this->dxgiFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
break;
case CAPTURE_FMT_COLOR :
case CAPTURE_FMT_MONO :
case CAPTURE_FMT_MASKED:
case CAPTURE_FMT_MAX :
DEBUG_ERROR("Unsupported input format");
result = CAPTURE_RESULT_ERROR;
goto exit;
}
unsigned pitch = 0;
LG_LOCK(this->deviceContextLock);
if (!this->backend->configure(cols, rows, this->dxgiFormat, &pitch))
{
LG_UNLOCK(this->deviceContextLock);
DEBUG_ERROR("Failed to configure the copy backend");
result = CAPTURE_RESULT_ERROR;
goto exit;
}
LG_UNLOCK(this->deviceContextLock);
DEBUG_ASSERT(pitch && "copy backend did not return the pitch");
this->backendConfigured = true;
this->outputWidth = width;
this->outputHeight = height;
this->outputFormat = format;
this->dataWidth = cols;
this->dataHeight = rows;
this->pitch = pitch;
this->stride = pitch / this->bpp;
}
if (!this->backend->copyFrame(tex, dst))
{
@@ -1265,17 +1340,19 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame, const size_t maxFrameS
tex->state = TEXTURE_STATE_MAPPED;
const unsigned int maxHeight = maxFrameSize / this->pitch;
const unsigned int maxRows = maxFrameSize / this->pitch;
frame->formatVer = tex->formatVer;
frame->screenWidth = this->width;
frame->screenHeight = this->height;
frame->frameWidth = this->targetWidth;
frame->frameHeight = min(maxHeight, this->targetHeight);
frame->truncated = maxHeight < this->targetHeight;
frame->dataWidth = this->dataWidth;
frame->dataHeight = min(maxRows, this->dataHeight);
frame->frameWidth = this->outputWidth;
frame->frameHeight = this->outputHeight;
frame->truncated = maxRows < this->dataHeight;
frame->pitch = this->pitch;
frame->stride = this->stride;
frame->format = this->format;
frame->format = this->outputFormat;
frame->hdr = this->hdr;
frame->hdrPQ = false;
frame->rotation = this->rotation;
@@ -1288,8 +1365,7 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame, const size_t maxFrameS
return CAPTURE_RESULT_OK;
}
static CaptureResult dxgi_getFrame(FrameBuffer * frame,
const unsigned int height, int frameIndex)
static CaptureResult dxgi_getFrame(FrameBuffer * frame, int frameIndex)
{
DEBUG_ASSERT(this);
DEBUG_ASSERT(this->initialized);
@@ -1301,14 +1377,14 @@ static CaptureResult dxgi_getFrame(FrameBuffer * frame,
damage->count + tex->damageRectsCount > KVMFR_MAX_DAMAGE_RECTS;
if (damageAll)
framebuffer_write(frame, tex->map, this->pitch * height);
framebuffer_write(frame, tex->map, this->pitch * this->dataHeight);
else
{
memcpy(damage->rects + damage->count, tex->damageRects,
tex->damageRectsCount * sizeof(*tex->damageRects));
damage->count += tex->damageRectsCount;
rectsBufferToFramebuffer(damage->rects, damage->count, this->bpp, frame,
this->pitch, height, tex->map, this->pitch);
this->pitch, this->dataHeight, tex->map, this->pitch);
}
for (int i = 0; i < LGMP_Q_FRAME_LEN; ++i)
@@ -1373,22 +1449,27 @@ static CaptureResult dxgi_releaseFrame(void)
static bool ppInit(const DXGIPostProcess * pp, bool shareable)
{
if (!pp->setup(this->device, this->deviceContext, this->output))
if (!pp->setup(this->device, this->deviceContext, this->output, shareable))
return false;
for(int i = 0; i < this->maxTextures; ++i)
{
PostProcessInstance inst = { .pp = pp };
if (!pp->init(&inst.opaque, this->width, this->height, shareable))
if (!pp->init(&inst.opaque))
{
DEBUG_ERROR("Failed to init a post processor");
return false;
}
vector_push(&this->texture[i].pp, &inst);
}
return true;
}
static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src)
static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src,
int * width, int * height,
int * rows, int * cols,
CaptureFormat * format)
{
PostProcessInstance * inst;
vector_forEachRef(inst, &tex->pp)
@@ -1419,12 +1500,42 @@ static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src)
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create the source resource view", status);
continue;
return NULL;
}
inst->src = src;
}
LG_LOCK(this->deviceContextLock);
if (!inst->configured)
{
if (!inst->pp->configure(inst->opaque,
width, height,
cols , rows,
format))
{
LG_UNLOCK(this->deviceContextLock);
DEBUG_ERROR("setFormat failed on a post processor");
return NULL;
}
inst->configured = true;
inst->rows = *rows;
inst->cols = *cols;
}
// set the viewport
const D3D11_VIEWPORT vp =
{
.TopLeftX = 0.0f,
.TopLeftY = 0.0f,
.Width = inst->cols,
.Height = inst->rows,
.MinDepth = 0.0f,
.MaxDepth = 1.0f,
};
ID3D11DeviceContext_RSSetViewports(*this->deviceContext, 1, &vp);
// set the vertex shader
ID3D11DeviceContext_VSSetShader(
*this->deviceContext, *this->vshader, NULL, 0);
@@ -1432,9 +1543,19 @@ static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src)
// run the post processor
ID3D11Texture2D * out = inst->pp->run(inst->opaque, inst->srv);
// if the post processor returned a different texture then draw to run it
// if the post processor failed
if (!out)
{
LG_UNLOCK(this->deviceContextLock);
return NULL;
}
// if the post processor did nothing, just continue
if (out == src)
{
LG_UNLOCK(this->deviceContextLock);
continue;
}
// draw the full screen quad
ID3D11DeviceContext_IASetPrimitiveTopology(
@@ -1443,6 +1564,7 @@ static ID3D11Texture2D * ppRun(Texture * tex, ID3D11Texture2D * src)
// the output is now the input
src = out;
LG_UNLOCK(this->deviceContextLock);
}
return src;

View File

@@ -96,19 +96,21 @@ struct DXGIInterface
DXGI_COLOR_SPACE_TYPE dxgiColorSpace;
ID3D11VertexShader ** vshader;
struct DXGICopyBackend * backend;
bool backendConfigured;
CaptureGetPointerBuffer getPointerBufferFn;
CapturePostPointerBuffer postPointerBufferFn;
LGEvent * frameEvent;
unsigned int formatVer;
unsigned int width , targetWidth ;
unsigned int height, targetHeight;
unsigned int width , outputWidth , dataWidth;
unsigned int height, outputHeight, dataHeight;
unsigned int downsampleLevel;
unsigned int pitch;
unsigned int stride;
unsigned int padding;
unsigned int bpp;
CaptureFormat format;
CaptureFormat format, outputFormat;
CaptureRotation rotation;
int lastPointerX, lastPointerY;
@@ -122,6 +124,8 @@ struct DXGICopyBackend
const char * name;
const char * code;
bool (*create)(struct DXGIInterface * intf);
bool (*configure)(unsigned width, unsigned height,
DXGI_FORMAT format, unsigned * pitch);
void (*free)(void);
bool (*copyFrame)(Texture * tex, ID3D11Texture2D * src);
CaptureResult (*mapTexture)(Texture * tex);

View File

@@ -21,6 +21,9 @@
#include <d3d11.h>
#include <stdbool.h>
#include "interface/capture.h"
#include "common/locking.h"
typedef struct
{
/* the friendly name of the processor for debugging */
@@ -33,14 +36,17 @@ typedef struct
bool (*setup)(
ID3D11Device ** device,
ID3D11DeviceContext ** context,
IDXGIOutput ** output);
IDXGIOutput ** output,
bool shareable);
/* instance initialization */
bool (*init)(
void ** opaque,
int width,
int height,
bool shareable);
bool (*init)(void ** opaque);
/* showtime configuration */
bool (*configure)(void * opaque,
int * width, int * height, // the image dimensions
int * cols , int * rows , // the texture dimensions for packed data
CaptureFormat * type);
/* perform the processing */
ID3D11Texture2D * (*run)(void * opaque, ID3D11ShaderResourceView * srv);

View File

@@ -0,0 +1,251 @@
/**
* Looking Glass
* Copyright © 2017-2023 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pp.h"
#include "com_ref.h"
#include "util.h"
#include "common/debug.h"
#include "common/windebug.h"
#include <math.h>
typedef struct RGB24
{
ID3D11Device ** device;
ID3D11DeviceContext ** context;
bool shareable;
int size;
ID3D11PixelShader ** pshader;
}
RGB24;
static RGB24 this = {0};
typedef struct
{
ID3D11Texture2D ** tex;
ID3D11RenderTargetView ** target;
}
RGB24Inst;
static bool rgb24_setup(
ID3D11Device ** device,
ID3D11DeviceContext ** context,
IDXGIOutput ** output,
bool shareable
)
{
this.device = device;
this.context = context;
this.shareable = shareable;
return true;
}
static void rgb24_finish(void)
{
memset(&this, 0, sizeof(this));
}
static bool rgb24_configure(void * opaque,
int * width, int * height,
int * cols , int * rows ,
CaptureFormat * format)
{
RGB24Inst * inst = (RGB24Inst *)opaque;
HRESULT status;
comRef_scopePush();
if (!this.pshader)
{
int pixels = (*cols * *rows) * 3 / 4;
this.size = (((int)ceil(sqrt(pixels))) + 0x3F) & ~0x3F;
char sWidth[6], sHeight[6], sSize[6];
snprintf(sWidth , sizeof(sWidth ), "%d", *width );
snprintf(sHeight, sizeof(sHeight), "%d", *height);
snprintf(sSize , sizeof(sSize ), "%d", this.size);
const D3D_SHADER_MACRO defines[] =
{
{"INPUT_WIDTH" , sWidth },
{"INPUT_HEIGHT" , sHeight},
{"OUTPUT_SIZE" , sSize },
{NULL, NULL}
};
static const char * pshaderSrc =
"Texture2D<float4> gInputTexture : register(t0);\n"
"\n"
"float4 main(\n"
" float4 position : SV_POSITION,\n"
" float2 texCoord : TEXCOORD0) : SV_TARGET\n"
"{\n"
" uint outputIdx = uint(texCoord.y * OUTPUT_SIZE) * OUTPUT_SIZE +\n"
" uint(texCoord.x * OUTPUT_SIZE);\n"
"\n"
" uint fst = (outputIdx * 4) / 3;\n"
" float4 color0 = gInputTexture.Load(\n"
" uint3(fst % INPUT_WIDTH, fst / INPUT_WIDTH, 0));\n"
"\n"
" uint snd = fst + 1;\n"
" float4 color3 = gInputTexture.Load(\n"
" uint3(snd % INPUT_WIDTH, snd / INPUT_WIDTH, 0));\n"
"\n"
" uint outputIdxMod3 = outputIdx % 3;\n"
"\n"
" float4 color1 = outputIdxMod3 <= 1 ? color0 : color3;\n"
" float4 color2 = outputIdxMod3 == 0 ? color0 : color3;\n"
"\n"
" float b = color0.bgr[outputIdxMod3];\n"
" float g = color1.grb[outputIdxMod3];\n"
" float r = color2.rbg[outputIdxMod3];\n"
" float a = color3.bgr[outputIdxMod3];\n"
" return float4(r, g, b, a);\n"
"}\n";
comRef_defineLocal(ID3DBlob, byteCode);
if (!compileShader(byteCode, "main", "ps_5_0", pshaderSrc, defines))
goto fail;
comRef_defineLocal(ID3D11PixelShader, pshader);
HRESULT status = ID3D11Device_CreatePixelShader(
*this.device,
ID3D10Blob_GetBufferPointer(*byteCode),
ID3D10Blob_GetBufferSize (*byteCode),
NULL,
pshader);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create the pixel shader", status);
goto fail;
}
comRef_toGlobal(this.pshader, pshader);
}
// This texture is actually going to contain the packed BGR24 output
D3D11_TEXTURE2D_DESC texDesc =
{
.Width = this.size,
.Height = this.size,
.MipLevels = 1,
.ArraySize = 1,
.SampleDesc.Count = 1,
.SampleDesc.Quality = 0,
.Usage = D3D11_USAGE_DEFAULT,
.Format = DXGI_FORMAT_B8G8R8A8_UNORM,
.BindFlags = D3D11_BIND_RENDER_TARGET |
D3D11_BIND_SHADER_RESOURCE,
.CPUAccessFlags = 0,
.MiscFlags = 0
};
// allow texture sharing with other backends
if (this.shareable)
texDesc.MiscFlags |=
D3D11_RESOURCE_MISC_SHARED |
D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
comRef_defineLocal(ID3D11Texture2D, tex);
status = ID3D11Device_CreateTexture2D(
*this.device, &texDesc, NULL, tex);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create the output texture", status);
goto fail;
}
comRef_defineLocal(ID3D11RenderTargetView, target);
status = ID3D11Device_CreateRenderTargetView(
*this.device, *(ID3D11Resource **)tex, NULL, target);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create the render target view", status);
goto fail;
}
*cols = this.size;
*rows = this.size;
*format = CAPTURE_FMT_BGR;
comRef_toGlobal(inst->tex , tex );
comRef_toGlobal(inst->target, target );
comRef_scopePop();
return true;
fail:
comRef_scopePop();
return false;
}
static bool rgb24_init(void ** opaque)
{
RGB24Inst * inst = (RGB24Inst *)calloc(1, sizeof(*inst));
if (!inst)
{
DEBUG_ERROR("Failed to allocate memory");
return false;
}
*opaque = inst;
return true;
}
static void rgb24_free(void * opaque)
{
RGB24Inst * inst = (RGB24Inst *)opaque;
comRef_release(inst->target);
comRef_release(inst->tex );
free(inst);
}
static ID3D11Texture2D * rgb24_run(void * opaque,
ID3D11ShaderResourceView * srv)
{
RGB24Inst * inst = (RGB24Inst *)opaque;
// set the pixel shader & resources
ID3D11DeviceContext_PSSetShader(*this.context, *this.pshader, NULL, 0);
ID3D11DeviceContext_PSSetShaderResources(*this.context, 0, 1, &srv);
// set the render target
ID3D11DeviceContext_OMSetRenderTargets(*this.context, 1, inst->target, NULL);
return *inst->tex;
}
DXGIPostProcess DXGIPP_RGB24 =
{
.name = "RGB24",
.earlyInit = NULL,
.setup = rgb24_setup,
.init = rgb24_init,
.free = rgb24_free,
.configure = rgb24_configure,
.run = rgb24_run,
.finish = rgb24_finish
};

View File

@@ -32,6 +32,7 @@ typedef struct SDRWhiteLevel
ID3D11Device ** device;
ID3D11DeviceContext ** context;
bool shareable;
ID3D11PixelShader ** pshader;
ID3D11SamplerState ** sampler;
ID3D11Buffer ** buffer;
@@ -40,7 +41,7 @@ typedef struct SDRWhiteLevel
float sdrWhiteLevel;
}
SDRWhiteLevel;
SDRWhiteLevel this = {0};
static SDRWhiteLevel this = {0};
typedef struct
{
@@ -60,15 +61,17 @@ static void updateConsts(void);
static bool sdrWhiteLevel_setup(
ID3D11Device ** device,
ID3D11DeviceContext ** context,
IDXGIOutput ** output
IDXGIOutput ** output,
bool shareable
)
{
bool result = false;
comRef_scopePush();
HRESULT status;
this.device = device;
this.context = context;
this.device = device;
this.context = context;
this.shareable = shareable;
comRef_defineLocal(IDXGIOutput6, output6);
status = IDXGIOutput_QueryInterface(
@@ -106,7 +109,7 @@ static bool sdrWhiteLevel_setup(
"}\n";
comRef_defineLocal(ID3DBlob, byteCode);
if (!compileShader(byteCode, "main", "ps_5_0", pshaderSrc))
if (!compileShader(byteCode, "main", "ps_5_0", pshaderSrc, NULL))
goto exit;
comRef_defineLocal(ID3D11PixelShader, pshader);
@@ -178,11 +181,7 @@ static void sdrWhiteLevel_finish(void)
memset(&this, 0, sizeof(this));
}
static bool sdrWhiteLevel_init(
void ** opaque,
int width,
int height,
bool shareable)
static bool sdrWhiteLevel_init(void ** opaque)
{
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)calloc(1, sizeof(*inst));
if (!inst)
@@ -191,13 +190,48 @@ static bool sdrWhiteLevel_init(
return false;
}
*opaque = inst;
return true;
}
static void sdrWhiteLevel_free(void * opaque)
{
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)opaque;
comRef_release(inst->target);
comRef_release(inst->tex );
free(inst);
}
static void updateConsts(void)
{
float nits = getSDRWhiteLevel(&this.displayPathInfo);
if (nits == this.sdrWhiteLevel)
return;
this.sdrWhiteLevel = nits;
struct ShaderConsts consts = { .sdrWhiteLevel = 80.0f / nits };
ID3D11DeviceContext_UpdateSubresource(
*this.context, *(ID3D11Resource**)this.buffer,
0, NULL, &consts, 0, 0);
}
static bool sdrWhiteLevel_configure(void * opaque,
int * width, int * height,
int * cols , int * rows,
CaptureFormat * format)
{
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)opaque;
if (inst->tex)
return true;
comRef_scopePush();
// create the output texture
D3D11_TEXTURE2D_DESC texDesc =
{
.Width = width,
.Height = height,
.Width = *width,
.Height = *height,
.MipLevels = 1,
.ArraySize = 1,
.SampleDesc.Count = 1,
@@ -211,7 +245,7 @@ static bool sdrWhiteLevel_init(
};
// allow texture sharing with other backends
if (shareable)
if (this.shareable)
texDesc.MiscFlags |=
D3D11_RESOURCE_MISC_SHARED |
D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
@@ -236,41 +270,19 @@ static bool sdrWhiteLevel_init(
goto fail;
}
*opaque = inst;
comRef_toGlobal(inst->tex , tex );
comRef_toGlobal(inst->target, target);
comRef_scopePop();
*format = CAPTURE_FMT_RGBA10;
return true;
fail:
comRef_scopePop();
free(inst);
return false;
}
static void sdrWhiteLevel_free(void * opaque)
{
SDRWhiteLevelInst * inst = (SDRWhiteLevelInst *)opaque;
comRef_release(inst->target);
comRef_release(inst->tex );
free(inst);
}
static void updateConsts(void)
{
float nits = getSDRWhiteLevel(&this.displayPathInfo);
if (nits == this.sdrWhiteLevel)
return;
this.sdrWhiteLevel = nits;
struct ShaderConsts consts = { .sdrWhiteLevel = 80.0f / nits };
ID3D11DeviceContext_UpdateSubresource(
*this.context, *(ID3D11Resource**)this.buffer,
0, NULL, &consts, 0, 0);
}
static ID3D11Texture2D * sdrWhiteLevel_run(void * opaque,
ID3D11ShaderResourceView * srv)
{
@@ -299,6 +311,7 @@ DXGIPostProcess DXGIPP_SDRWhiteLevel =
.setup = sdrWhiteLevel_setup,
.init = sdrWhiteLevel_init,
.free = sdrWhiteLevel_free,
.configure = sdrWhiteLevel_configure,
.run = sdrWhiteLevel_run,
.finish = sdrWhiteLevel_finish
};

View File

@@ -196,18 +196,18 @@ const char * getDXGIColorSpaceTypeStr(DXGI_COLOR_SPACE_TYPE type)
}
bool compileShader(ID3DBlob ** dst, const char * entry, const char * target,
const char * code)
const char * code, const D3D_SHADER_MACRO * defines)
{
ID3DBlob * errors;
HRESULT status = D3DCompile(
code,
strlen(code),
NULL,
NULL,
defines,
NULL,
entry,
target,
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
0,//D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
0,
dst,
&errors);

View File

@@ -25,7 +25,7 @@ const char * getDXGIFormatStr(DXGI_FORMAT format);
const char * getDXGIColorSpaceTypeStr(DXGI_COLOR_SPACE_TYPE type);
bool compileShader(ID3DBlob ** dst, const char * entry, const char * target,
const char * code);
const char * code, const D3D_SHADER_MACRO * defines);
bool getDisplayPathInfo(HMONITOR monitor, DISPLAYCONFIG_PATH_INFO * info);