cpu start
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
misc/cpp/
|
||||
InputText() wrappers for C++ standard library (STL) type: std::string.
|
||||
This is also an example of how you may wrap your own similar types.
|
||||
Includes imgui_cpu_validate.cpp, an offscreen validation utility for the imgui_impl_cpu backend.
|
||||
|
||||
misc/debuggers/
|
||||
Helper files for popular debuggers (Visual Studio, GDB, LLDB).
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,385 @@
|
||||
// dear imgui: imgui_impl_cpu format validation utility
|
||||
// Build manually with imgui core sources + backends/imgui_impl_cpu.cpp.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_cpu.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct ValidationBuffer
|
||||
{
|
||||
ImVector<unsigned char> Storage;
|
||||
ImVector<ImU32> Palette;
|
||||
ImGui_ImplCPU_PixelFormat Format;
|
||||
ImGui_ImplCPU_Framebuffer Framebuffer;
|
||||
|
||||
ValidationBuffer() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
static inline unsigned char Validation_ExpandBits(ImU32 value, int bits)
|
||||
{
|
||||
if (bits <= 0)
|
||||
return 0;
|
||||
if (bits >= 8)
|
||||
return (unsigned char)value;
|
||||
ImU32 max_value = (1u << bits) - 1u;
|
||||
return (unsigned char)((value * 255u + (max_value >> 1)) / max_value);
|
||||
}
|
||||
|
||||
static inline ImU32 Validation_CompressBits(unsigned char value, int bits)
|
||||
{
|
||||
if (bits <= 0)
|
||||
return 0;
|
||||
if (bits >= 8)
|
||||
return value;
|
||||
ImU32 max_value = (1u << bits) - 1u;
|
||||
return (ImU32)((value * max_value + 127u) / 255u);
|
||||
}
|
||||
|
||||
static inline void Validation_UnpackCanonicalRGBA(ImU32 pixel, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
||||
{
|
||||
*r = (unsigned char)((pixel >> IM_COL32_R_SHIFT) & 0xFF);
|
||||
*g = (unsigned char)((pixel >> IM_COL32_G_SHIFT) & 0xFF);
|
||||
*b = (unsigned char)((pixel >> IM_COL32_B_SHIFT) & 0xFF);
|
||||
*a = (unsigned char)((pixel >> IM_COL32_A_SHIFT) & 0xFF);
|
||||
}
|
||||
|
||||
static inline ImU32 Validation_ReadRawPixel(const ValidationBuffer& buffer, int x, int y)
|
||||
{
|
||||
const unsigned char* p = buffer.Framebuffer.Pixels + (size_t)y * (size_t)buffer.Framebuffer.Pitch + (size_t)x * (size_t)buffer.Format.BytesPerPixel;
|
||||
switch (buffer.Format.BytesPerPixel)
|
||||
{
|
||||
case 1:
|
||||
return *p;
|
||||
case 2:
|
||||
{
|
||||
ImU16 pixel = 0;
|
||||
memcpy(&pixel, p, sizeof(pixel));
|
||||
return pixel;
|
||||
}
|
||||
case 3:
|
||||
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
return (ImU32)((p[0] << 16) | (p[1] << 8) | p[2]);
|
||||
#else
|
||||
return (ImU32)(p[0] | (p[1] << 8) | (p[2] << 16));
|
||||
#endif
|
||||
case 4:
|
||||
{
|
||||
ImU32 pixel = 0;
|
||||
memcpy(&pixel, p, sizeof(pixel));
|
||||
return pixel;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void Validation_WriteRawPixel(ValidationBuffer* buffer, int x, int y, ImU32 pixel)
|
||||
{
|
||||
unsigned char* p = buffer->Framebuffer.Pixels + (size_t)y * (size_t)buffer->Framebuffer.Pitch + (size_t)x * (size_t)buffer->Format.BytesPerPixel;
|
||||
switch (buffer->Format.BytesPerPixel)
|
||||
{
|
||||
case 1:
|
||||
*p = (unsigned char)pixel;
|
||||
return;
|
||||
case 2:
|
||||
{
|
||||
ImU16 v = (ImU16)pixel;
|
||||
memcpy(p, &v, sizeof(v));
|
||||
return;
|
||||
}
|
||||
case 3:
|
||||
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
p[0] = (unsigned char)((pixel >> 16) & 0xFF);
|
||||
p[1] = (unsigned char)((pixel >> 8) & 0xFF);
|
||||
p[2] = (unsigned char)(pixel & 0xFF);
|
||||
#else
|
||||
p[0] = (unsigned char)(pixel & 0xFF);
|
||||
p[1] = (unsigned char)((pixel >> 8) & 0xFF);
|
||||
p[2] = (unsigned char)((pixel >> 16) & 0xFF);
|
||||
#endif
|
||||
return;
|
||||
case 4:
|
||||
memcpy(p, &pixel, sizeof(pixel));
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static ImU32 Validation_MapNearestPaletteColor(const ImGui_ImplCPU_PixelFormat* format, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
unsigned int best_distance = 0xFFFFFFFFu;
|
||||
int best_index = 0;
|
||||
for (int i = 0; i < format->PaletteSize; i++)
|
||||
{
|
||||
unsigned char pr, pg, pb, pa;
|
||||
Validation_UnpackCanonicalRGBA(format->Palette[i], &pr, &pg, &pb, &pa);
|
||||
int dr = (int)pr - (int)r;
|
||||
int dg = (int)pg - (int)g;
|
||||
int db = (int)pb - (int)b;
|
||||
int da = (int)pa - (int)a;
|
||||
unsigned int distance = (unsigned int)(dr * dr + dg * dg + db * db + da * da);
|
||||
if (distance < best_distance)
|
||||
{
|
||||
best_distance = distance;
|
||||
best_index = i;
|
||||
if (distance == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (ImU32)best_index;
|
||||
}
|
||||
|
||||
static ImU32 Validation_PackPixel(const ValidationBuffer& buffer, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
if (buffer.Format.Palette != nullptr && buffer.Format.PaletteSize > 0)
|
||||
{
|
||||
if (buffer.Format.MapColorFn != nullptr)
|
||||
return buffer.Format.MapColorFn(&buffer.Format, r, g, b, a);
|
||||
return Validation_MapNearestPaletteColor(&buffer.Format, r, g, b, a);
|
||||
}
|
||||
|
||||
ImU32 pixel = 0;
|
||||
if (buffer.Format.Rmask != 0)
|
||||
pixel |= (Validation_CompressBits(r, 8 - buffer.Format.Rloss) << buffer.Format.Rshift) & buffer.Format.Rmask;
|
||||
if (buffer.Format.Gmask != 0)
|
||||
pixel |= (Validation_CompressBits(g, 8 - buffer.Format.Gloss) << buffer.Format.Gshift) & buffer.Format.Gmask;
|
||||
if (buffer.Format.Bmask != 0)
|
||||
pixel |= (Validation_CompressBits(b, 8 - buffer.Format.Bloss) << buffer.Format.Bshift) & buffer.Format.Bmask;
|
||||
if (buffer.Format.Amask != 0)
|
||||
pixel |= (Validation_CompressBits(a, 8 - buffer.Format.Aloss) << buffer.Format.Ashift) & buffer.Format.Amask;
|
||||
return pixel;
|
||||
}
|
||||
|
||||
static void Validation_DecodePixel(const ValidationBuffer& buffer, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
||||
{
|
||||
ImU32 pixel = Validation_ReadRawPixel(buffer, x, y);
|
||||
if (buffer.Format.Palette != nullptr && buffer.Format.PaletteSize > 0)
|
||||
{
|
||||
if (pixel >= (ImU32)buffer.Format.PaletteSize)
|
||||
{
|
||||
*r = *g = *b = *a = 0;
|
||||
return;
|
||||
}
|
||||
Validation_UnpackCanonicalRGBA(buffer.Format.Palette[pixel], r, g, b, a);
|
||||
return;
|
||||
}
|
||||
|
||||
*r = (buffer.Format.Rmask != 0) ? Validation_ExpandBits((pixel & buffer.Format.Rmask) >> buffer.Format.Rshift, 8 - buffer.Format.Rloss) : 0;
|
||||
*g = (buffer.Format.Gmask != 0) ? Validation_ExpandBits((pixel & buffer.Format.Gmask) >> buffer.Format.Gshift, 8 - buffer.Format.Gloss) : 0;
|
||||
*b = (buffer.Format.Bmask != 0) ? Validation_ExpandBits((pixel & buffer.Format.Bmask) >> buffer.Format.Bshift, 8 - buffer.Format.Bloss) : 0;
|
||||
*a = (buffer.Format.Amask != 0) ? Validation_ExpandBits((pixel & buffer.Format.Amask) >> buffer.Format.Ashift, 8 - buffer.Format.Aloss) : 255;
|
||||
}
|
||||
|
||||
static bool Validation_InitBuffer(ValidationBuffer* buffer, int width, int height, const ImGui_ImplCPU_PixelFormat* format)
|
||||
{
|
||||
buffer->Format = *format;
|
||||
buffer->Framebuffer.Width = width;
|
||||
buffer->Framebuffer.Height = height;
|
||||
buffer->Framebuffer.Pitch = width * buffer->Format.BytesPerPixel;
|
||||
buffer->Storage.resize(height * buffer->Framebuffer.Pitch);
|
||||
buffer->Framebuffer.Pixels = buffer->Storage.Data;
|
||||
buffer->Framebuffer.Format = &buffer->Format;
|
||||
return buffer->Framebuffer.Pixels != nullptr;
|
||||
}
|
||||
|
||||
static bool Validation_InitIndexedBuffer(ValidationBuffer* buffer, int width, int height)
|
||||
{
|
||||
buffer->Palette.clear();
|
||||
buffer->Palette.push_back(IM_COL32(114, 140, 153, 255));
|
||||
buffer->Palette.push_back(IM_COL32(255, 0, 0, 255));
|
||||
buffer->Palette.push_back(IM_COL32(0, 255, 0, 255));
|
||||
buffer->Palette.push_back(IM_COL32(0, 0, 255, 255));
|
||||
buffer->Palette.push_back(IM_COL32(255, 255, 255, 255));
|
||||
buffer->Palette.push_back(IM_COL32(255, 255, 0, 255));
|
||||
|
||||
memset(&buffer->Format, 0, sizeof(buffer->Format));
|
||||
buffer->Format.BitsPerPixel = 8;
|
||||
buffer->Format.BytesPerPixel = 1;
|
||||
buffer->Format.Palette = buffer->Palette.Data;
|
||||
buffer->Format.PaletteSize = buffer->Palette.Size;
|
||||
buffer->Format.MapColorFn = Validation_MapNearestPaletteColor;
|
||||
return Validation_InitBuffer(buffer, width, height, &buffer->Format);
|
||||
}
|
||||
|
||||
static void Validation_ClearBuffer(ValidationBuffer* buffer, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
ImU32 pixel = Validation_PackPixel(*buffer, r, g, b, a);
|
||||
for (int y = 0; y < buffer->Framebuffer.Height; y++)
|
||||
for (int x = 0; x < buffer->Framebuffer.Width; x++)
|
||||
Validation_WriteRawPixel(buffer, x, y, pixel);
|
||||
}
|
||||
|
||||
static bool Validation_CompareBuffers(const char* name, const ValidationBuffer& reference, const ValidationBuffer& candidate, int tolerance_rgb, int tolerance_alpha, bool ignore_alpha)
|
||||
{
|
||||
for (int y = 0; y < reference.Framebuffer.Height; y++)
|
||||
for (int x = 0; x < reference.Framebuffer.Width; x++)
|
||||
{
|
||||
unsigned char rr, rg, rb, ra;
|
||||
unsigned char cr, cg, cb, ca;
|
||||
Validation_DecodePixel(reference, x, y, &rr, &rg, &rb, &ra);
|
||||
Validation_DecodePixel(candidate, x, y, &cr, &cg, &cb, &ca);
|
||||
|
||||
if (abs((int)rr - (int)cr) > tolerance_rgb
|
||||
|| abs((int)rg - (int)cg) > tolerance_rgb
|
||||
|| abs((int)rb - (int)cb) > tolerance_rgb
|
||||
|| (!ignore_alpha && abs((int)ra - (int)ca) > tolerance_alpha))
|
||||
{
|
||||
printf("Validation failed for %s at (%d, %d): ref=(%u,%u,%u,%u) got=(%u,%u,%u,%u)\n",
|
||||
name, x, y, rr, rg, rb, ra, cr, cg, cb, ca);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Validation_FillBGRAImage(ImVector<unsigned char>* storage, ImGui_ImplCPU_Texture* texture)
|
||||
{
|
||||
const int width = 48;
|
||||
const int height = 32;
|
||||
storage->resize(width * height * 4);
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
unsigned char r = (unsigned char)(32 + x * 4);
|
||||
unsigned char g = (unsigned char)(32 + y * 6);
|
||||
unsigned char b = (unsigned char)(255 - x * 4);
|
||||
int offset = (y * width + x) * 4;
|
||||
(*storage)[offset + 0] = b;
|
||||
(*storage)[offset + 1] = g;
|
||||
(*storage)[offset + 2] = r;
|
||||
(*storage)[offset + 3] = 255;
|
||||
}
|
||||
|
||||
texture->Pixels = storage->Data;
|
||||
texture->Width = width;
|
||||
texture->Height = height;
|
||||
texture->Pitch = width * 4;
|
||||
texture->Format = ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_BGRA8888);
|
||||
}
|
||||
|
||||
static void Validation_BuildMainScene(const ImGui_ImplCPU_Texture* image_texture)
|
||||
{
|
||||
ImDrawList* bg = ImGui::GetBackgroundDrawList();
|
||||
bg->AddRectFilled(ImVec2(8.0f, 8.0f), ImVec2(40.0f, 40.0f), IM_COL32(255, 0, 0, 255));
|
||||
bg->AddRectFilled(ImVec2(472.0f, 280.0f), ImVec2(504.0f, 312.0f), IM_COL32(0, 255, 0, 255));
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(32.0f, 24.0f), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(320.0f, 180.0f), ImGuiCond_Always);
|
||||
ImGui::Begin("Validation", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
ImGui::Text("CPU format validation");
|
||||
ImGui::Text("Top-left marker is red. Bottom-right is green.");
|
||||
ImGui::ColorButton("##color", ImVec4(0.2f, 0.6f, 0.9f, 1.0f), 0, ImVec2(48.0f, 24.0f));
|
||||
ImGui::SameLine();
|
||||
ImGui::Image((ImTextureID)(intptr_t)image_texture, ImVec2((float)image_texture->Width, (float)image_texture->Height));
|
||||
ImGui::ProgressBar(0.65f, ImVec2(240.0f, 0.0f));
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
static void Validation_BuildPaletteScene()
|
||||
{
|
||||
ImDrawList* bg = ImGui::GetBackgroundDrawList();
|
||||
bg->AddRectFilled(ImVec2(8.0f, 8.0f), ImVec2(40.0f, 40.0f), IM_COL32(255, 0, 0, 255));
|
||||
bg->AddRectFilled(ImVec2(472.0f, 280.0f), ImVec2(504.0f, 312.0f), IM_COL32(0, 255, 0, 255));
|
||||
bg->AddRectFilled(ImVec2(160.0f, 32.0f), ImVec2(320.0f, 96.0f), IM_COL32(0, 0, 255, 255));
|
||||
bg->AddRectFilled(ImVec2(56.0f, 232.0f), ImVec2(168.0f, 280.0f), IM_COL32(255, 255, 0, 255));
|
||||
bg->AddRectFilled(ImVec2(360.0f, 64.0f), ImVec2(456.0f, 112.0f), IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
|
||||
static bool Validation_RenderInto(ValidationBuffer* buffer, ImDrawData* draw_data)
|
||||
{
|
||||
Validation_ClearBuffer(buffer, 114, 140, 153, 255);
|
||||
ImGui_ImplCPU_RenderDrawData(draw_data, &buffer->Framebuffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2(512.0f, 320.0f);
|
||||
io.DeltaTime = 1.0f / 60.0f;
|
||||
io.Fonts->TexDesiredFormat = ImTextureFormat_Alpha8;
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
ImGui_ImplCPU_Init();
|
||||
|
||||
ImVector<unsigned char> image_storage;
|
||||
ImGui_ImplCPU_Texture image_texture;
|
||||
memset(&image_texture, 0, sizeof(image_texture));
|
||||
Validation_FillBGRAImage(&image_storage, &image_texture);
|
||||
|
||||
ValidationBuffer reference;
|
||||
Validation_InitBuffer(&reference, 512, 320, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_RGBA8888));
|
||||
|
||||
const ImGui_ImplCPU_BuiltinFormat builtin_formats[] =
|
||||
{
|
||||
ImGui_ImplCPU_BuiltinFormat_RGBA8888,
|
||||
ImGui_ImplCPU_BuiltinFormat_BGRA8888,
|
||||
ImGui_ImplCPU_BuiltinFormat_ARGB8888,
|
||||
ImGui_ImplCPU_BuiltinFormat_ABGR8888,
|
||||
ImGui_ImplCPU_BuiltinFormat_RGB565,
|
||||
ImGui_ImplCPU_BuiltinFormat_ARGB1555,
|
||||
ImGui_ImplCPU_BuiltinFormat_RGBA4444,
|
||||
ImGui_ImplCPU_BuiltinFormat_RGB888,
|
||||
ImGui_ImplCPU_BuiltinFormat_BGR888
|
||||
};
|
||||
const char* builtin_names[] =
|
||||
{
|
||||
"RGBA8888",
|
||||
"BGRA8888",
|
||||
"ARGB8888",
|
||||
"ABGR8888",
|
||||
"RGB565",
|
||||
"ARGB1555",
|
||||
"RGBA4444",
|
||||
"RGB888",
|
||||
"BGR888"
|
||||
};
|
||||
const int builtin_tolerance[] =
|
||||
{
|
||||
0, 0, 0, 0, 8, 8, 17, 0, 0
|
||||
};
|
||||
const bool builtin_ignore_alpha[] =
|
||||
{
|
||||
false, false, false, false, true, false, false, true, true
|
||||
};
|
||||
|
||||
ImGui_ImplCPU_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
Validation_BuildMainScene(&image_texture);
|
||||
ImGui::Render();
|
||||
if (!Validation_RenderInto(&reference, ImGui::GetDrawData()))
|
||||
return 1;
|
||||
|
||||
for (int i = 0; i < IM_ARRAYSIZE(builtin_formats); i++)
|
||||
{
|
||||
ValidationBuffer candidate;
|
||||
Validation_InitBuffer(&candidate, 512, 320, ImGui_ImplCPU_GetBuiltinPixelFormat(builtin_formats[i]));
|
||||
Validation_RenderInto(&candidate, ImGui::GetDrawData());
|
||||
if (!Validation_CompareBuffers(builtin_names[i], reference, candidate, builtin_tolerance[i], builtin_tolerance[i], builtin_ignore_alpha[i]))
|
||||
return 1;
|
||||
}
|
||||
|
||||
ValidationBuffer palette_reference;
|
||||
Validation_InitBuffer(&palette_reference, 512, 320, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_RGBA8888));
|
||||
ValidationBuffer palette_candidate;
|
||||
Validation_InitIndexedBuffer(&palette_candidate, 512, 320);
|
||||
|
||||
ImGui_ImplCPU_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
Validation_BuildPaletteScene();
|
||||
ImGui::Render();
|
||||
Validation_RenderInto(&palette_reference, ImGui::GetDrawData());
|
||||
Validation_RenderInto(&palette_candidate, ImGui::GetDrawData());
|
||||
if (!Validation_CompareBuffers("Indexed8", palette_reference, palette_candidate, 0, 0, false))
|
||||
return 1;
|
||||
|
||||
ImGui_ImplCPU_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
printf("imgui_impl_cpu validation passed.\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user