mirror of
https://github.com/libretro/parallel-gx1.git
synced 2026-11-11 03:11:28 -10:00
A generator can now build its stage through rslc's builder instead of writing GLSL for the backend to parse: AbstractGfx::CreateShaderFromBuild takes a build function, and each backend asks rslc for its own destination from the built stage - SPIR-V for Vulkan, DXBC at the device's feature level for D3D11 and D3D12, GLSL or GLSL ES at the context's version for OpenGL, MSL for Metal. VideoCommon/ShaderBuild carries the per-backend resource layout the shader headers' macros gave, and builds a stage in the worker's shader arena, again from the start where the arena has to grow. The framebuffer utility stages move first: the screen quad, texture copy, clear and EFB poke vertex stages, the passthrough geometry stages, and the texture copy, color and multisample resolve pixel stages. Each compiles to the same SPIR-V and DXBC words as its GLSL did; the text writers are gone. rslc prints OpenGL's GLSL without bindings, so the OpenGL backend binds blocks, samplers, attributes and outputs by name for every program.
155 lines
5.1 KiB
C++
155 lines
5.1 KiB
C++
// Copyright 2023 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "VideoBackends/Software/SWGfx.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "DolphinLibretro/Common/Globals.h"
|
|
|
|
#include "VideoBackends/Software/EfbCopy.h"
|
|
#include "VideoBackends/Software/Rasterizer.h"
|
|
#include "VideoBackends/Software/SWTexture.h"
|
|
|
|
#include "VideoCommon/AbstractPipeline.h"
|
|
#include "VideoCommon/AbstractShader.h"
|
|
#include "VideoCommon/AbstractTexture.h"
|
|
#include "VideoCommon/NativeVertexFormat.h"
|
|
#include "VideoCommon/Present.h"
|
|
#include "VideoCommon/VideoCommon.h"
|
|
#include "VideoCommon/VideoBackendKind.h"
|
|
|
|
namespace SW
|
|
{
|
|
SWGfx::SWGfx()
|
|
{
|
|
g_video_backend_kind = VIDEO_BACKEND_SOFTWARE;
|
|
}
|
|
|
|
SWGfx::~SWGfx() = default;
|
|
|
|
bool SWGfx::IsHeadless() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool SWGfx::SupportsUtilityDrawing() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
AbstractTexture* SWGfx::CreateTexture(const TextureConfig& config,
|
|
std::string_view /* name */)
|
|
{
|
|
return new SWTexture(config);
|
|
}
|
|
|
|
AbstractStagingTexture* SWGfx::CreateStagingTexture(StagingTextureType type,
|
|
const TextureConfig& config)
|
|
{
|
|
return new SWStagingTexture(type, config);
|
|
}
|
|
|
|
AbstractFramebuffer*
|
|
SWGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment)
|
|
{
|
|
return SWFramebuffer::Create(static_cast<SWTexture*>(color_attachment),
|
|
static_cast<SWTexture*>(depth_attachment));
|
|
}
|
|
|
|
bool SWGfx::BindBackbuffer(const ClearColor& clear_color)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
AbstractShader*
|
|
SWGfx::CreateShaderFromSource(ShaderStage stage, ShaderCode* /* source */,
|
|
std::string_view /* name */)
|
|
{
|
|
return new AbstractShader(stage);
|
|
}
|
|
|
|
AbstractShader* SWGfx::CreateShaderFromBuild(ShaderStage stage, shader_build_fn /* fn */,
|
|
const void* /* arg */, std::string_view /* name */)
|
|
{
|
|
return new AbstractShader(stage);
|
|
}
|
|
|
|
AbstractShader* SWGfx::CreateShaderFromBinary(ShaderStage stage,
|
|
const void* /* data */,
|
|
size_t /* length */,
|
|
std::string_view /* name */)
|
|
{
|
|
return new AbstractShader(stage);
|
|
}
|
|
|
|
AbstractPipeline* SWGfx::CreatePipeline(const AbstractPipelineConfig& config,
|
|
const void* cache_data,
|
|
size_t cache_data_length)
|
|
{
|
|
return new AbstractPipeline();
|
|
}
|
|
|
|
// Called on the GPU thread. The frontend takes the picture in memory, in
|
|
// its XRGB8888 order: one pass from the texture's RGBA8, into a buffer
|
|
// that grows only when the picture does.
|
|
void SWGfx::ShowImage(const AbstractTexture* source_texture,
|
|
const MathUtil::Rectangle<int>& source_rc)
|
|
{
|
|
const SWTexture* texture = static_cast<const SWTexture*>(source_texture);
|
|
const u32 tex_width = texture->GetWidth();
|
|
const u32 tex_height = texture->GetHeight();
|
|
const u32 left = static_cast<u32>(std::clamp(source_rc.left, 0, static_cast<int>(tex_width)));
|
|
const u32 top = static_cast<u32>(std::clamp(source_rc.top, 0, static_cast<int>(tex_height)));
|
|
const u32 right =
|
|
static_cast<u32>(std::clamp(source_rc.right, static_cast<int>(left), static_cast<int>(tex_width)));
|
|
const u32 bottom =
|
|
static_cast<u32>(std::clamp(source_rc.bottom, static_cast<int>(top), static_cast<int>(tex_height)));
|
|
const u32 width = right - left;
|
|
const u32 height = bottom - top;
|
|
if (!width || !height)
|
|
return;
|
|
|
|
if (m_picture.size() < static_cast<size_t>(width) * height)
|
|
m_picture.resize(static_cast<size_t>(width) * height);
|
|
|
|
const u8* src = texture->GetData(0, 0) + (static_cast<size_t>(top) * tex_width + left) * 4;
|
|
u32* dst = m_picture.data();
|
|
for (u32 y = 0; y < height; y++)
|
|
{
|
|
const u8* s = src + static_cast<size_t>(y) * tex_width * 4;
|
|
for (u32 x = 0; x < width; x++, s += 4)
|
|
*dst++ = (static_cast<u32>(s[0]) << 16) | (static_cast<u32>(s[1]) << 8) | s[2];
|
|
}
|
|
|
|
Libretro::Video::video_cb(m_picture.data(), width, height, width * 4);
|
|
}
|
|
|
|
void SWGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool colorEnable,
|
|
bool alphaEnable, bool zEnable, u32 color, u32 z)
|
|
{
|
|
EfbCopy::ClearEfb();
|
|
}
|
|
|
|
NativeVertexFormat*
|
|
SWGfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
|
|
{
|
|
return new NativeVertexFormat(vtx_decl);
|
|
}
|
|
|
|
void SWGfx::SetScissorRect(const MathUtil::Rectangle<int>& rc)
|
|
{
|
|
// BPFunctions calls SetScissorRect with the "best" scissor rect whenever the viewport or scissor
|
|
// changes. However, the software renderer is actually able to use multiple scissor rects (which
|
|
// is necessary in a few rendering edge cases, such as with Major Minor's Majestic March).
|
|
// Thus, we use this as a signal to update the list of scissor rects, but ignore the parameter.
|
|
Rasterizer::ScissorChanged();
|
|
}
|
|
|
|
SurfaceInfo SWGfx::GetSurfaceInfo() const
|
|
{
|
|
return {EFB_WIDTH, EFB_HEIGHT, 1.0f, AbstractTextureFormat::RGBA8};
|
|
}
|
|
|
|
} // namespace SW
|