blob: a571cc274fa5d21b8ab20df51250252b3ba8a78b [file] [log] [blame] [edit]
/*
* Copyright 2022 Rive
*/
#ifndef TESTING_WINDOW_HPP
#define TESTING_WINDOW_HPP
#include "common/offscreen_render_target.hpp"
#include "rive/renderer/gpu.hpp"
#include "rive/refcnt.hpp"
#include <memory>
#include <vector>
#include <string>
namespace rive
{
class Renderer;
class Factory;
namespace gpu
{
class RenderContext;
class RenderContextGLImpl;
class RenderTarget;
class Texture;
class TextureRenderTarget;
} // namespace gpu
}; // namespace rive
// Wraps a factory for rive::Renderer and a singleton target for it to render
// into (GL window, HTML canvas, software buffer, etc.):
//
// TestingWindow::Init(type);
// renderer = TestingWindow::Get()->reset(width, height);
// ...
//
class TestingWindow
{
public:
enum class Backend
{
gl,
d3d,
d3d12,
metal,
vk,
// Vulkan on Metal, aka MoltenVK.
// (defaults to /usr/local/share/vulkan/icd.d/MoltenVK_icd.json if
// VK_ICD_FILENAMES is not set.)
moltenvk,
// Swiftshader, Google's CPU implementation of Vulkan.
// (defaults to ./vk_swiftshader_icd.json if VK_ICD_FILENAMES is not
// set.)
swiftshader,
angle,
dawn,
rhi,
coregraphics,
skia,
null,
};
struct BackendParams
{
bool atomic = false;
bool core = false;
bool msaa = false;
bool srgb = false;
bool clockwise = false;
bool disableValidationLayers = false;
bool disableDebugCallbacks = false;
std::string gpuNameFilter;
};
enum class Visibility
{
headless,
window,
fullscreen,
};
enum class InputEvent
{
KeyPress,
MouseDown,
MouseUp,
MouseMove
};
// Aligns with GLFW's mouse button enum
enum MouseButton : int
{
Left,
Right,
Middle,
// can support more buttons
};
struct InputEventData
{
InputEventData() : InputEventData(InputEvent::KeyPress, '\0') {}
InputEventData(InputEvent type, float posX, float posY) :
eventType(type)
{
metadata = {.posX = posX, .posY = posY};
}
InputEventData(InputEvent type, char c) : eventType(type)
{
metadata = {.key = c};
}
InputEvent eventType;
union
{
struct
{
// Move & down/up mouse press events all have coords
float posX;
float posY;
};
char key;
} metadata;
};
static const char* BackendName(Backend);
static Backend ParseBackend(const char* name, BackendParams*);
static TestingWindow* Init(Backend,
const BackendParams&,
Visibility,
void* platformWindow = nullptr);
static TestingWindow* Get();
static void Set(TestingWindow* inWindow);
static void Destroy();
uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; }
virtual rive::Factory* factory() = 0;
virtual void resize(int width, int height)
{
m_width = width;
m_height = height;
}
struct FrameOptions
{
uint32_t clearColor;
bool doClear = true;
bool forceMSAA = false;
bool disableRasterOrdering = false;
bool wireframe = false;
bool clockwiseFillOverride = false;
rive::gpu::SynthesizedFailureType synthesizedFailureType =
rive::gpu::SynthesizedFailureType::none;
};
virtual std::unique_ptr<rive::Renderer> beginFrame(const FrameOptions&) = 0;
virtual void endFrame(std::vector<uint8_t>* pixelData = nullptr) = 0;
// For testing directly on RenderContext.
virtual rive::gpu::RenderContext* renderContext() const { return nullptr; }
virtual rive::gpu::RenderContextGLImpl* renderContextGLImpl() const
{
return nullptr;
}
virtual rive::gpu::RenderTarget* renderTarget() const { return nullptr; }
// Creates a new render target, for testing offscreen rendering.
// If riveRenderable is false, the texture will lack features required by
// Rive for rendering directly to it (e.g., input attachment, UAV, etc.),
// which will exercise indirect rendering fallbacks.
virtual rive::rcp<rive_tests::OffscreenRenderTarget>
makeOffscreenRenderTarget(uint32_t width,
uint32_t height,
bool riveRenderable) const
{
return nullptr;
}
// For testing render pass breaks. Caller must call
// renderContext()->beginFrame() again.
virtual void flushPLSContext(
rive::gpu::RenderTarget* offscreenRenderTarget = nullptr)
{}
virtual bool consumeInputEvent(InputEventData& eventData) { return false; }
virtual InputEventData waitForInputEvent()
{
fprintf(stderr, "TestingWindow::waitForInputEvent not implemented.");
abort();
}
virtual bool shouldQuit() const { return false; }
virtual void hotloadShaders() {}
virtual ~TestingWindow() {}
static TestingWindow* MakeEGL(Backend,
const BackendParams&,
void* platformWindow);
#if defined(__APPLE__) && !defined(RIVE_UNREAL)
static TestingWindow* MakeMetalTexture();
#endif
static TestingWindow* MakeCoreGraphics();
static TestingWindow* MakeFiddleContext(Backend,
const BackendParams&,
Visibility,
void* platformWindow);
static TestingWindow* MakeVulkanTexture(const BackendParams&);
static TestingWindow* MakeAndroidVulkan(const BackendParams&,
void* platformWindow);
static TestingWindow* MakeSkia();
static TestingWindow* MakeNULL();
protected:
uint32_t m_width = 0;
uint32_t m_height = 0;
};
#endif