From f3e4211226c379c546de38d15e97083da2e322f5 Mon Sep 17 00:00:00 2001 From: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com> Date: Thu, 11 Nov 2021 14:30:56 +0300 Subject: [PATCH] Improved frame time diagnostic tool. Split overdraw palette from frame time tool. --- SpaceCadetPinball/gdrv.cpp | 70 ++++++++++++++++++---- SpaceCadetPinball/gdrv.h | 14 ++++- SpaceCadetPinball/render.cpp | 48 +++------------ SpaceCadetPinball/render.h | 2 - SpaceCadetPinball/winmain.cpp | 110 +++++++++++++++++++++------------- SpaceCadetPinball/winmain.h | 5 +- 6 files changed, 150 insertions(+), 99 deletions(-) diff --git a/SpaceCadetPinball/gdrv.cpp b/SpaceCadetPinball/gdrv.cpp index 02d65c3..c808db7 100644 --- a/SpaceCadetPinball/gdrv.cpp +++ b/SpaceCadetPinball/gdrv.cpp @@ -111,6 +111,44 @@ void gdrv_bitmap8::ScaleIndexed(float scaleX, float scaleY) BmpBufPtr1 = new ColorRgba[Stride * Height]; } +void gdrv_bitmap8::CreateTexture(const char* scaleHint, int access) +{ + if (Texture != nullptr) + { + SDL_DestroyTexture(Texture); + } + + UsingSdlHint hint{ SDL_HINT_RENDER_SCALE_QUALITY, scaleHint }; + Texture = SDL_CreateTexture + ( + winmain::Renderer, + SDL_PIXELFORMAT_ARGB8888, + access, + Width, Height + ); + SDL_SetTextureBlendMode(Texture, SDL_BLENDMODE_NONE); +} + +void gdrv_bitmap8::BlitToTexture() +{ + assertm(Texture, "Updating null texture"); + int pitch = 0; + ColorRgba* lockedPixels; + auto result = SDL_LockTexture + ( + Texture, + nullptr, + reinterpret_cast(&lockedPixels), + &pitch + ); + assertm(result == 0, "Updating non-streaming texture"); + assertm(static_cast(pitch) == Width * sizeof(ColorRgba), "Padding on vScreen texture"); + + std::memcpy(lockedPixels, BmpBufPtr1, Width * Height * sizeof(ColorRgba)); + + SDL_UnlockTexture(Texture); +} + int gdrv::display_palette(ColorRgba* plt) { const uint32_t sysPaletteColors[] @@ -168,12 +206,16 @@ int gdrv::display_palette(ColorRgba* plt) void gdrv::fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int yOff, uint8_t fillChar) { - auto color = current_palette[fillChar]; + fill_bitmap(bmp, width, height, xOff, yOff, current_palette[fillChar]); +} + +void gdrv::fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int yOff, ColorRgba fillColor) +{ auto bmpPtr = &bmp->BmpBufPtr1[bmp->Width * yOff + xOff]; for (; height > 0; --height) { for (int x = width; x > 0; --x) - *bmpPtr++ = color; + *bmpPtr++ = fillColor; bmpPtr += bmp->Stride - width; } } @@ -213,6 +255,19 @@ void gdrv::copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int heigh } } +void gdrv::ScrollBitmapHorizontal(gdrv_bitmap8* bmp, int xStart) +{ + auto srcPtr = bmp->BmpBufPtr1; + auto startOffset = xStart >= 0 ? 0 : -xStart; + auto endOffset = xStart >= 0 ? xStart : 0; + auto length = bmp->Width - std::abs(xStart); + for (int y = bmp->Height; y > 0; --y) + { + std::memmove(srcPtr + endOffset, srcPtr + startOffset, length * sizeof(ColorRgba)); + srcPtr += bmp->Stride; + } +} + void gdrv::grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6) { @@ -242,13 +297,6 @@ void gdrv::CreatePreview(gdrv_bitmap8& bmp) if (bmp.Texture) return; - auto texture = SDL_CreateTexture - ( - winmain::Renderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STATIC, - bmp.Width, bmp.Height - ); - SDL_UpdateTexture(texture, nullptr, bmp.BmpBufPtr1, bmp.Width * 4); - bmp.Texture = texture; + bmp.CreateTexture("nearest", SDL_TEXTUREACCESS_STATIC); + SDL_UpdateTexture(bmp.Texture, nullptr, bmp.BmpBufPtr1, bmp.Width * 4); } diff --git a/SpaceCadetPinball/gdrv.h b/SpaceCadetPinball/gdrv.h index 4d2d51f..6099b17 100644 --- a/SpaceCadetPinball/gdrv.h +++ b/SpaceCadetPinball/gdrv.h @@ -19,14 +19,20 @@ struct Rgba union ColorRgba { + static constexpr ColorRgba Black() { return ColorRgba{ Rgba{0, 0, 0, 255} }; } + static constexpr ColorRgba White() { return ColorRgba{ Rgba{255, 255, 255, 255} }; } + static constexpr ColorRgba Red() { return ColorRgba{ Rgba{0, 0, 255, 255} }; } + static constexpr ColorRgba Green() { return ColorRgba{ Rgba{0, 255,0, 255} }; } + static constexpr ColorRgba Blue() { return ColorRgba{ Rgba{255, 0, 0, 255} }; } + ColorRgba() = default; - explicit ColorRgba(uint32_t color) + explicit constexpr ColorRgba(uint32_t color) : Color(color) { } - explicit ColorRgba(Rgba rgba) + explicit constexpr ColorRgba(Rgba rgba) : rgba(rgba) { } @@ -43,6 +49,8 @@ struct gdrv_bitmap8 gdrv_bitmap8(const struct dat8BitBmpHeader& header); ~gdrv_bitmap8(); void ScaleIndexed(float scaleX, float scaleY); + void CreateTexture(const char* scaleHint, int access); + void BlitToTexture(); ColorRgba* BmpBufPtr1; char* IndexedBmpPtr; int Width; @@ -62,10 +70,12 @@ class gdrv public: static int display_palette(ColorRgba* plt); static void fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int yOff, uint8_t fillChar); + static void fill_bitmap(gdrv_bitmap8* bmp, int width, int height, int xOff, int yOff, ColorRgba fillColor); static void copy_bitmap(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff, gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff); static void copy_bitmap_w_transparency(gdrv_bitmap8* dstBmp, int width, int height, int xOff, int yOff, gdrv_bitmap8* srcBmp, int srcXOff, int srcYOff); + static void ScrollBitmapHorizontal(gdrv_bitmap8* bmp, int xStart); static void grtext_draw_ttext_in_box(LPCSTR text, int xOff, int yOff, int width, int height, int a6); static void ApplyPalette(gdrv_bitmap8& bmp); static void CreatePreview(gdrv_bitmap8& bmp); diff --git a/SpaceCadetPinball/render.cpp b/SpaceCadetPinball/render.cpp index cd9bae6..432576f 100644 --- a/SpaceCadetPinball/render.cpp +++ b/SpaceCadetPinball/render.cpp @@ -16,7 +16,6 @@ float render::zscaler, render::zmin, render::zmax; rectangle_type render::vscreen_rect; gdrv_bitmap8 *render::vscreen, *render::background_bitmap, *render::ball_bitmap[20]; zmap_header_type* render::zscreen; -SDL_Texture* render::vScreenTex = nullptr; SDL_Rect render::DestinationRect{}; void render::init(gdrv_bitmap8* bmp, float zMin, float zScaler, int width, int height) @@ -58,26 +57,11 @@ void render::uninit() ball_list.clear(); dirty_list.clear(); sprite_list.clear(); - SDL_DestroyTexture(vScreenTex); - vScreenTex = nullptr; } void render::recreate_screen_texture() { - if (vScreenTex != nullptr) - { - SDL_DestroyTexture(vScreenTex); - } - - UsingSdlHint hint{ SDL_HINT_RENDER_SCALE_QUALITY, options::Options.LinearFiltering ? "linear" : "nearest" }; - vScreenTex = SDL_CreateTexture - ( - winmain::Renderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, - vscreen_rect.Width, vscreen_rect.Height - ); - SDL_SetTextureBlendMode(vScreenTex, SDL_BLENDMODE_NONE); + vscreen->CreateTexture(options::Options.LinearFiltering ? "linear" : "nearest", SDL_TEXTUREACCESS_STREAMING); } void render::update() @@ -535,31 +519,13 @@ void render::SpriteViewer(bool* show) ImGui::End(); } -void render::BlitVScreen() -{ - int pitch = 0; - ColorRgba* lockedPixels; - SDL_LockTexture - ( - vScreenTex, - nullptr, - reinterpret_cast(&lockedPixels), - &pitch - ); - assertm(static_cast(pitch) == vscreen->Width * sizeof(ColorRgba), "Padding on vScreen texture"); - - std::memcpy(lockedPixels, vscreen->BmpBufPtr1, vscreen->Width * vscreen->Height * sizeof(ColorRgba)); - - SDL_UnlockTexture(vScreenTex); -} - void render::PresentVScreen() { - BlitVScreen(); + vscreen->BlitToTexture(); if (offset_x == 0 && offset_y == 0) { - SDL_RenderCopy(winmain::Renderer, vScreenTex, nullptr, &DestinationRect); + SDL_RenderCopy(winmain::Renderer, vscreen->Texture, nullptr, &DestinationRect); } else { @@ -591,8 +557,8 @@ void render::PresentVScreen() DestinationRect.w - dstSeparationX, static_cast(DestinationRect.h) }; - SDL_RenderCopyF(winmain::Renderer, vScreenTex, &srcBoardRect, &dstBoardRect); - SDL_RenderCopyF(winmain::Renderer, vScreenTex, &srcSidebarRect, &dstSidebarRect); + SDL_RenderCopyF(winmain::Renderer, vscreen->Texture, &srcBoardRect, &dstBoardRect); + SDL_RenderCopyF(winmain::Renderer, vscreen->Texture, &srcSidebarRect, &dstSidebarRect); #else // SDL_RenderCopy cannot express sub pixel offset. // Vscreen shift is required for that. @@ -615,8 +581,8 @@ void render::PresentVScreen() DestinationRect.w - dstSeparationX, DestinationRect.h }; - SDL_RenderCopy(winmain::Renderer, vScreenTex, &srcBoardRect, &dstBoardRect); - SDL_RenderCopy(winmain::Renderer, vScreenTex, &srcSidebarRect, &dstSidebarRect); + SDL_RenderCopy(winmain::Renderer, vscreen->Texture, &srcBoardRect, &dstBoardRect); + SDL_RenderCopy(winmain::Renderer, vscreen->Texture, &srcSidebarRect, &dstSidebarRect); #endif } } diff --git a/SpaceCadetPinball/render.h b/SpaceCadetPinball/render.h index 5e66ade..46310b2 100644 --- a/SpaceCadetPinball/render.h +++ b/SpaceCadetPinball/render.h @@ -60,10 +60,8 @@ private: static rectangle_type vscreen_rect; static gdrv_bitmap8 *ball_bitmap[20]; static zmap_header_type* zscreen; - static SDL_Texture* vScreenTex; static void repaint(struct render_sprite_type_struct* sprite); static void paint_balls(); static void unpaint_balls(); - static void BlitVScreen(); }; diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index d77b0aa..8442fc6 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -18,7 +18,7 @@ int winmain::return_value = 0; bool winmain::bQuit = false; bool winmain::activated = false; int winmain::DispFrameRate = 0; -int winmain::DispGRhistory = 0; +bool winmain::DispGRhistory = false; bool winmain::single_step = false; bool winmain::has_focus = true; int winmain::last_mouse_x; @@ -185,7 +185,7 @@ int winmain::WinMain(LPCSTR lpCmdLine) else pb::replay_level(0); - unsigned dtHistoryCounter = 300u, updateCounter = 0, frameCounter = 0; + unsigned updateCounter = 0, frameCounter = 0; auto frameStart = Clock::now(); double UpdateToFrameCounter = 0; @@ -209,36 +209,6 @@ int winmain::WinMain(LPCSTR lpCmdLine) } } - if (DispGRhistory) - { - if (!gfr_display) - { - auto plt = static_cast(malloc(1024u)); - auto pltPtr = &plt[10]; // first 10 entries are system colors hardcoded in display_palette() - for (int i1 = 0, i2 = 0; i1 < 256 - 10; ++i1, i2 += 8) - { - unsigned char blue = i2, redGreen = i2; - if (i2 > 255) - { - blue = 255; - redGreen = i1; - } - - *pltPtr++ = ColorRgba{Rgba{redGreen, redGreen, blue, 0}}; - } - gdrv::display_palette(plt); - free(plt); - gfr_display = new gdrv_bitmap8(400, 15, false); - } - - if (!dtHistoryCounter) - { - dtHistoryCounter = 300; - gdrv::copy_bitmap(render::vscreen, 300, 10, 0, 30, gfr_display, 0, 0); - gdrv::fill_bitmap(gfr_display, 300, 10, 0, 0, 0); - } - } - if (!ProcessWindowMessages() || bQuit) break; @@ -262,18 +232,30 @@ int winmain::WinMain(LPCSTR lpCmdLine) if (!single_step && !no_time_loss) { auto dt = static_cast(frameDuration.count()); - auto dtWhole = static_cast(std::round(dt)); pb::frame(dt); - if (gfr_display) + if (DispGRhistory) { - auto deltaTPal = dtWhole + 10; - auto fillChar = static_cast(deltaTPal); - if (deltaTPal > 236) + auto width = 300; + auto height = 64; + if (!gfr_display) { - fillChar = 1; + gfr_display = new gdrv_bitmap8(width, height, false); + gfr_display->CreateTexture("nearest", SDL_TEXTUREACCESS_STREAMING); } - gdrv::fill_bitmap(gfr_display, 1, 10, 300 - dtHistoryCounter, 0, fillChar); - --dtHistoryCounter; + + gdrv::ScrollBitmapHorizontal(gfr_display, -1); + + auto target = static_cast(TargetFrameTime.count()); + auto scale = height / target / 2; + gdrv::fill_bitmap(gfr_display, 1, height, width - 1, 0, ColorRgba::Black()); // Background + + auto targetVal = dt < target ? dt : target; + auto targetHeight = std::min(static_cast(std::round(targetVal * scale)), width); + gdrv::fill_bitmap(gfr_display, 1, targetHeight, width - 1, height - targetHeight, ColorRgba::White()); // Target + + auto diffVal = dt < target ? target - dt : dt - target; + auto diffHeight = std::min(static_cast(std::round(diffVal * scale)), width); + gdrv::fill_bitmap(gfr_display, 1, diffHeight, width - 1, height - targetHeight - diffHeight, ColorRgba::Red()); // Target diff } updateCounter++; } @@ -327,6 +309,7 @@ int winmain::WinMain(LPCSTR lpCmdLine) } delete gfr_display; + gfr_display = nullptr; options::uninit(); midi::music_shutdown(); pb::uninit(); @@ -561,6 +544,10 @@ void winmain::RenderUi() pause(); ShowSpriteViewer ^= true; } + if (pb::cheat_mode && ImGui::MenuItem("Frame Times", nullptr, DispGRhistory)) + { + DispGRhistory ^= true; + } if (ImGui::BeginMenu("Cheats")) { if (ImGui::MenuItem("hidden test", nullptr, pb::cheat_mode)) @@ -599,6 +586,8 @@ void winmain::RenderUi() if (ShowSpriteViewer) render::SpriteViewer(&ShowSpriteViewer); options::RenderControlDialog(); + if (DispGRhistory) + RenderFrameTimeDialog(); } int winmain::event_handler(const SDL_Event* event) @@ -687,7 +676,26 @@ int winmain::event_handler(const SDL_Event* event) switch (event->key.keysym.sym) { case SDLK_g: - DispGRhistory = 1; + DispGRhistory ^= true; + break; + case SDLK_o: + { + auto plt = new ColorRgba[4 * 256]; + auto pltPtr = &plt[10]; // first 10 entries are system colors hardcoded in display_palette() + for (int i1 = 0, i2 = 0; i1 < 256 - 10; ++i1, i2 += 8) + { + unsigned char blue = i2, redGreen = i2; + if (i2 > 255) + { + blue = 255; + redGreen = i1; + } + + *pltPtr++ = ColorRgba{ Rgba{redGreen, redGreen, blue, 0} }; + } + gdrv::display_palette(plt); + delete[] plt; + } break; case SDLK_y: SDL_SetWindowTitle(MainWindow, "Pinball"); @@ -925,3 +933,23 @@ void winmain::UpdateFrameRate() UpdateToFrameRatio = static_cast(ups) / fps; TargetFrameTime = DurationMs(1000.0 / ups); } + +void winmain::RenderFrameTimeDialog() +{ + if (!gfr_display) + return; + + ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2{ 300, 70 }); + if (ImGui::Begin("Frame Times", &DispGRhistory, ImGuiWindowFlags_NoScrollbar)) + { + auto target = static_cast(TargetFrameTime.count()); + auto scale = 1 / (64 / 2 / target); + + ImGui::Text("Target frame time:%03.04fms, 1px:%03.04fms", target, scale); + gfr_display->BlitToTexture(); + auto region = ImGui::GetContentRegionAvail(); + ImGui::Image(gfr_display->Texture, region); + } + ImGui::End(); + ImGui::PopStyleVar(); +} diff --git a/SpaceCadetPinball/winmain.h b/SpaceCadetPinball/winmain.h index 485232f..c6ab002 100644 --- a/SpaceCadetPinball/winmain.h +++ b/SpaceCadetPinball/winmain.h @@ -63,9 +63,9 @@ public: static bool RestartRequested() { return restart; } static void UpdateFrameRate(); private: - static int return_value, DispFrameRate, DispGRhistory; + static int return_value, DispFrameRate; static int mouse_down, last_mouse_x, last_mouse_y; - static bool no_time_loss, activated, bQuit, has_focus; + static bool no_time_loss, activated, bQuit, has_focus, DispGRhistory; static gdrv_bitmap8* gfr_display; static std::string FpsDetails; static bool restart; @@ -77,4 +77,5 @@ private: static struct optionsStruct& Options; static void RenderUi(); + static void RenderFrameTimeDialog(); };