284 lines
8.4 KiB
C
284 lines
8.4 KiB
C
#pragma bss_seg(".analysisbss")
|
|
static ID3D11Texture2D* resolvedTexture;
|
|
static ID3D11Texture2D* stagingTexture;
|
|
static D3D11_MAPPED_SUBRESOURCE analysisResource;
|
|
static int* pixels;
|
|
static HBITMAP hbmp;
|
|
static HDC hdcMem;
|
|
static HDC hdc;
|
|
static D3D11_TEXTURE2D_DESC stagingDesc;
|
|
static unsigned int hR[256];
|
|
static unsigned int hG[256];
|
|
static unsigned int hB[256];
|
|
static unsigned int waveForm[screenWidth * 256];
|
|
static unsigned int paradeR[screenWidth * 256];
|
|
static unsigned int paradeG[screenWidth * 256];
|
|
static unsigned int paradeB[screenWidth * 256];
|
|
static unsigned int vectorScope[256 * 256];
|
|
|
|
#pragma data_seg(".analysisdata")
|
|
extern ID3D11Texture2D* backBufferPtr;
|
|
extern ID3D11Device* device;
|
|
extern ID3D11DeviceContext* deviceContext;
|
|
|
|
float fast_log2(float val)
|
|
{
|
|
int * const exp_ptr = reinterpret_cast <int *> (&val);
|
|
int x = *exp_ptr;
|
|
const int log_2 = ((x >> 23) & 255) - 128;
|
|
x &= ~(255 << 23);
|
|
x += 127 << 23;
|
|
*exp_ptr = x;
|
|
|
|
return (val + log_2);
|
|
}
|
|
|
|
void InitAnalysis(HWND hwnd)
|
|
{
|
|
backBufferPtr->GetDesc(&stagingDesc);
|
|
stagingDesc.Usage = D3D11_USAGE_DEFAULT;
|
|
stagingDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
stagingDesc.BindFlags = 0;
|
|
stagingDesc.SampleDesc.Count = 1;
|
|
device->CreateTexture2D(&stagingDesc, NULL, &resolvedTexture);
|
|
|
|
stagingDesc.Usage = D3D11_USAGE_STAGING;
|
|
stagingDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_READ;
|
|
device->CreateTexture2D(&stagingDesc, NULL, &stagingTexture);
|
|
|
|
BITMAPINFO bmi;
|
|
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
|
|
bmi.bmiHeader.biWidth = 1024;
|
|
bmi.bmiHeader.biHeight = -512; // Order pixels from top to bottom
|
|
bmi.bmiHeader.biPlanes = 1;
|
|
bmi.bmiHeader.biBitCount = 32; // last byte not used, 32 bit for alignment
|
|
bmi.bmiHeader.biCompression = BI_RGB;
|
|
bmi.bmiHeader.biSizeImage = 0;
|
|
bmi.bmiHeader.biXPelsPerMeter = 0;
|
|
bmi.bmiHeader.biYPelsPerMeter = 0;
|
|
bmi.bmiHeader.biClrUsed = 0;
|
|
bmi.bmiHeader.biClrImportant = 0;
|
|
bmi.bmiColors[0].rgbBlue = 0;
|
|
bmi.bmiColors[0].rgbGreen = 0;
|
|
bmi.bmiColors[0].rgbRed = 0;
|
|
bmi.bmiColors[0].rgbReserved = 0;
|
|
|
|
hdc = ::GetDC(hwnd);
|
|
hdcMem = CreateCompatibleDC(hdc);
|
|
hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&pixels, NULL, 0);
|
|
}
|
|
|
|
void Analyze()
|
|
{
|
|
SelectObject(hdcMem, hbmp);
|
|
deviceContext->ResolveSubresource(resolvedTexture, 0, backBufferPtr, 0, stagingDesc.Format);
|
|
deviceContext->CopyResource(stagingTexture, resolvedTexture);
|
|
deviceContext->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &analysisResource);
|
|
int* image = (int*)analysisResource.pData;
|
|
memset(pixels, 0, 1024 * 512 * 4);
|
|
|
|
memset(hR, 0, 256 * 4);
|
|
memset(hG, 0, 256 * 4);
|
|
memset(hB, 0, 256 * 4);
|
|
memset(waveForm, 0, screenWidth * 256 * 4);
|
|
memset(paradeR, 0, screenWidth * 256 * 4);
|
|
memset(paradeG, 0, screenWidth * 256 * 4);
|
|
memset(paradeB, 0, screenWidth * 256 * 4);
|
|
memset(vectorScope, 0, 256 * 256 * 4);
|
|
|
|
// Gather data
|
|
for (int y = 0; y < screenHeight; ++y)
|
|
{
|
|
for (int x = 0; x < screenWidth; ++x)
|
|
{
|
|
unsigned char* colors = (unsigned char*)&image[y * (analysisResource.RowPitch / 4) + x]; // BGRA
|
|
float luminance = 0.2126f * colors[2] + 0.7152f * colors[1] + 0.0722f * colors[0];
|
|
|
|
float umax = 0.436f;
|
|
float vmax = 0.615f;
|
|
float ly = luminance / 255.0f;
|
|
float fu = 0.492f * (colors[0] / 255.0f - ly);
|
|
float fv = 0.877f * (colors[2] / 255.0f - ly);
|
|
int u = min(255, max(0, 128 * (1 + fu / umax)));
|
|
int v = min(255, max(0, 128 * (1 + fv / vmax)));
|
|
|
|
int l = (int)(luminance);
|
|
waveForm[l * screenWidth + x]++;
|
|
vectorScope[v * 256 + u]++;
|
|
paradeR[colors[2] * screenWidth + x]++;
|
|
paradeG[colors[1] * screenWidth + x]++;
|
|
paradeB[colors[0] * screenWidth + x]++;
|
|
hR[colors[2]]++;
|
|
hG[colors[1]]++;
|
|
hB[colors[0]]++;
|
|
}
|
|
}
|
|
|
|
deviceContext->Unmap(stagingTexture, 0);
|
|
|
|
// Determine max values
|
|
float maxHistogramValue = 0;
|
|
float maxVectorscopeValue = 0;
|
|
float maxWaveForm = 0;
|
|
float maxParadeR = 0;
|
|
float maxParadeG = 0;
|
|
float maxParadeB = 0;
|
|
for (int i = 0; i < 256; ++i)
|
|
{
|
|
if (hR[i] > maxHistogramValue)
|
|
maxHistogramValue = hR[i];
|
|
if (hG[i] > maxHistogramValue)
|
|
maxHistogramValue = hG[i];
|
|
if (hB[i] > maxHistogramValue)
|
|
maxHistogramValue = hB[i];
|
|
|
|
for (int j = 0; j < screenWidth; ++j)
|
|
{
|
|
if (waveForm[i * screenWidth + j] > maxWaveForm)
|
|
maxWaveForm = waveForm[i * screenWidth + j];
|
|
if (paradeR[i * screenWidth + j] > maxParadeR)
|
|
maxParadeR = paradeR[i * screenWidth + j];
|
|
if (paradeG[i * screenWidth + j] > maxParadeG)
|
|
maxParadeG = paradeG[i * screenWidth + j];
|
|
if (paradeB[i * screenWidth + j] > maxParadeB)
|
|
maxParadeB = paradeB[i * screenWidth + j];
|
|
}
|
|
|
|
for (int j = 0; j < 256; ++j)
|
|
{
|
|
if (vectorScope[i * 256 + j] > maxVectorscopeValue)
|
|
maxVectorscopeValue = vectorScope[i * 256 + j];
|
|
}
|
|
}
|
|
|
|
maxHistogramValue = fast_log2(1 + maxHistogramValue);
|
|
maxVectorscopeValue = fast_log2(1 + maxVectorscopeValue);
|
|
maxWaveForm = fast_log2(1 + maxWaveForm);
|
|
maxParadeR = fast_log2(1 + maxParadeR);
|
|
maxParadeG = fast_log2(1 + maxParadeG);
|
|
maxParadeB = fast_log2(1 + maxParadeB);
|
|
|
|
// Draw histogram
|
|
int oldYR = 255;
|
|
int oldYG = 255;
|
|
int oldYB = 255;
|
|
for (int i = 0; i < 768; ++i)
|
|
{
|
|
int x = i * 256 / 768;
|
|
int yR = 255 - min(255, max(0, (int)(fast_log2(1 + hR[x]) * 256.0f / maxHistogramValue)));
|
|
int yG = 255 - min(255, max(0, (int)(fast_log2(1 + hG[x]) * 256.0f / maxHistogramValue)));
|
|
int yB = 255 - min(255, max(0, (int)(fast_log2(1 + hB[x]) * 256.0f / maxHistogramValue)));
|
|
if (oldYR < yR)
|
|
{
|
|
for (int y = oldYR; y <= yR; ++y)
|
|
pixels[y * 1024 + i] |= 0x000000FF;
|
|
}
|
|
else
|
|
{
|
|
for (int y = yR; y <= oldYR; ++y)
|
|
pixels[y * 1024 + i] |= 0x000000FF;
|
|
}
|
|
|
|
if (oldYG < yG)
|
|
{
|
|
for (int y = oldYG; y <= yG; ++y)
|
|
pixels[y * 1024 + i] |= 0x0000FF00;
|
|
}
|
|
else
|
|
{
|
|
for (int y = yG; y <= oldYG; ++y)
|
|
pixels[y * 1024 + i] |= 0x0000FF00;
|
|
}
|
|
|
|
if (oldYB < yB)
|
|
{
|
|
for (int y = oldYB; y <= yB; ++y)
|
|
pixels[y * 1024 + i] |= 0x00FF0000;
|
|
}
|
|
else
|
|
{
|
|
for (int y = yB; y <= oldYB; ++y)
|
|
pixels[y * 1024 + i] |= 0x00FF0000;
|
|
}
|
|
|
|
for (int y = yR; y <= 255; ++y)
|
|
pixels[y * 1024 + i] |= 0x00000080;
|
|
|
|
for (int y = yG; y <= 255; ++y)
|
|
pixels[y * 1024 + i] |= 0x00008000;
|
|
|
|
for (int y = yB; y <= 255; ++y)
|
|
pixels[y * 1024 + i] |= 0x00800000;
|
|
|
|
oldYR = yR;
|
|
oldYG = yG;
|
|
oldYB = yB;
|
|
}
|
|
|
|
for (int y = 0; y < 256; ++y)
|
|
{
|
|
// Draw Waveform and RGB parade
|
|
for (int wx = 0; wx < screenWidth; ++wx)
|
|
{
|
|
int x = (int)(wx * 255.0f / screenWidth);
|
|
|
|
int luminance = (int)(fast_log2(1 + waveForm[y * screenWidth + wx]) * 256.0f / maxWaveForm);
|
|
int r = (int)(fast_log2(1 + paradeR[y * screenWidth + wx]) * 256.0f / maxParadeR);
|
|
int g = (int)(fast_log2(1 + paradeG[y * screenWidth + wx]) * 256.0f / maxParadeG);
|
|
int b = (int)(fast_log2(1 + paradeB[y * screenWidth + wx]) * 256.0f / maxParadeB);
|
|
|
|
luminance = max(luminance, pixels[(511 - y) * 1024 + x] & 0x000000FF);
|
|
r = max(r, pixels[(511 - y) * 1024 + x + 768]);
|
|
g = max(g, pixels[(511 - y) * 1024 + x + 512] >> 8);
|
|
b = max(b, pixels[(511 - y) * 1024 + x + 256] >> 16);
|
|
|
|
int pixel = luminance | (luminance << 8) | (luminance << 16);
|
|
pixels[(511 - y) * 1024 + x] = pixel;
|
|
pixels[(511 - y) * 1024 + x + 768] = r;
|
|
pixels[(511 - y) * 1024 + x + 512] = g << 8;
|
|
pixels[(511 - y) * 1024 + x + 256] = b << 16;
|
|
}
|
|
|
|
// Draw Vectorscope
|
|
for (int x = 0; x < 256; ++x)
|
|
{
|
|
float luminance = 0.1f + 0.9f * (1.0f - max(0, min(1, fast_log2(vectorScope[y * 256 + x] + 1) / maxVectorscopeValue)));
|
|
float fx = (x - 128) / 128.0f;
|
|
float fy = (y - 128) / 128.0f;
|
|
if (fx*fx + fy*fy > 1)
|
|
luminance = 0.0f;
|
|
|
|
float umax = 0.436f;
|
|
float vmax = 0.615f;
|
|
float ly = 0.5;
|
|
float u = ((x / 128.0f) - 1.0f) * umax;
|
|
float v = ((y / 128.0f) - 1.0f) * vmax;
|
|
int r = luminance * 255.0f * min(1, max(0, (ly + v / 0.877f)));
|
|
int b = luminance * 255.0f * min(1, max(0, (ly + u / 0.492f)));
|
|
int g = luminance * 255.0f * min(1, max(0, (ly - u * 0.395f - v * 0.581f)));
|
|
|
|
int pixel = r | (g << 8) | (b << 16);
|
|
pixels[(255 - y) * 1024 + x + 768] = pixel;
|
|
}
|
|
}
|
|
|
|
RECT rect = { 0 };
|
|
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
DrawText(hdcMem, "Histogram", -1, &rect, DT_SINGLELINE | DT_NOCLIP);
|
|
|
|
rect.left = 768;
|
|
rect.top = 0;
|
|
DrawText(hdcMem, "Vectorscope", -1, &rect, DT_SINGLELINE | DT_NOCLIP);
|
|
|
|
rect.left = 0;
|
|
rect.top = 256;
|
|
DrawText(hdcMem, "Waveform", -1, &rect, DT_SINGLELINE | DT_NOCLIP);
|
|
|
|
rect.left = 256;
|
|
rect.top = 256;
|
|
DrawText(hdcMem, "RGB Parade", -1, &rect, DT_SINGLELINE | DT_NOCLIP);
|
|
|
|
BitBlt(hdc, 0, 0, 1024, 512, hdcMem, 0, 0, SRCCOPY);
|
|
} |