Integrate the MicroProfile profiling library

This brings goodies such as a configurable user interface and
multi-threaded timeline view.
master
Yuri Kunde Schlesner 2015-08-17 18:25:21 +07:00
parent c7745408f7
commit 0fcabd2b11
24 changed files with 11142 additions and 0 deletions

@ -213,6 +213,7 @@ set(INI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/inih")
include_directories(${INI_PREFIX})
add_subdirectory(${INI_PREFIX})
include_directories(externals/microprofile)
include_directories(externals/nihstro/include)
if (MSVC)

@ -0,0 +1,7 @@
# microprofile
MicroProfile is a embeddable profiler in a single file, written in C++
It can display profile information in the application, or by generating captures via a minimal built in webserver.
For more information see the project webpage at https://bitbucket.org/jonasmeyer/microprofile

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -6,6 +6,9 @@
#include <thread>
#include <iostream>
// This needs to be included before getopt.h because the latter #defines symbols used by it
#include "common/microprofile.h"
#ifdef _MSC_VER
#include <getopt.h>
#else
@ -59,6 +62,8 @@ int main(int argc, char **argv) {
Log::Filter log_filter(Log::Level::Debug);
Log::SetFilter(&log_filter);
MicroProfileOnThreadCreate("EmuThread");
if (boot_filename.empty()) {
LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
return -1;
@ -89,5 +94,7 @@ int main(int argc, char **argv) {
delete emu_window;
MicroProfileShutdown();
return 0;
}

@ -14,6 +14,7 @@
#include "common/string_util.h"
#include "common/scm_rev.h"
#include "common/key_map.h"
#include "common/microprofile.h"
#include "core/core.h"
#include "core/settings.h"
@ -37,6 +38,8 @@ EmuThread::EmuThread(GRenderWindow* render_window) :
void EmuThread::run() {
render_window->MakeCurrent();
MicroProfileOnThreadCreate("EmuThread");
stop_run = false;
// holds whether the cpu was running during the last iteration,
@ -69,6 +72,8 @@ void EmuThread::run() {
}
}
MicroProfileOnThreadExit();
render_window->moveContext();
}

@ -2,9 +2,21 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QMouseEvent>
#include <QPainter>
#include <QString>
#include "profiler.h"
#include "citra_qt/util/util.h"
#include "common/profiler_reporting.h"
#include "common/microprofile.h"
// Include the implementation of the UI in this file. This isn't in microprofile.cpp because the
// non-Qt frontends don't need it (and don't implement the UI drawing hooks either).
#define MICROPROFILEUI_IMPL 1
#include "common/microprofileui.h"
using namespace Common::Profiling;
@ -136,3 +148,193 @@ void ProfilerWidget::setProfilingInfoUpdateEnabled(bool enable)
update_timer.stop();
}
}
class MicroProfileWidget : public QWidget {
public:
MicroProfileWidget(QWidget* parent = 0);
protected:
void paintEvent(QPaintEvent* ev) override;
void showEvent(QShowEvent* ev) override;
void hideEvent(QHideEvent* ev) override;
void mouseMoveEvent(QMouseEvent* ev) override;
void mousePressEvent(QMouseEvent* ev) override;
void mouseReleaseEvent(QMouseEvent* ev) override;
void wheelEvent(QWheelEvent* ev) override;
void keyPressEvent(QKeyEvent* ev) override;
void keyReleaseEvent(QKeyEvent* ev) override;
private:
/// This timer is used to redraw the widget's contents continuously. To save resources, it only
/// runs while the widget is visible.
QTimer update_timer;
};
MicroProfileDialog::MicroProfileDialog(QWidget* parent)
: QWidget(parent, Qt::Dialog)
{
setObjectName("MicroProfile");
setWindowTitle(tr("MicroProfile"));
resize(1000, 600);
// Remove the "?" button from the titlebar and enable the maximize button
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::WindowMaximizeButtonHint);
MicroProfileWidget* widget = new MicroProfileWidget(this);
QLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(widget);
setLayout(layout);
// Configure focus so that widget is focusable and the dialog automatically forwards focus to it.
setFocusProxy(widget);
widget->setFocusPolicy(Qt::StrongFocus);
widget->setFocus();
}
QAction* MicroProfileDialog::toggleViewAction() {
if (toggle_view_action == nullptr) {
toggle_view_action = new QAction(windowTitle(), this);
toggle_view_action->setCheckable(true);
toggle_view_action->setChecked(isVisible());
connect(toggle_view_action, SIGNAL(toggled(bool)), SLOT(setVisible(bool)));
}
return toggle_view_action;
}
void MicroProfileDialog::showEvent(QShowEvent* ev) {
if (toggle_view_action) {
toggle_view_action->setChecked(isVisible());
}
QWidget::showEvent(ev);
}
void MicroProfileDialog::hideEvent(QHideEvent* ev) {
if (toggle_view_action) {
toggle_view_action->setChecked(isVisible());
}
QWidget::hideEvent(ev);
}
/// There's no way to pass a user pointer to MicroProfile, so this variable is used to make the
/// QPainter available inside the drawing callbacks.
static QPainter* mp_painter = nullptr;
MicroProfileWidget::MicroProfileWidget(QWidget* parent) : QWidget(parent) {
// Send mouse motion events even when not dragging.
setMouseTracking(true);
MicroProfileSetDisplayMode(1); // Timers screen
MicroProfileInitUI();
connect(&update_timer, SIGNAL(timeout()), SLOT(update()));
}
void MicroProfileWidget::paintEvent(QPaintEvent* ev) {
QPainter painter(this);
painter.setBackground(Qt::black);
painter.eraseRect(rect());
QFont font = GetMonospaceFont();
font.setPixelSize(MICROPROFILE_TEXT_HEIGHT);
painter.setFont(font);
mp_painter = &painter;
MicroProfileDraw(rect().width(), rect().height());
mp_painter = nullptr;
}
void MicroProfileWidget::showEvent(QShowEvent* ev) {
update_timer.start(15); // ~60 Hz
QWidget::showEvent(ev);
}
void MicroProfileWidget::hideEvent(QHideEvent* ev) {
update_timer.stop();
QWidget::hideEvent(ev);
}
void MicroProfileWidget::mouseMoveEvent(QMouseEvent* ev) {
MicroProfileMousePosition(ev->x(), ev->y(), 0);
ev->accept();
}
void MicroProfileWidget::mousePressEvent(QMouseEvent* ev) {
MicroProfileMousePosition(ev->x(), ev->y(), 0);
MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton);
ev->accept();
}
void MicroProfileWidget::mouseReleaseEvent(QMouseEvent* ev) {
MicroProfileMousePosition(ev->x(), ev->y(), 0);
MicroProfileMouseButton(ev->buttons() & Qt::LeftButton, ev->buttons() & Qt::RightButton);
ev->accept();
}
void MicroProfileWidget::wheelEvent(QWheelEvent* ev) {
MicroProfileMousePosition(ev->x(), ev->y(), ev->delta() / 120);
ev->accept();
}
void MicroProfileWidget::keyPressEvent(QKeyEvent* ev) {
if (ev->key() == Qt::Key_Control) {
// Inform MicroProfile that the user is holding Ctrl.
MicroProfileModKey(1);
}
QWidget::keyPressEvent(ev);
}
void MicroProfileWidget::keyReleaseEvent(QKeyEvent* ev) {
if (ev->key() == Qt::Key_Control) {
MicroProfileModKey(0);
}
QWidget::keyReleaseEvent(ev);
}
// These functions are called by MicroProfileDraw to draw the interface elements on the screen.
void MicroProfileDrawText(int x, int y, u32 hex_color, const char* text, u32 text_length) {
// hex_color does not include an alpha, so it must be assumed to be 255
mp_painter->setPen(QColor::fromRgb(hex_color));
// It's impossible to draw a string using a monospaced font with a fixed width per cell in a
// way that's reliable across different platforms and fonts as far as I (yuriks) can tell, so
// draw each character individually in order to precisely control the text advance.
for (u32 i = 0; i < text_length; ++i) {
// Position the text baseline 1 pixel above the bottom of the text cell, this gives nice
// vertical alignment of text for a wide range of tested fonts.
mp_painter->drawText(x, y + MICROPROFILE_TEXT_HEIGHT - 2, QChar(text[i]));
x += MICROPROFILE_TEXT_WIDTH + 1;
}
}
void MicroProfileDrawBox(int left, int top, int right, int bottom, u32 hex_color, MicroProfileBoxType type) {
QColor color = QColor::fromRgba(hex_color);
QBrush brush = color;
if (type == MicroProfileBoxTypeBar) {
QLinearGradient gradient(left, top, left, bottom);
gradient.setColorAt(0.f, color.lighter(125));
gradient.setColorAt(1.f, color.darker(125));
brush = gradient;
}
mp_painter->fillRect(left, top, right - left, bottom - top, brush);
}
void MicroProfileDrawLine2D(u32 vertices_length, float* vertices, u32 hex_color) {
// Temporary vector used to convert between the float array and QPointF. Marked static to reuse
// the allocation across calls.
static std::vector<QPointF> point_buf;
for (u32 i = 0; i < vertices_length; ++i) {
point_buf.emplace_back(vertices[i*2 + 0], vertices[i*2 + 1]);
}
// hex_color does not include an alpha, so it must be assumed to be 255
mp_painter->setPen(QColor::fromRgb(hex_color));
mp_painter->drawPolyline(point_buf.data(), vertices_length);
point_buf.clear();
}

@ -48,3 +48,20 @@ private:
QTimer update_timer;
};
class MicroProfileDialog : public QWidget {
Q_OBJECT
public:
MicroProfileDialog(QWidget* parent = 0);
/// Returns a QAction that can be used to toggle visibility of this dialog.
QAction* toggleViewAction();
protected:
void showEvent(QShowEvent* ev) override;
void hideEvent(QHideEvent* ev) override;
private:
QAction* toggle_view_action = nullptr;
};

@ -17,6 +17,7 @@
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/make_unique.h"
#include "common/microprofile.h"
#include "common/platform.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
@ -64,6 +65,9 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
addDockWidget(Qt::BottomDockWidgetArea, profilerWidget);
profilerWidget->hide();
microProfileDialog = new MicroProfileDialog(this);
microProfileDialog->hide();
disasmWidget = new DisassemblerWidget(this, emu_thread.get());
addDockWidget(Qt::BottomDockWidgetArea, disasmWidget);
disasmWidget->hide();
@ -102,6 +106,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
debug_menu->addAction(profilerWidget->toggleViewAction());
debug_menu->addAction(microProfileDialog->toggleViewAction());
debug_menu->addAction(disasmWidget->toggleViewAction());
debug_menu->addAction(registersWidget->toggleViewAction());
debug_menu->addAction(callstackWidget->toggleViewAction());
@ -128,6 +133,8 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
restoreGeometry(settings.value("geometry").toByteArray());
restoreState(settings.value("state").toByteArray());
render_window->restoreGeometry(settings.value("geometryRenderWindow").toByteArray());
microProfileDialog->restoreGeometry(settings.value("microProfileDialogGeometry").toByteArray());
microProfileDialog->setVisible(settings.value("microProfileDialogVisible").toBool());
ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer);
SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked());
@ -434,6 +441,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
settings.setValue("geometry", saveGeometry());
settings.setValue("state", saveState());
settings.setValue("geometryRenderWindow", render_window->saveGeometry());
settings.setValue("microProfileDialogGeometry", microProfileDialog->saveGeometry());
settings.setValue("microProfileDialogVisible", microProfileDialog->isVisible());
settings.setValue("singleWindowMode", ui.action_Single_Window_Mode->isChecked());
settings.setValue("displayTitleBars", ui.actionDisplay_widget_title_bars->isChecked());
settings.setValue("firstStart", false);
@ -456,6 +465,11 @@ int main(int argc, char* argv[]) {
Log::Filter log_filter(Log::Level::Info);
Log::SetFilter(&log_filter);
MicroProfileOnThreadCreate("Frontend");
SCOPE_EXIT({
MicroProfileShutdown();
});
// Init settings params
QSettings::setDefaultFormat(QSettings::IniFormat);
QCoreApplication::setOrganizationName("Citra team");

@ -14,6 +14,7 @@ class GImageInfo;
class GRenderWindow;
class EmuThread;
class ProfilerWidget;
class MicroProfileDialog;
class DisassemblerWidget;
class RegistersWidget;
class CallstackWidget;
@ -104,6 +105,7 @@ private:
std::unique_ptr<EmuThread> emu_thread;
ProfilerWidget* profilerWidget;
MicroProfileDialog* microProfileDialog;
DisassemblerWidget* disasmWidget;
RegistersWidget* registersWidget;
CallstackWidget* callstackWidget;

@ -11,6 +11,7 @@ set(SRCS
logging/text_formatter.cpp
logging/backend.cpp
memory_util.cpp
microprofile.cpp
misc.cpp
profiler.cpp
scm_rev.cpp
@ -43,6 +44,8 @@ set(HEADERS
make_unique.h
math_util.h
memory_util.h
microprofile.h
microprofileui.h
platform.h
profiler.h
profiler_reporting.h

@ -0,0 +1,7 @@
// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// Includes the MicroProfile implementation in this file for compilation
#define MICROPROFILE_IMPL 1
#include "common/microprofile.h"

@ -0,0 +1,25 @@
// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
// Customized Citra settings.
// This file wraps the MicroProfile header so that these are consistent everywhere.
#define MICROPROFILE_WEBSERVER 0
#define MICROPROFILE_GPU_TIMERS 0 // TODO: Implement timer queries when we upgrade to OpenGL 3.3
#define MICROPROFILE_CONTEXT_SWITCH_TRACE 0
#define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048<<12) // 8 MB
#include <microprofile.h>
#define MP_RGB(r, g, b) ((r) << 16 | (g) << 8 | (b) << 0)
// On OS X, some Mach header included by MicroProfile defines these as macros, conflicting with
// identifiers we use.
#ifdef PAGE_SIZE
#undef PAGE_SIZE
#endif
#ifdef PAGE_MASK
#undef PAGE_MASK
#endif

@ -0,0 +1,16 @@
// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/microprofile.h"
// Customized Citra settings.
// This file wraps the MicroProfile header so that these are consistent everywhere.
#define MICROPROFILE_TEXT_WIDTH 6
#define MICROPROFILE_TEXT_HEIGHT 12
#define MICROPROFILE_HELP_ALT "Right-Click"
#define MICROPROFILE_HELP_MOD "Ctrl"
#include <microprofileui.h>

@ -9,6 +9,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/profiler.h"
#include "core/memory.h"
@ -3522,8 +3523,11 @@ enum {
FETCH_EXCEPTION
};
MICROPROFILE_DEFINE(DynCom_Decode, "DynCom", "Decode", MP_RGB(255, 64, 64));
static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) {
Common::Profiling::ScopeTimer timer_decode(profile_decode);
MICROPROFILE_SCOPE(DynCom_Decode);
// Decode instruction, get index
// Allocate memory and init InsCream
@ -3588,8 +3592,11 @@ static int clz(unsigned int x) {
return n;
}
MICROPROFILE_DEFINE(DynCom_Execute, "DynCom", "Execute", MP_RGB(255, 0, 0));
unsigned InterpreterMainLoop(ARMul_State* cpu) {
Common::Profiling::ScopeTimer timer_execute(profile_execute);
MICROPROFILE_SCOPE(DynCom_Execute);
#undef RM
#undef RS

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/bit_field.h"
#include "common/microprofile.h"
#include "core/memory.h"
#include "core/hle/kernel/event.h"
@ -229,6 +230,10 @@ void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
if (Pica::g_debug_context)
Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
if (screen_id == 0) {
MicroProfileFlip();
}
}
/**

@ -5,6 +5,7 @@
#include <map>
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/profiler.h"
#include "common/string_util.h"
#include "common/symbols.h"
@ -969,8 +970,11 @@ static const FunctionDef* GetSVCInfo(u32 func_num) {
return &SVC_Table[func_num];
}
MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
void CallSVC(u32 immediate) {
Common::Profiling::ScopeTimer timer_svc(profiler_svc);
MICROPROFILE_SCOPE(Kernel_SVC);
const FunctionDef* info = GetSVCInfo(immediate);
if (info) {

@ -9,6 +9,7 @@
#include "common/color.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/vector_math.h"
#include "core/settings.h"
@ -85,6 +86,9 @@ static Math::Vec4<u8> DecodePixel(Regs::PixelFormat input_format, const u8* src_
}
}
MICROPROFILE_DEFINE(GPU_DisplayTransfer, "GPU", "DisplayTransfer", MP_RGB(100, 100, 255));
MICROPROFILE_DEFINE(GPU_CmdlistProcessing, "GPU", "Cmdlist Processing", MP_RGB(100, 255, 100));
template <typename T>
inline void Write(u32 addr, const T data) {
addr -= HW::VADDR_GPU;
@ -150,6 +154,8 @@ inline void Write(u32 addr, const T data) {
case GPU_REG_INDEX(display_transfer_config.trigger):
{
MICROPROFILE_SCOPE(GPU_DisplayTransfer);
const auto& config = g_regs.display_transfer_config;
if (config.trigger & 1) {
@ -344,6 +350,8 @@ inline void Write(u32 addr, const T data) {
const auto& config = g_regs.command_processor_config;
if (config.trigger & 1)
{
MICROPROFILE_SCOPE(GPU_CmdlistProcessing);
u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress());
if (Pica::g_debug_context && Pica::g_debug_context->recorder) {

@ -4,6 +4,7 @@
#include <boost/range/algorithm/fill.hpp>
#include "common/microprofile.h"
#include "common/profiler.h"
#include "core/hle/service/gsp_gpu.h"
@ -43,6 +44,8 @@ static const u32 expand_bits_to_bytes[] = {
0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
};
MICROPROFILE_DEFINE(GPU_Drawing, "GPU", "Drawing", MP_RGB(50, 50, 240));
static void WritePicaReg(u32 id, u32 value, u32 mask) {
auto& regs = g_state.regs;
@ -126,6 +129,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
case PICA_REG_INDEX(trigger_draw_indexed):
{
Common::Profiling::ScopeTimer scope_timer(category_drawing);
MICROPROFILE_SCOPE(GPU_Drawing);
#if PICA_LOG_TEV
DebugUtils::DumpTevStageConfig(regs.GetTevStages());

@ -7,6 +7,7 @@
#include "common/color.h"
#include "common/common_types.h"
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/profiler.h"
#include "core/hw/gpu.h"
@ -267,6 +268,7 @@ static int SignedArea (const Math::Vec2<Fix12P4>& vtx1,
};
static Common::Profiling::TimingCategory rasterization_category("Rasterization");
MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240));
/**
* Helper function for ProcessTriangle with the "reversed" flag to allow for implementing
@ -279,6 +281,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
{
const auto& regs = g_state.regs;
Common::Profiling::ScopeTimer timer(rasterization_category);
MICROPROFILE_SCOPE(GPU_Rasterization);
// vertex positions in rasterizer coordinates
static auto FloatToFix = [](float24 flt) {

@ -7,6 +7,7 @@
#include "common/color.h"
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/profiler.h"
#include "core/hw/gpu.h"
@ -777,12 +778,16 @@ void RasterizerOpenGL::SyncDrawState() {
state.Apply();
}
MICROPROFILE_DEFINE(OpenGL_FramebufferReload, "OpenGL", "FB Reload", MP_RGB(70, 70, 200));
void RasterizerOpenGL::ReloadColorBuffer() {
u8* color_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetColorBufferPhysicalAddress());
if (color_buffer == nullptr)
return;
MICROPROFILE_SCOPE(OpenGL_FramebufferReload);
u32 bytes_per_pixel = Pica::Regs::BytesPerColorPixel(fb_color_texture.format);
std::unique_ptr<u8[]> temp_fb_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]);
@ -822,6 +827,8 @@ void RasterizerOpenGL::ReloadDepthBuffer() {
if (depth_buffer == nullptr)
return;
MICROPROFILE_SCOPE(OpenGL_FramebufferReload);
u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format);
// OpenGL needs 4 bpp alignment for D24
@ -868,6 +875,7 @@ void RasterizerOpenGL::ReloadDepthBuffer() {
}
Common::Profiling::TimingCategory buffer_commit_category("Framebuffer Commit");
MICROPROFILE_DEFINE(OpenGL_FramebufferCommit, "OpenGL", "FB Commit", MP_RGB(70, 70, 200));
void RasterizerOpenGL::CommitColorBuffer() {
if (last_fb_color_addr != 0) {
@ -875,6 +883,7 @@ void RasterizerOpenGL::CommitColorBuffer() {
if (color_buffer != nullptr) {
Common::Profiling::ScopeTimer timer(buffer_commit_category);
MICROPROFILE_SCOPE(OpenGL_FramebufferCommit);
u32 bytes_per_pixel = Pica::Regs::BytesPerColorPixel(fb_color_texture.format);
@ -911,6 +920,7 @@ void RasterizerOpenGL::CommitDepthBuffer() {
if (depth_buffer != nullptr) {
Common::Profiling::ScopeTimer timer(buffer_commit_category);
MICROPROFILE_SCOPE(OpenGL_FramebufferCommit);
u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format);

@ -4,6 +4,7 @@
#include "common/make_unique.h"
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/vector_math.h"
#include "core/memory.h"
@ -16,6 +17,8 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
FullFlush();
}
MICROPROFILE_DEFINE(OpenGL_TextureUpload, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned texture_unit, const Pica::Regs::FullTextureConfig& config) {
PAddr texture_addr = config.config.GetPhysicalAddress();
@ -25,6 +28,8 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned text
state.texture_units[texture_unit].texture_2d = cached_texture->second->texture.handle;
state.Apply();
} else {
MICROPROFILE_SCOPE(OpenGL_TextureUpload);
std::unique_ptr<CachedTexture> new_texture = Common::make_unique<CachedTexture>();
new_texture->texture.Create();

@ -9,6 +9,7 @@
#include "common/hash.h"
#include "common/make_unique.h"
#include "common/microprofile.h"
#include "common/profiler.h"
#include "video_core/debug_utils/debug_utils.h"
@ -55,11 +56,13 @@ void Shutdown() {
}
static Common::Profiling::TimingCategory shader_category("Vertex Shader");
MICROPROFILE_DEFINE(GPU_VertexShader, "GPU", "Vertex Shader", MP_RGB(50, 50, 240));
OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attributes) {
auto& config = g_state.regs.vs;
Common::Profiling::ScopeTimer timer(shader_category);
MICROPROFILE_SCOPE(GPU_VertexShader);
state.program_counter = config.main_offset;
state.debug.max_offset = 0;