mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-27 09:12:46 +01:00
commit
a10baacf9e
17 changed files with 591 additions and 296 deletions
|
@ -26,14 +26,13 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
|
||||||
"Drawing from address %lx offset %08X Width %u Height %u Stride %u Format %u", addr,
|
"Drawing from address %lx offset %08X Width %u Height %u Stride %u Format %u", addr,
|
||||||
offset, width, height, stride, format);
|
offset, width, height, stride, format);
|
||||||
|
|
||||||
using PixelFormat = RendererBase::FramebufferInfo::PixelFormat;
|
using PixelFormat = Tegra::FramebufferConfig::PixelFormat;
|
||||||
using Flags = NVFlinger::BufferQueue::BufferTransformFlags;
|
const Tegra::FramebufferConfig framebuffer{
|
||||||
const bool flip_vertical = static_cast<u32>(transform) & static_cast<u32>(Flags::FlipV);
|
addr, offset, width, height, stride, static_cast<PixelFormat>(format), transform};
|
||||||
const RendererBase::FramebufferInfo framebuffer_info{
|
|
||||||
addr, offset, width, height, stride, static_cast<PixelFormat>(format), flip_vertical};
|
|
||||||
|
|
||||||
Core::System::GetInstance().perf_stats.EndGameFrame();
|
Core::System::GetInstance().perf_stats.EndGameFrame();
|
||||||
VideoCore::g_renderer->SwapBuffers(framebuffer_info);
|
|
||||||
|
VideoCore::g_renderer->SwapBuffers(framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Devices
|
} // namespace Devices
|
||||||
|
|
|
@ -47,6 +47,8 @@ public:
|
||||||
~BufferQueue() = default;
|
~BufferQueue() = default;
|
||||||
|
|
||||||
enum class BufferTransformFlags : u32 {
|
enum class BufferTransformFlags : u32 {
|
||||||
|
/// No transform flags are set
|
||||||
|
Unset = 0x00,
|
||||||
/// Flip source image horizontally (around the vertical axis)
|
/// Flip source image horizontally (around the vertical axis)
|
||||||
FlipH = 0x01,
|
FlipH = 0x01,
|
||||||
/// Flip source image vertically (around the horizontal axis)
|
/// Flip source image vertically (around the horizontal axis)
|
||||||
|
|
|
@ -41,6 +41,9 @@ static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, Pa
|
||||||
LOG_DEBUG(HW_Memory, "Mapping %p onto %016" PRIX64 "-%016" PRIX64, memory, base * PAGE_SIZE,
|
LOG_DEBUG(HW_Memory, "Mapping %p onto %016" PRIX64 "-%016" PRIX64, memory, base * PAGE_SIZE,
|
||||||
(base + size) * PAGE_SIZE);
|
(base + size) * PAGE_SIZE);
|
||||||
|
|
||||||
|
RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE,
|
||||||
|
FlushMode::FlushAndInvalidate);
|
||||||
|
|
||||||
VAddr end = base + size;
|
VAddr end = base + size;
|
||||||
while (base != end) {
|
while (base != end) {
|
||||||
ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %016" PRIX64, base);
|
ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %016" PRIX64, base);
|
||||||
|
@ -288,6 +291,43 @@ u8* GetPhysicalPointer(PAddr address) {
|
||||||
return target_pointer;
|
return target_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
|
||||||
|
// Since pages are unmapped on shutdown after video core is shutdown, the renderer may be
|
||||||
|
// null here
|
||||||
|
if (VideoCore::g_renderer == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr end = start + size;
|
||||||
|
|
||||||
|
auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
|
||||||
|
if (start >= region_end || end <= region_start) {
|
||||||
|
// No overlap with region
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr overlap_start = std::max(start, region_start);
|
||||||
|
VAddr overlap_end = std::min(end, region_end);
|
||||||
|
u64 overlap_size = overlap_end - overlap_start;
|
||||||
|
|
||||||
|
auto* rasterizer = VideoCore::g_renderer->Rasterizer();
|
||||||
|
switch (mode) {
|
||||||
|
case FlushMode::Flush:
|
||||||
|
rasterizer->FlushRegion(overlap_start, overlap_size);
|
||||||
|
break;
|
||||||
|
case FlushMode::Invalidate:
|
||||||
|
rasterizer->InvalidateRegion(overlap_start, overlap_size);
|
||||||
|
break;
|
||||||
|
case FlushMode::FlushAndInvalidate:
|
||||||
|
rasterizer->FlushAndInvalidateRegion(overlap_start, overlap_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CheckRegion(PROCESS_IMAGE_VADDR, PROCESS_IMAGE_VADDR_END);
|
||||||
|
CheckRegion(HEAP_VADDR, HEAP_VADDR_END);
|
||||||
|
}
|
||||||
|
|
||||||
u8 Read8(const VAddr addr) {
|
u8 Read8(const VAddr addr) {
|
||||||
return Read<u8>(addr);
|
return Read<u8>(addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,10 @@ enum class PageType : u8 {
|
||||||
Unmapped,
|
Unmapped,
|
||||||
/// Page is mapped to regular memory. This is the only type you can get pointers to.
|
/// Page is mapped to regular memory. This is the only type you can get pointers to.
|
||||||
Memory,
|
Memory,
|
||||||
/// Page is mapped to a memory hook, which intercepts read and write requests.
|
/// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
|
||||||
|
/// invalidation
|
||||||
|
RasterizerCachedMemory,
|
||||||
|
/// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
|
||||||
Special,
|
Special,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -242,4 +245,19 @@ boost::optional<VAddr> PhysicalToVirtualAddress(PAddr addr);
|
||||||
*/
|
*/
|
||||||
u8* GetPhysicalPointer(PAddr address);
|
u8* GetPhysicalPointer(PAddr address);
|
||||||
|
|
||||||
|
enum class FlushMode {
|
||||||
|
/// Write back modified surfaces to RAM
|
||||||
|
Flush,
|
||||||
|
/// Remove region from the cache
|
||||||
|
Invalidate,
|
||||||
|
/// Write back modified surfaces to RAM, and also remove them from the cache
|
||||||
|
FlushAndInvalidate,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes and invalidates any externally cached rasterizer resources touching the given virtual
|
||||||
|
* address region.
|
||||||
|
*/
|
||||||
|
void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode);
|
||||||
|
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "common/assert.h"
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -62,6 +63,107 @@ public:
|
||||||
Fragment = 4,
|
Fragment = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class VertexSize : u32 {
|
||||||
|
Size_32_32_32_32 = 0x01,
|
||||||
|
Size_32_32_32 = 0x02,
|
||||||
|
Size_16_16_16_16 = 0x03,
|
||||||
|
Size_32_32 = 0x04,
|
||||||
|
Size_16_16_16 = 0x05,
|
||||||
|
Size_8_8_8_8 = 0x0a,
|
||||||
|
Size_16_16 = 0x0f,
|
||||||
|
Size_32 = 0x12,
|
||||||
|
Size_8_8_8 = 0x13,
|
||||||
|
Size_8_8 = 0x18,
|
||||||
|
Size_16 = 0x1b,
|
||||||
|
Size_8 = 0x1d,
|
||||||
|
Size_10_10_10_2 = 0x30,
|
||||||
|
Size_11_11_10 = 0x31,
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string VertexSizeToString(VertexSize vertex_size) {
|
||||||
|
switch (vertex_size) {
|
||||||
|
case VertexSize::Size_32_32_32_32:
|
||||||
|
return "32_32_32_32";
|
||||||
|
case VertexSize::Size_32_32_32:
|
||||||
|
return "32_32_32";
|
||||||
|
case VertexSize::Size_16_16_16_16:
|
||||||
|
return "16_16_16_16";
|
||||||
|
case VertexSize::Size_32_32:
|
||||||
|
return "32_32";
|
||||||
|
case VertexSize::Size_16_16_16:
|
||||||
|
return "16_16_16";
|
||||||
|
case VertexSize::Size_8_8_8_8:
|
||||||
|
return "8_8_8_8";
|
||||||
|
case VertexSize::Size_16_16:
|
||||||
|
return "16_16";
|
||||||
|
case VertexSize::Size_32:
|
||||||
|
return "32";
|
||||||
|
case VertexSize::Size_8_8_8:
|
||||||
|
return "8_8_8";
|
||||||
|
case VertexSize::Size_8_8:
|
||||||
|
return "8_8";
|
||||||
|
case VertexSize::Size_16:
|
||||||
|
return "16";
|
||||||
|
case VertexSize::Size_8:
|
||||||
|
return "8";
|
||||||
|
case VertexSize::Size_10_10_10_2:
|
||||||
|
return "10_10_10_2";
|
||||||
|
case VertexSize::Size_11_11_10:
|
||||||
|
return "11_11_10";
|
||||||
|
}
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class VertexType : u32 {
|
||||||
|
SignedNorm = 1,
|
||||||
|
UnsignedNorm = 2,
|
||||||
|
SignedInt = 3,
|
||||||
|
UnsignedInt = 4,
|
||||||
|
UnsignedScaled = 5,
|
||||||
|
SignedScaled = 6,
|
||||||
|
Float = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string VertexTypeToString(VertexType vertex_type) {
|
||||||
|
switch (vertex_type) {
|
||||||
|
case VertexType::SignedNorm:
|
||||||
|
return "SignedNorm";
|
||||||
|
case VertexType::UnsignedNorm:
|
||||||
|
return "UnsignedNorm";
|
||||||
|
case VertexType::SignedInt:
|
||||||
|
return "SignedInt";
|
||||||
|
case VertexType::UnsignedInt:
|
||||||
|
return "UnsignedInt";
|
||||||
|
case VertexType::UnsignedScaled:
|
||||||
|
return "UnsignedScaled";
|
||||||
|
case VertexType::SignedScaled:
|
||||||
|
return "SignedScaled";
|
||||||
|
case VertexType::Float:
|
||||||
|
return "Float";
|
||||||
|
}
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class PrimitiveTopology : u32 {
|
||||||
|
Points = 0x0,
|
||||||
|
Lines = 0x1,
|
||||||
|
LineLoop = 0x2,
|
||||||
|
LineStrip = 0x3,
|
||||||
|
Triangles = 0x4,
|
||||||
|
TriangleStrip = 0x5,
|
||||||
|
TriangleFan = 0x6,
|
||||||
|
Quads = 0x7,
|
||||||
|
QuadStrip = 0x8,
|
||||||
|
Polygon = 0x9,
|
||||||
|
LinesAdjacency = 0xa,
|
||||||
|
LineStripAdjacency = 0xb,
|
||||||
|
TrianglesAdjacency = 0xc,
|
||||||
|
TriangleStripAdjacency = 0xd,
|
||||||
|
Patches = 0xe,
|
||||||
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
INSERT_PADDING_WORDS(0x200);
|
INSERT_PADDING_WORDS(0x200);
|
||||||
|
@ -112,8 +214,8 @@ public:
|
||||||
BitField<0, 5, u32> buffer;
|
BitField<0, 5, u32> buffer;
|
||||||
BitField<6, 1, u32> constant;
|
BitField<6, 1, u32> constant;
|
||||||
BitField<7, 14, u32> offset;
|
BitField<7, 14, u32> offset;
|
||||||
BitField<21, 6, u32> size;
|
BitField<21, 6, VertexSize> size;
|
||||||
BitField<27, 3, u32> type;
|
BitField<27, 3, VertexType> type;
|
||||||
BitField<31, 1, u32> bgra;
|
BitField<31, 1, u32> bgra;
|
||||||
} vertex_attrib_format[NumVertexAttributes];
|
} vertex_attrib_format[NumVertexAttributes];
|
||||||
|
|
||||||
|
@ -163,13 +265,15 @@ public:
|
||||||
}
|
}
|
||||||
} code_address;
|
} code_address;
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(1);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u32 vertex_end_gl;
|
u32 vertex_end_gl;
|
||||||
union {
|
union {
|
||||||
u32 vertex_begin_gl;
|
u32 vertex_begin_gl;
|
||||||
BitField<0, 16, u32> topology;
|
BitField<0, 16, PrimitiveTopology> topology;
|
||||||
};
|
};
|
||||||
} draw;
|
} draw;
|
||||||
|
|
||||||
INSERT_PADDING_WORDS(0x139);
|
INSERT_PADDING_WORDS(0x139);
|
||||||
struct {
|
struct {
|
||||||
u32 query_address_high;
|
u32 query_address_high;
|
||||||
|
|
|
@ -8,10 +8,42 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/service/nvflinger/buffer_queue.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
|
|
||||||
namespace Tegra {
|
namespace Tegra {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct describing framebuffer configuration
|
||||||
|
*/
|
||||||
|
struct FramebufferConfig {
|
||||||
|
enum class PixelFormat : u32 {
|
||||||
|
ABGR8 = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes per pixel.
|
||||||
|
*/
|
||||||
|
static u32 BytesPerPixel(PixelFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case PixelFormat::ABGR8:
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr address;
|
||||||
|
u32 offset;
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
u32 stride;
|
||||||
|
PixelFormat pixel_format;
|
||||||
|
|
||||||
|
using TransformFlags = Service::NVFlinger::BufferQueue::BufferTransformFlags;
|
||||||
|
TransformFlags transform_flags;
|
||||||
|
};
|
||||||
|
|
||||||
namespace Engines {
|
namespace Engines {
|
||||||
class Fermi2D;
|
class Fermi2D;
|
||||||
class Maxwell3D;
|
class Maxwell3D;
|
||||||
|
@ -36,6 +68,10 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<MemoryManager> memory_manager;
|
std::unique_ptr<MemoryManager> memory_manager;
|
||||||
|
|
||||||
|
Engines::Maxwell3D& Maxwell3D() {
|
||||||
|
return *maxwell_3d;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr u32 InvalidGraphMacroEntry = 0xFFFFFFFF;
|
static constexpr u32 InvalidGraphMacroEntry = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "video_core/gpu.h"
|
||||||
|
|
||||||
struct ScreenInfo;
|
struct ScreenInfo;
|
||||||
|
|
||||||
|
@ -24,14 +25,14 @@ public:
|
||||||
virtual void FlushAll() = 0;
|
virtual void FlushAll() = 0;
|
||||||
|
|
||||||
/// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory
|
/// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory
|
||||||
virtual void FlushRegion(PAddr addr, u32 size) = 0;
|
virtual void FlushRegion(VAddr addr, u64 size) = 0;
|
||||||
|
|
||||||
/// Notify rasterizer that any caches of the specified region should be invalidated
|
/// Notify rasterizer that any caches of the specified region should be invalidated
|
||||||
virtual void InvalidateRegion(PAddr addr, u32 size) = 0;
|
virtual void InvalidateRegion(VAddr addr, u64 size) = 0;
|
||||||
|
|
||||||
/// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory
|
/// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory
|
||||||
/// and invalidated
|
/// and invalidated
|
||||||
virtual void FlushAndInvalidateRegion(PAddr addr, u32 size) = 0;
|
virtual void FlushAndInvalidateRegion(VAddr addr, u64 size) = 0;
|
||||||
|
|
||||||
/// Attempt to use a faster method to perform a display transfer with is_texture_copy = 0
|
/// Attempt to use a faster method to perform a display transfer with is_texture_copy = 0
|
||||||
virtual bool AccelerateDisplayTransfer(const void* config) {
|
virtual bool AccelerateDisplayTransfer(const void* config) {
|
||||||
|
@ -49,7 +50,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to use a faster method to display the framebuffer to screen
|
/// Attempt to use a faster method to display the framebuffer to screen
|
||||||
virtual bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride,
|
virtual bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer,
|
||||||
|
VAddr framebuffer_addr, u32 pixel_stride,
|
||||||
ScreenInfo& screen_info) {
|
ScreenInfo& screen_info) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
|
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
void RendererBase::RefreshRasterizerSetting() {}
|
void RendererBase::RefreshRasterizerSetting() {
|
||||||
|
if (rasterizer == nullptr) {
|
||||||
|
rasterizer = std::make_unique<RasterizerOpenGL>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "video_core/gpu.h"
|
||||||
|
#include "video_core/rasterizer_interface.h"
|
||||||
|
|
||||||
class EmuWindow;
|
class EmuWindow;
|
||||||
|
|
||||||
|
@ -16,40 +18,10 @@ public:
|
||||||
/// Used to reference a framebuffer
|
/// Used to reference a framebuffer
|
||||||
enum kFramebuffer { kFramebuffer_VirtualXFB = 0, kFramebuffer_EFB, kFramebuffer_Texture };
|
enum kFramebuffer { kFramebuffer_VirtualXFB = 0, kFramebuffer_EFB, kFramebuffer_Texture };
|
||||||
|
|
||||||
/**
|
|
||||||
* Struct describing framebuffer metadata
|
|
||||||
* TODO(bunnei): This struct belongs in the GPU code, but we don't have a good place for it yet.
|
|
||||||
*/
|
|
||||||
struct FramebufferInfo {
|
|
||||||
enum class PixelFormat : u32 {
|
|
||||||
ABGR8 = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of bytes per pixel.
|
|
||||||
*/
|
|
||||||
static u32 BytesPerPixel(PixelFormat format) {
|
|
||||||
switch (format) {
|
|
||||||
case PixelFormat::ABGR8:
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
VAddr address;
|
|
||||||
u32 offset;
|
|
||||||
u32 width;
|
|
||||||
u32 height;
|
|
||||||
u32 stride;
|
|
||||||
PixelFormat pixel_format;
|
|
||||||
bool flip_vertical;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~RendererBase() {}
|
virtual ~RendererBase() {}
|
||||||
|
|
||||||
/// Swap buffers (render frame)
|
/// Swap buffers (render frame)
|
||||||
virtual void SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) = 0;
|
virtual void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the emulator window to use for renderer
|
* Set the emulator window to use for renderer
|
||||||
|
@ -74,12 +46,16 @@ public:
|
||||||
return m_current_frame;
|
return m_current_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VideoCore::RasterizerInterface* Rasterizer() const {
|
||||||
|
return rasterizer.get();
|
||||||
|
}
|
||||||
|
|
||||||
void RefreshRasterizerSetting();
|
void RefreshRasterizerSetting();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
std::unique_ptr<VideoCore::RasterizerInterface> rasterizer;
|
||||||
f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
|
f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
|
||||||
int m_current_frame = 0; ///< Current frame, should be set by the renderer
|
int m_current_frame = 0; ///< Current frame, should be set by the renderer
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool opengl_rasterizer_active = false;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,6 +54,8 @@ static void SetShaderUniformBlockBindings(GLuint shader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RasterizerOpenGL::RasterizerOpenGL() {
|
RasterizerOpenGL::RasterizerOpenGL() {
|
||||||
|
shader_dirty = true;
|
||||||
|
|
||||||
has_ARB_buffer_storage = false;
|
has_ARB_buffer_storage = false;
|
||||||
has_ARB_direct_state_access = false;
|
has_ARB_direct_state_access = false;
|
||||||
has_ARB_separate_shader_objects = false;
|
has_ARB_separate_shader_objects = false;
|
||||||
|
@ -106,8 +108,6 @@ RasterizerOpenGL::RasterizerOpenGL() {
|
||||||
state.draw.vertex_buffer = stream_buffer->GetHandle();
|
state.draw.vertex_buffer = stream_buffer->GetHandle();
|
||||||
|
|
||||||
pipeline.Create();
|
pipeline.Create();
|
||||||
vs_input_index_min = 0;
|
|
||||||
vs_input_index_max = 0;
|
|
||||||
state.draw.program_pipeline = pipeline.handle;
|
state.draw.program_pipeline = pipeline.handle;
|
||||||
state.draw.shader_program = 0;
|
state.draw.shader_program = 0;
|
||||||
state.draw.vertex_array = hw_vao.handle;
|
state.draw.vertex_array = hw_vao.handle;
|
||||||
|
@ -120,20 +120,14 @@ RasterizerOpenGL::RasterizerOpenGL() {
|
||||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY);
|
glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY);
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle);
|
glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle);
|
||||||
} else {
|
} else {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
accelerate_draw = AccelDraw::Disabled;
|
accelerate_draw = AccelDraw::Disabled;
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
// Sync fixed function OpenGL state
|
LOG_WARNING(HW_GPU, "Sync fixed function OpenGL state here when ready");
|
||||||
SyncClipEnabled();
|
|
||||||
SyncClipCoef();
|
|
||||||
SyncCullMode();
|
|
||||||
SyncBlendEnabled();
|
|
||||||
SyncBlendFuncs();
|
|
||||||
SyncBlendColor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RasterizerOpenGL::~RasterizerOpenGL() {
|
RasterizerOpenGL::~RasterizerOpenGL() {
|
||||||
|
@ -167,12 +161,12 @@ void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_
|
||||||
|
|
||||||
void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) {
|
void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) {
|
||||||
MICROPROFILE_SCOPE(OpenGL_FS);
|
MICROPROFILE_SCOPE(OpenGL_FS);
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
|
bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
|
||||||
if (!has_ARB_separate_shader_objects) {
|
if (!has_ARB_separate_shader_objects) {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,17 +188,17 @@ void RasterizerOpenGL::FlushAll() {
|
||||||
res_cache.FlushAll();
|
res_cache.FlushAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) {
|
void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
|
||||||
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
||||||
res_cache.FlushRegion(addr, size);
|
res_cache.FlushRegion(addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) {
|
void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) {
|
||||||
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
||||||
res_cache.InvalidateRegion(addr, size, nullptr);
|
res_cache.InvalidateRegion(addr, size, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
|
void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
|
||||||
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
||||||
res_cache.FlushRegion(addr, size);
|
res_cache.FlushRegion(addr, size);
|
||||||
res_cache.InvalidateRegion(addr, size, nullptr);
|
res_cache.InvalidateRegion(addr, size, nullptr);
|
||||||
|
@ -212,58 +206,144 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
|
||||||
|
|
||||||
bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) {
|
bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) {
|
||||||
MICROPROFILE_SCOPE(OpenGL_Blits);
|
MICROPROFILE_SCOPE(OpenGL_Blits);
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) {
|
bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RasterizerOpenGL::AccelerateFill(const void* config) {
|
bool RasterizerOpenGL::AccelerateFill(const void* config) {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RasterizerOpenGL::AccelerateDisplay(const void* config, PAddr framebuffer_addr,
|
bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer,
|
||||||
u32 pixel_stride, ScreenInfo& screen_info) {
|
VAddr framebuffer_addr, u32 pixel_stride,
|
||||||
UNIMPLEMENTED();
|
ScreenInfo& screen_info) {
|
||||||
|
if (framebuffer_addr == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
|
||||||
|
|
||||||
|
SurfaceParams src_params;
|
||||||
|
src_params.addr = framebuffer_addr;
|
||||||
|
src_params.width = std::min(framebuffer.width, pixel_stride);
|
||||||
|
src_params.height = framebuffer.height;
|
||||||
|
src_params.stride = pixel_stride;
|
||||||
|
src_params.is_tiled = false;
|
||||||
|
src_params.pixel_format =
|
||||||
|
SurfaceParams::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format);
|
||||||
|
src_params.UpdateParams();
|
||||||
|
|
||||||
|
MathUtil::Rectangle<u32> src_rect;
|
||||||
|
Surface src_surface;
|
||||||
|
std::tie(src_surface, src_rect) =
|
||||||
|
res_cache.GetSurfaceSubRect(src_params, ScaleMatch::Ignore, true);
|
||||||
|
|
||||||
|
if (src_surface == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 scaled_width = src_surface->GetScaledWidth();
|
||||||
|
u32 scaled_height = src_surface->GetScaledHeight();
|
||||||
|
|
||||||
|
screen_info.display_texcoords = MathUtil::Rectangle<float>(
|
||||||
|
(float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
|
||||||
|
(float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
|
||||||
|
|
||||||
|
screen_info.display_texture = src_surface->texture.handle;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SetShader() {
|
void RasterizerOpenGL::SetShader() {
|
||||||
UNIMPLEMENTED();
|
// TODO(bunnei): The below sets up a static test shader for passing untransformed vertices to
|
||||||
|
// OpenGL for rendering. This should be removed/replaced when we start emulating Maxwell
|
||||||
|
// shaders.
|
||||||
|
|
||||||
|
static constexpr char vertex_shader[] = R"(
|
||||||
|
#version 150 core
|
||||||
|
|
||||||
|
in vec2 vert_position;
|
||||||
|
in vec2 vert_tex_coord;
|
||||||
|
out vec2 frag_tex_coord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// Multiply input position by the rotscale part of the matrix and then manually translate by
|
||||||
|
// the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
|
||||||
|
// to `vec3(vert_position.xy, 1.0)`
|
||||||
|
gl_Position = vec4(mat2(mat3x2(0.0015625f, 0.0, 0.0, -0.0027778, -1.0, 1.0)) * vert_position + mat3x2(0.0015625f, 0.0, 0.0, -0.0027778, -1.0, 1.0)[2], 0.0, 1.0);
|
||||||
|
frag_tex_coord = vert_tex_coord;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
static constexpr char fragment_shader[] = R"(
|
||||||
|
#version 150 core
|
||||||
|
|
||||||
|
in vec2 frag_tex_coord;
|
||||||
|
out vec4 color;
|
||||||
|
|
||||||
|
uniform sampler2D color_texture;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
color = vec4(1.0, 0.0, 1.0, 0.0);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
if (current_shader) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_ERROR(HW_GPU, "Emulated shaders are not supported! Using a passthrough shader.");
|
||||||
|
|
||||||
|
current_shader = &test_shader;
|
||||||
|
if (has_ARB_separate_shader_objects) {
|
||||||
|
test_shader.shader.Create(vertex_shader, nullptr, fragment_shader, {}, true);
|
||||||
|
glActiveShaderProgram(pipeline.handle, test_shader.shader.handle);
|
||||||
|
} else {
|
||||||
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
state.draw.shader_program = test_shader.shader.handle;
|
||||||
|
state.Apply();
|
||||||
|
|
||||||
|
if (has_ARB_separate_shader_objects) {
|
||||||
|
state.draw.shader_program = 0;
|
||||||
|
state.Apply();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncClipEnabled() {
|
void RasterizerOpenGL::SyncClipEnabled() {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncClipCoef() {
|
void RasterizerOpenGL::SyncClipCoef() {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncCullMode() {
|
void RasterizerOpenGL::SyncCullMode() {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncDepthScale() {
|
void RasterizerOpenGL::SyncDepthScale() {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncDepthOffset() {
|
void RasterizerOpenGL::SyncDepthOffset() {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncBlendEnabled() {
|
void RasterizerOpenGL::SyncBlendEnabled() {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncBlendFuncs() {
|
void RasterizerOpenGL::SyncBlendFuncs() {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncBlendColor() {
|
void RasterizerOpenGL::SyncBlendColor() {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,16 +32,22 @@ public:
|
||||||
void DrawTriangles() override;
|
void DrawTriangles() override;
|
||||||
void NotifyMaxwellRegisterChanged(u32 id) override;
|
void NotifyMaxwellRegisterChanged(u32 id) override;
|
||||||
void FlushAll() override;
|
void FlushAll() override;
|
||||||
void FlushRegion(PAddr addr, u32 size) override;
|
void FlushRegion(VAddr addr, u64 size) override;
|
||||||
void InvalidateRegion(PAddr addr, u32 size) override;
|
void InvalidateRegion(VAddr addr, u64 size) override;
|
||||||
void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
|
void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
|
||||||
bool AccelerateDisplayTransfer(const void* config) override;
|
bool AccelerateDisplayTransfer(const void* config) override;
|
||||||
bool AccelerateTextureCopy(const void* config) override;
|
bool AccelerateTextureCopy(const void* config) override;
|
||||||
bool AccelerateFill(const void* config) override;
|
bool AccelerateFill(const void* config) override;
|
||||||
bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride,
|
bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, VAddr framebuffer_addr,
|
||||||
ScreenInfo& screen_info) override;
|
u32 pixel_stride, ScreenInfo& screen_info) override;
|
||||||
bool AccelerateDrawBatch(bool is_indexed) override;
|
bool AccelerateDrawBatch(bool is_indexed) override;
|
||||||
|
|
||||||
|
/// OpenGL shader generated for a given Maxwell register state
|
||||||
|
struct MaxwellShader {
|
||||||
|
/// OpenGL shader resource
|
||||||
|
OGLShader shader;
|
||||||
|
};
|
||||||
|
|
||||||
struct VertexShader {
|
struct VertexShader {
|
||||||
OGLShader shader;
|
OGLShader shader;
|
||||||
};
|
};
|
||||||
|
@ -117,6 +123,12 @@ private:
|
||||||
|
|
||||||
RasterizerCacheOpenGL res_cache;
|
RasterizerCacheOpenGL res_cache;
|
||||||
|
|
||||||
|
/// Shader used for test renderering - to be removed once we have emulated shaders
|
||||||
|
MaxwellShader test_shader{};
|
||||||
|
|
||||||
|
const MaxwellShader* current_shader{};
|
||||||
|
bool shader_dirty{};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
UniformData data;
|
UniformData data;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
|
@ -136,8 +148,6 @@ private:
|
||||||
static constexpr size_t STREAM_BUFFER_SIZE = 4 * 1024 * 1024;
|
static constexpr size_t STREAM_BUFFER_SIZE = 4 * 1024 * 1024;
|
||||||
std::unique_ptr<OGLStreamBuffer> stream_buffer;
|
std::unique_ptr<OGLStreamBuffer> stream_buffer;
|
||||||
|
|
||||||
GLint vs_input_index_min;
|
|
||||||
GLint vs_input_index_max;
|
|
||||||
GLsizeiptr vs_input_size;
|
GLsizeiptr vs_input_size;
|
||||||
|
|
||||||
void AnalyzeVertexArray(bool is_indexed);
|
void AnalyzeVertexArray(bool is_indexed);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
|
#include "core/hle/kernel/vm_manager.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
||||||
|
@ -107,7 +108,7 @@ static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool morton_to_gl, PixelFormat format>
|
template <bool morton_to_gl, PixelFormat format>
|
||||||
static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr start, PAddr end) {
|
static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) {
|
||||||
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
|
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
|
||||||
constexpr u32 tile_size = bytes_per_pixel * 64;
|
constexpr u32 tile_size = bytes_per_pixel * 64;
|
||||||
|
|
||||||
|
@ -115,9 +116,9 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr
|
||||||
static_assert(gl_bytes_per_pixel >= bytes_per_pixel, "");
|
static_assert(gl_bytes_per_pixel >= bytes_per_pixel, "");
|
||||||
gl_buffer += gl_bytes_per_pixel - bytes_per_pixel;
|
gl_buffer += gl_bytes_per_pixel - bytes_per_pixel;
|
||||||
|
|
||||||
const PAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size);
|
const VAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size);
|
||||||
const PAddr aligned_start = base + Common::AlignUp(start - base, tile_size);
|
const VAddr aligned_start = base + Common::AlignUp(start - base, tile_size);
|
||||||
const PAddr aligned_end = base + Common::AlignDown(end - base, tile_size);
|
const VAddr aligned_end = base + Common::AlignDown(end - base, tile_size);
|
||||||
|
|
||||||
ASSERT(!morton_to_gl || (aligned_start == start && aligned_end == end));
|
ASSERT(!morton_to_gl || (aligned_start == start && aligned_end == end));
|
||||||
|
|
||||||
|
@ -136,7 +137,7 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
u8* tile_buffer = Memory::GetPhysicalPointer(start);
|
u8* tile_buffer = Memory::GetPointer(start);
|
||||||
|
|
||||||
if (start < aligned_start && !morton_to_gl) {
|
if (start < aligned_start && !morton_to_gl) {
|
||||||
std::array<u8, tile_size> tmp_buf;
|
std::array<u8, tile_size> tmp_buf;
|
||||||
|
@ -162,7 +163,7 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> morton_to_gl_fns = {
|
static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> morton_to_gl_fns = {
|
||||||
MortonCopy<true, PixelFormat::RGBA8>, // 0
|
MortonCopy<true, PixelFormat::RGBA8>, // 0
|
||||||
MortonCopy<true, PixelFormat::RGB8>, // 1
|
MortonCopy<true, PixelFormat::RGB8>, // 1
|
||||||
MortonCopy<true, PixelFormat::RGB5A1>, // 2
|
MortonCopy<true, PixelFormat::RGB5A1>, // 2
|
||||||
|
@ -183,7 +184,7 @@ static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> mo
|
||||||
MortonCopy<true, PixelFormat::D24S8> // 17
|
MortonCopy<true, PixelFormat::D24S8> // 17
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> gl_to_morton_fns = {
|
static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl_to_morton_fns = {
|
||||||
MortonCopy<false, PixelFormat::RGBA8>, // 0
|
MortonCopy<false, PixelFormat::RGBA8>, // 0
|
||||||
MortonCopy<false, PixelFormat::RGB8>, // 1
|
MortonCopy<false, PixelFormat::RGB8>, // 1
|
||||||
MortonCopy<false, PixelFormat::RGB5A1>, // 2
|
MortonCopy<false, PixelFormat::RGB5A1>, // 2
|
||||||
|
@ -290,7 +291,7 @@ static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rec
|
||||||
|
|
||||||
static bool FillSurface(const Surface& surface, const u8* fill_data,
|
static bool FillSurface(const Surface& surface, const u8* fill_data,
|
||||||
const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) {
|
const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,9 +299,9 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const {
|
||||||
SurfaceParams params = *this;
|
SurfaceParams params = *this;
|
||||||
const u32 tiled_size = is_tiled ? 8 : 1;
|
const u32 tiled_size = is_tiled ? 8 : 1;
|
||||||
const u64 stride_tiled_bytes = BytesInPixels(stride * tiled_size);
|
const u64 stride_tiled_bytes = BytesInPixels(stride * tiled_size);
|
||||||
PAddr aligned_start =
|
VAddr aligned_start =
|
||||||
addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes);
|
addr + Common::AlignDown(boost::icl::first(interval) - addr, stride_tiled_bytes);
|
||||||
PAddr aligned_end =
|
VAddr aligned_end =
|
||||||
addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes);
|
addr + Common::AlignUp(boost::icl::last_next(interval) - addr, stride_tiled_bytes);
|
||||||
|
|
||||||
if (aligned_end - aligned_start > stride_tiled_bytes) {
|
if (aligned_end - aligned_start > stride_tiled_bytes) {
|
||||||
|
@ -527,10 +528,10 @@ void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surfac
|
||||||
}
|
}
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
|
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
|
||||||
void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
|
void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) {
|
||||||
ASSERT(type != SurfaceType::Fill);
|
ASSERT(type != SurfaceType::Fill);
|
||||||
|
|
||||||
const u8* const texture_src_data = Memory::GetPhysicalPointer(addr);
|
u8* texture_src_data = Memory::GetPointer(addr);
|
||||||
if (texture_src_data == nullptr)
|
if (texture_src_data == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -539,35 +540,25 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
|
||||||
gl_buffer.reset(new u8[gl_buffer_size]);
|
gl_buffer.reset(new u8[gl_buffer_size]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should probably be done in ::Memory:: and check for other regions too
|
|
||||||
if (load_start < Memory::VRAM_VADDR_END && load_end > Memory::VRAM_VADDR_END)
|
|
||||||
load_end = Memory::VRAM_VADDR_END;
|
|
||||||
|
|
||||||
if (load_start < Memory::VRAM_VADDR && load_end > Memory::VRAM_VADDR)
|
|
||||||
load_start = Memory::VRAM_VADDR;
|
|
||||||
|
|
||||||
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
|
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
|
||||||
|
|
||||||
ASSERT(load_start >= addr && load_end <= end);
|
ASSERT(load_start >= addr && load_end <= end);
|
||||||
const u32 start_offset = load_start - addr;
|
const u64 start_offset = load_start - addr;
|
||||||
|
|
||||||
if (!is_tiled) {
|
if (!is_tiled) {
|
||||||
ASSERT(type == SurfaceType::Color);
|
ASSERT(type == SurfaceType::Color);
|
||||||
std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset,
|
const u32 bytes_per_pixel{GetFormatBpp() >> 3};
|
||||||
load_end - load_start);
|
VideoCore::MortonCopyPixels128(width, height, bytes_per_pixel, 4,
|
||||||
|
texture_src_data + start_offset, &gl_buffer[start_offset],
|
||||||
|
true);
|
||||||
} else {
|
} else {
|
||||||
if (type == SurfaceType::Texture) {
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
UNIMPLEMENTED();
|
|
||||||
} else {
|
|
||||||
morton_to_gl_fns[static_cast<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr,
|
|
||||||
load_start, load_end);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
|
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
|
||||||
void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) {
|
void CachedSurface::FlushGLBuffer(VAddr flush_start, VAddr flush_end) {
|
||||||
u8* const dst_buffer = Memory::GetPhysicalPointer(addr);
|
u8* const dst_buffer = Memory::GetPointer(addr);
|
||||||
if (dst_buffer == nullptr)
|
if (dst_buffer == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1102,7 +1093,7 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams&
|
||||||
}
|
}
|
||||||
|
|
||||||
Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) {
|
Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1113,7 +1104,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
|
||||||
}
|
}
|
||||||
|
|
||||||
Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) {
|
Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) {
|
||||||
UNIMPLEMENTED();
|
ASSERT_MSG(false, "Unimplemented");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1167,7 +1158,7 @@ void RasterizerCacheOpenGL::DuplicateSurface(const Surface& src_surface,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, PAddr addr, u64 size) {
|
void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, VAddr addr, u64 size) {
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1227,7 +1218,7 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, PAddr addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u64 size, Surface flush_surface) {
|
void RasterizerCacheOpenGL::FlushRegion(VAddr addr, u64 size, Surface flush_surface) {
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1260,10 +1251,10 @@ void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u64 size, Surface flush_surf
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCacheOpenGL::FlushAll() {
|
void RasterizerCacheOpenGL::FlushAll() {
|
||||||
FlushRegion(0, 0xFFFFFFFF);
|
FlushRegion(0, Kernel::VMManager::MAX_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCacheOpenGL::InvalidateRegion(PAddr addr, u64 size, const Surface& region_owner) {
|
void RasterizerCacheOpenGL::InvalidateRegion(VAddr addr, u64 size, const Surface& region_owner) {
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1356,6 +1347,6 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
|
||||||
surface_cache.subtract({surface->GetInterval(), SurfaceSet{surface}});
|
surface_cache.subtract({surface->GetInterval(), SurfaceSet{surface}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u64 size, int delta) {
|
void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
|
||||||
UNIMPLEMENTED();
|
// ASSERT_MSG(false, "Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,15 +22,16 @@
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
|
#include "video_core/gpu.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
|
|
||||||
struct CachedSurface;
|
struct CachedSurface;
|
||||||
using Surface = std::shared_ptr<CachedSurface>;
|
using Surface = std::shared_ptr<CachedSurface>;
|
||||||
using SurfaceSet = std::set<Surface>;
|
using SurfaceSet = std::set<Surface>;
|
||||||
|
|
||||||
using SurfaceRegions = boost::icl::interval_set<PAddr>;
|
using SurfaceRegions = boost::icl::interval_set<VAddr>;
|
||||||
using SurfaceMap = boost::icl::interval_map<PAddr, Surface>;
|
using SurfaceMap = boost::icl::interval_map<VAddr, Surface>;
|
||||||
using SurfaceCache = boost::icl::interval_map<PAddr, SurfaceSet>;
|
using SurfaceCache = boost::icl::interval_map<VAddr, SurfaceSet>;
|
||||||
|
|
||||||
using SurfaceInterval = SurfaceCache::interval_type;
|
using SurfaceInterval = SurfaceCache::interval_type;
|
||||||
static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval_type>() &&
|
static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval_type>() &&
|
||||||
|
@ -115,6 +116,15 @@ struct SurfaceParams {
|
||||||
return GetFormatBpp(pixel_format);
|
return GetFormatBpp(pixel_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
||||||
|
return PixelFormat::RGBA8;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) {
|
static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) {
|
||||||
SurfaceType a_type = GetFormatType(pixel_format_a);
|
SurfaceType a_type = GetFormatType(pixel_format_a);
|
||||||
SurfaceType b_type = GetFormatType(pixel_format_b);
|
SurfaceType b_type = GetFormatType(pixel_format_b);
|
||||||
|
@ -211,8 +221,8 @@ struct SurfaceParams {
|
||||||
MathUtil::Rectangle<u32> GetSubRect(const SurfaceParams& sub_surface) const;
|
MathUtil::Rectangle<u32> GetSubRect(const SurfaceParams& sub_surface) const;
|
||||||
MathUtil::Rectangle<u32> GetScaledSubRect(const SurfaceParams& sub_surface) const;
|
MathUtil::Rectangle<u32> GetScaledSubRect(const SurfaceParams& sub_surface) const;
|
||||||
|
|
||||||
PAddr addr = 0;
|
VAddr addr = 0;
|
||||||
PAddr end = 0;
|
VAddr end = 0;
|
||||||
u64 size = 0;
|
u64 size = 0;
|
||||||
|
|
||||||
u32 width = 0;
|
u32 width = 0;
|
||||||
|
@ -257,9 +267,9 @@ struct CachedSurface : SurfaceParams {
|
||||||
std::unique_ptr<u8[]> gl_buffer;
|
std::unique_ptr<u8[]> gl_buffer;
|
||||||
size_t gl_buffer_size = 0;
|
size_t gl_buffer_size = 0;
|
||||||
|
|
||||||
// Read/Write data in 3DS memory to/from gl_buffer
|
// Read/Write data in Switch memory to/from gl_buffer
|
||||||
void LoadGLBuffer(PAddr load_start, PAddr load_end);
|
void LoadGLBuffer(VAddr load_start, VAddr load_end);
|
||||||
void FlushGLBuffer(PAddr flush_start, PAddr flush_end);
|
void FlushGLBuffer(VAddr flush_start, VAddr flush_end);
|
||||||
|
|
||||||
// Upload/Download data in gl_buffer in/to this surface's texture
|
// Upload/Download data in gl_buffer in/to this surface's texture
|
||||||
void UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
|
void UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
|
||||||
|
@ -307,10 +317,10 @@ public:
|
||||||
SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params);
|
SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params);
|
||||||
|
|
||||||
/// Write any cached resources overlapping the region back to memory (if dirty)
|
/// Write any cached resources overlapping the region back to memory (if dirty)
|
||||||
void FlushRegion(PAddr addr, u64 size, Surface flush_surface = nullptr);
|
void FlushRegion(VAddr addr, u64 size, Surface flush_surface = nullptr);
|
||||||
|
|
||||||
/// Mark region as being invalidated by region_owner (nullptr if 3DS memory)
|
/// Mark region as being invalidated by region_owner (nullptr if 3DS memory)
|
||||||
void InvalidateRegion(PAddr addr, u64 size, const Surface& region_owner);
|
void InvalidateRegion(VAddr addr, u64 size, const Surface& region_owner);
|
||||||
|
|
||||||
/// Flush all cached resources tracked by this cache manager
|
/// Flush all cached resources tracked by this cache manager
|
||||||
void FlushAll();
|
void FlushAll();
|
||||||
|
@ -319,7 +329,7 @@ private:
|
||||||
void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface);
|
void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface);
|
||||||
|
|
||||||
/// Update surface's texture for given region when necessary
|
/// Update surface's texture for given region when necessary
|
||||||
void ValidateSurface(const Surface& surface, PAddr addr, u64 size);
|
void ValidateSurface(const Surface& surface, VAddr addr, u64 size);
|
||||||
|
|
||||||
/// Create a new surface
|
/// Create a new surface
|
||||||
Surface CreateSurface(const SurfaceParams& params);
|
Surface CreateSurface(const SurfaceParams& params);
|
||||||
|
@ -331,7 +341,7 @@ private:
|
||||||
void UnregisterSurface(const Surface& surface);
|
void UnregisterSurface(const Surface& surface);
|
||||||
|
|
||||||
/// Increase/decrease the number of surface in pages touching the specified region
|
/// Increase/decrease the number of surface in pages touching the specified region
|
||||||
void UpdatePagesCachedCount(PAddr addr, u64 size, int delta);
|
void UpdatePagesCachedCount(VAddr addr, u64 size, int delta);
|
||||||
|
|
||||||
SurfaceCache surface_cache;
|
SurfaceCache surface_cache;
|
||||||
PageMap cached_pages;
|
PageMap cached_pages;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "core/tracer/recorder.h"
|
#include "core/tracer/recorder.h"
|
||||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||||
|
#include "video_core/utils.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
static const char vertex_shader[] = R"(
|
static const char vertex_shader[] = R"(
|
||||||
|
@ -98,22 +99,22 @@ RendererOpenGL::RendererOpenGL() = default;
|
||||||
RendererOpenGL::~RendererOpenGL() = default;
|
RendererOpenGL::~RendererOpenGL() = default;
|
||||||
|
|
||||||
/// Swap buffers (render frame)
|
/// Swap buffers (render frame)
|
||||||
void RendererOpenGL::SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) {
|
void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) {
|
||||||
// Maintain the rasterizer's state as a priority
|
// Maintain the rasterizer's state as a priority
|
||||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
if (framebuffer_info != boost::none) {
|
if (framebuffer != boost::none) {
|
||||||
// If framebuffer_info is provided, reload it from memory to a texture
|
// If framebuffer is provided, reload it from memory to a texture
|
||||||
if (screen_info.texture.width != (GLsizei)framebuffer_info->width ||
|
if (screen_info.texture.width != (GLsizei)framebuffer->width ||
|
||||||
screen_info.texture.height != (GLsizei)framebuffer_info->height ||
|
screen_info.texture.height != (GLsizei)framebuffer->height ||
|
||||||
screen_info.texture.pixel_format != framebuffer_info->pixel_format) {
|
screen_info.texture.pixel_format != framebuffer->pixel_format) {
|
||||||
// Reallocate texture if the framebuffer size has changed.
|
// Reallocate texture if the framebuffer size has changed.
|
||||||
// This is expected to not happen very often and hence should not be a
|
// This is expected to not happen very often and hence should not be a
|
||||||
// performance problem.
|
// performance problem.
|
||||||
ConfigureFramebufferTexture(screen_info.texture, *framebuffer_info);
|
ConfigureFramebufferTexture(screen_info.texture, *framebuffer);
|
||||||
}
|
}
|
||||||
LoadFBToScreenInfo(*framebuffer_info, screen_info);
|
LoadFBToScreenInfo(*framebuffer, screen_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawScreens();
|
DrawScreens();
|
||||||
|
@ -131,157 +132,51 @@ void RendererOpenGL::SwapBuffers(boost::optional<const FramebufferInfo&> framebu
|
||||||
RefreshRasterizerSetting();
|
RefreshRasterizerSetting();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 MortonInterleave128(u32 x, u32 y) {
|
|
||||||
// 128x128 Z-Order coordinate from 2D coordinates
|
|
||||||
static constexpr u32 xlut[] = {
|
|
||||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042,
|
|
||||||
0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809,
|
|
||||||
0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000,
|
|
||||||
0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043,
|
|
||||||
0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a,
|
|
||||||
0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001,
|
|
||||||
0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048,
|
|
||||||
0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b,
|
|
||||||
0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002,
|
|
||||||
0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049,
|
|
||||||
0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840,
|
|
||||||
0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003,
|
|
||||||
0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a,
|
|
||||||
0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841,
|
|
||||||
0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008,
|
|
||||||
0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b,
|
|
||||||
0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842,
|
|
||||||
0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009,
|
|
||||||
0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800,
|
|
||||||
0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843,
|
|
||||||
0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a,
|
|
||||||
0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801,
|
|
||||||
0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848,
|
|
||||||
0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b,
|
|
||||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802,
|
|
||||||
0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849,
|
|
||||||
0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040,
|
|
||||||
0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803,
|
|
||||||
0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a,
|
|
||||||
0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041,
|
|
||||||
0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808,
|
|
||||||
0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b,
|
|
||||||
0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042,
|
|
||||||
0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809,
|
|
||||||
0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b,
|
|
||||||
};
|
|
||||||
static constexpr u32 ylut[] = {
|
|
||||||
0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090,
|
|
||||||
0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124,
|
|
||||||
0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200,
|
|
||||||
0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294,
|
|
||||||
0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330,
|
|
||||||
0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404,
|
|
||||||
0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0,
|
|
||||||
0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534,
|
|
||||||
0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610,
|
|
||||||
0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4,
|
|
||||||
0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780,
|
|
||||||
0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014,
|
|
||||||
0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0,
|
|
||||||
0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184,
|
|
||||||
0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220,
|
|
||||||
0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4,
|
|
||||||
0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390,
|
|
||||||
0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424,
|
|
||||||
0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500,
|
|
||||||
0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594,
|
|
||||||
0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630,
|
|
||||||
0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704,
|
|
||||||
0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0,
|
|
||||||
0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034,
|
|
||||||
0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110,
|
|
||||||
0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4,
|
|
||||||
0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280,
|
|
||||||
0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314,
|
|
||||||
0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0,
|
|
||||||
0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484,
|
|
||||||
0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520,
|
|
||||||
0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4,
|
|
||||||
0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690,
|
|
||||||
0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724,
|
|
||||||
0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4,
|
|
||||||
};
|
|
||||||
return xlut[x % 128] + ylut[y % 128];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) {
|
|
||||||
// Calculates the offset of the position of the pixel in Morton order
|
|
||||||
// Framebuffer images are split into 128x128 tiles.
|
|
||||||
|
|
||||||
const unsigned int block_height = 128;
|
|
||||||
const unsigned int coarse_x = x & ~127;
|
|
||||||
|
|
||||||
u32 i = MortonInterleave128(x, y);
|
|
||||||
|
|
||||||
const unsigned int offset = coarse_x * block_height;
|
|
||||||
|
|
||||||
return (i + offset) * bytes_per_pixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, u32 gl_bytes_per_pixel,
|
|
||||||
u8* morton_data, u8* gl_data, bool morton_to_gl) {
|
|
||||||
u8* data_ptrs[2];
|
|
||||||
for (unsigned y = 0; y < height; ++y) {
|
|
||||||
for (unsigned x = 0; x < width; ++x) {
|
|
||||||
const u32 coarse_y = y & ~127;
|
|
||||||
u32 morton_offset =
|
|
||||||
GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
|
|
||||||
u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel;
|
|
||||||
|
|
||||||
data_ptrs[morton_to_gl] = morton_data + morton_offset;
|
|
||||||
data_ptrs[!morton_to_gl] = &gl_data[gl_pixel_index];
|
|
||||||
|
|
||||||
memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads framebuffer from emulated memory into the active OpenGL texture.
|
* Loads framebuffer from emulated memory into the active OpenGL texture.
|
||||||
*/
|
*/
|
||||||
void RendererOpenGL::LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info,
|
void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer,
|
||||||
ScreenInfo& screen_info) {
|
ScreenInfo& screen_info) {
|
||||||
const u32 bpp{FramebufferInfo::BytesPerPixel(framebuffer_info.pixel_format)};
|
const u32 bytes_per_pixel{Tegra::FramebufferConfig::BytesPerPixel(framebuffer.pixel_format)};
|
||||||
const u32 size_in_bytes{framebuffer_info.stride * framebuffer_info.height * bpp};
|
const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
|
||||||
|
const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
|
||||||
|
|
||||||
MortonCopyPixels128(framebuffer_info.width, framebuffer_info.height, bpp, 4,
|
// TODO(bunnei): The framebuffer region should only be invalidated if it is written to, not
|
||||||
Memory::GetPointer(framebuffer_info.address), gl_framebuffer_data.data(),
|
// every frame. When we find the right place for this, the below line can be removed.
|
||||||
true);
|
Memory::RasterizerFlushVirtualRegion(framebuffer_addr, size_in_bytes,
|
||||||
|
Memory::FlushMode::Invalidate);
|
||||||
|
|
||||||
LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%llx(%dx%d), fmt %x", size_in_bytes,
|
// Framebuffer orientation handling
|
||||||
framebuffer_info.address, framebuffer_info.width, framebuffer_info.height,
|
framebuffer_transform_flags = framebuffer.transform_flags;
|
||||||
(int)framebuffer_info.pixel_format);
|
|
||||||
|
|
||||||
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
|
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
|
||||||
// only allows rows to have a memory alignement of 4.
|
// only allows rows to have a memory alignement of 4.
|
||||||
ASSERT(framebuffer_info.stride % 4 == 0);
|
ASSERT(framebuffer.stride % 4 == 0);
|
||||||
|
|
||||||
framebuffer_flip_vertical = framebuffer_info.flip_vertical;
|
|
||||||
|
|
||||||
|
if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride,
|
||||||
|
screen_info)) {
|
||||||
// Reset the screen info's display texture to its own permanent texture
|
// Reset the screen info's display texture to its own permanent texture
|
||||||
screen_info.display_texture = screen_info.texture.resource.handle;
|
screen_info.display_texture = screen_info.texture.resource.handle;
|
||||||
screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
|
screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
|
||||||
|
|
||||||
// Memory::RasterizerFlushRegion(framebuffer_info.address, size_in_bytes);
|
Rasterizer()->FlushRegion(framebuffer_addr, size_in_bytes);
|
||||||
|
|
||||||
|
VideoCore::MortonCopyPixels128(framebuffer.width, framebuffer.height, bytes_per_pixel, 4,
|
||||||
|
Memory::GetPointer(framebuffer_addr),
|
||||||
|
gl_framebuffer_data.data(), true);
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
|
state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)framebuffer_info.stride);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
|
||||||
|
|
||||||
// Update existing texture
|
// Update existing texture
|
||||||
// TODO: Test what happens on hardware when you change the framebuffer dimensions so that
|
// TODO: Test what happens on hardware when you change the framebuffer dimensions so that
|
||||||
// they differ from the LCD resolution.
|
// they differ from the LCD resolution.
|
||||||
// TODO: Applications could theoretically crash Citra here by specifying too large
|
// TODO: Applications could theoretically crash yuzu here by specifying too large
|
||||||
// framebuffer sizes. We should make sure that this cannot happen.
|
// framebuffer sizes. We should make sure that this cannot happen.
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer_info.width, framebuffer_info.height,
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
|
||||||
screen_info.texture.gl_format, screen_info.texture.gl_type,
|
screen_info.texture.gl_format, screen_info.texture.gl_type,
|
||||||
gl_framebuffer_data.data());
|
gl_framebuffer_data.data());
|
||||||
|
|
||||||
|
@ -289,6 +184,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info,
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = 0;
|
state.texture_units[0].texture_2d = 0;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -372,14 +268,14 @@ void RendererOpenGL::InitOpenGLObjects() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||||
const FramebufferInfo& framebuffer_info) {
|
const Tegra::FramebufferConfig& framebuffer) {
|
||||||
|
|
||||||
texture.width = framebuffer_info.width;
|
texture.width = framebuffer.width;
|
||||||
texture.height = framebuffer_info.height;
|
texture.height = framebuffer.height;
|
||||||
|
|
||||||
GLint internal_format;
|
GLint internal_format;
|
||||||
switch (framebuffer_info.pixel_format) {
|
switch (framebuffer.pixel_format) {
|
||||||
case FramebufferInfo::PixelFormat::ABGR8:
|
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
||||||
// Use RGBA8 and swap in the fragment shader
|
// Use RGBA8 and swap in the fragment shader
|
||||||
internal_format = GL_RGBA;
|
internal_format = GL_RGBA;
|
||||||
texture.gl_format = GL_RGBA;
|
texture.gl_format = GL_RGBA;
|
||||||
|
@ -404,8 +300,19 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||||
void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w,
|
void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w,
|
||||||
float h) {
|
float h) {
|
||||||
const auto& texcoords = screen_info.display_texcoords;
|
const auto& texcoords = screen_info.display_texcoords;
|
||||||
const auto& left = framebuffer_flip_vertical ? texcoords.right : texcoords.left;
|
auto left = texcoords.left;
|
||||||
const auto& right = framebuffer_flip_vertical ? texcoords.left : texcoords.right;
|
auto right = texcoords.right;
|
||||||
|
if (framebuffer_transform_flags != Tegra::FramebufferConfig::TransformFlags::Unset)
|
||||||
|
if (framebuffer_transform_flags == Tegra::FramebufferConfig::TransformFlags::FlipV) {
|
||||||
|
// Flip the framebuffer vertically
|
||||||
|
left = texcoords.right;
|
||||||
|
right = texcoords.left;
|
||||||
|
} else {
|
||||||
|
// Other transformations are unsupported
|
||||||
|
LOG_CRITICAL(HW_GPU, "unsupported framebuffer_transform_flags=%d",
|
||||||
|
framebuffer_transform_flags);
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
std::array<ScreenRectVertex, 4> vertices = {{
|
std::array<ScreenRectVertex, 4> vertices = {{
|
||||||
ScreenRectVertex(x, y, texcoords.top, right),
|
ScreenRectVertex(x, y, texcoords.top, right),
|
||||||
|
|
|
@ -21,7 +21,7 @@ struct TextureInfo {
|
||||||
GLsizei height;
|
GLsizei height;
|
||||||
GLenum gl_format;
|
GLenum gl_format;
|
||||||
GLenum gl_type;
|
GLenum gl_type;
|
||||||
RendererBase::FramebufferInfo::PixelFormat pixel_format;
|
Tegra::FramebufferConfig::PixelFormat pixel_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Structure used for storing information about the display target for each 3DS screen
|
/// Structure used for storing information about the display target for each 3DS screen
|
||||||
|
@ -37,7 +37,7 @@ public:
|
||||||
~RendererOpenGL() override;
|
~RendererOpenGL() override;
|
||||||
|
|
||||||
/// Swap buffers (render frame)
|
/// Swap buffers (render frame)
|
||||||
void SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) override;
|
void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the emulator window to use for renderer
|
* Set the emulator window to use for renderer
|
||||||
|
@ -53,13 +53,14 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitOpenGLObjects();
|
void InitOpenGLObjects();
|
||||||
void ConfigureFramebufferTexture(TextureInfo& texture, const FramebufferInfo& framebuffer_info);
|
void ConfigureFramebufferTexture(TextureInfo& texture,
|
||||||
|
const Tegra::FramebufferConfig& framebuffer);
|
||||||
void DrawScreens();
|
void DrawScreens();
|
||||||
void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h);
|
void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h);
|
||||||
void UpdateFramerate();
|
void UpdateFramerate();
|
||||||
|
|
||||||
// Loads framebuffer from emulated memory into the display information structure
|
// Loads framebuffer from emulated memory into the display information structure
|
||||||
void LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info, ScreenInfo& screen_info);
|
void LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer, ScreenInfo& screen_info);
|
||||||
// Fills active OpenGL texture with the given RGBA color.
|
// Fills active OpenGL texture with the given RGBA color.
|
||||||
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
|
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
|
||||||
const TextureInfo& texture);
|
const TextureInfo& texture);
|
||||||
|
@ -87,6 +88,6 @@ private:
|
||||||
GLuint attrib_position;
|
GLuint attrib_position;
|
||||||
GLuint attrib_tex_coord;
|
GLuint attrib_tex_coord;
|
||||||
|
|
||||||
/// Flips the framebuffer vertically when true
|
/// Used for transforming the framebuffer orientation
|
||||||
bool framebuffer_flip_vertical;
|
Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags;
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,4 +49,116 @@ static inline u32 GetMortonOffset(u32 x, u32 y, u32 bytes_per_pixel) {
|
||||||
return (i + offset) * bytes_per_pixel;
|
return (i + offset) * bytes_per_pixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 MortonInterleave128(u32 x, u32 y) {
|
||||||
|
// 128x128 Z-Order coordinate from 2D coordinates
|
||||||
|
static constexpr u32 xlut[] = {
|
||||||
|
0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042,
|
||||||
|
0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809,
|
||||||
|
0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000,
|
||||||
|
0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043,
|
||||||
|
0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a,
|
||||||
|
0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001,
|
||||||
|
0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048,
|
||||||
|
0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b,
|
||||||
|
0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002,
|
||||||
|
0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049,
|
||||||
|
0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840,
|
||||||
|
0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003,
|
||||||
|
0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a,
|
||||||
|
0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841,
|
||||||
|
0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008,
|
||||||
|
0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b,
|
||||||
|
0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842,
|
||||||
|
0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009,
|
||||||
|
0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800,
|
||||||
|
0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843,
|
||||||
|
0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a,
|
||||||
|
0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801,
|
||||||
|
0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848,
|
||||||
|
0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b,
|
||||||
|
0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802,
|
||||||
|
0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849,
|
||||||
|
0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040,
|
||||||
|
0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803,
|
||||||
|
0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a,
|
||||||
|
0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041,
|
||||||
|
0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808,
|
||||||
|
0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b,
|
||||||
|
0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042,
|
||||||
|
0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809,
|
||||||
|
0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b,
|
||||||
|
};
|
||||||
|
static constexpr u32 ylut[] = {
|
||||||
|
0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090,
|
||||||
|
0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124,
|
||||||
|
0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200,
|
||||||
|
0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294,
|
||||||
|
0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330,
|
||||||
|
0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404,
|
||||||
|
0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0,
|
||||||
|
0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534,
|
||||||
|
0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610,
|
||||||
|
0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4,
|
||||||
|
0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780,
|
||||||
|
0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014,
|
||||||
|
0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0,
|
||||||
|
0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184,
|
||||||
|
0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220,
|
||||||
|
0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4,
|
||||||
|
0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390,
|
||||||
|
0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424,
|
||||||
|
0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500,
|
||||||
|
0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594,
|
||||||
|
0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630,
|
||||||
|
0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704,
|
||||||
|
0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0,
|
||||||
|
0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034,
|
||||||
|
0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110,
|
||||||
|
0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4,
|
||||||
|
0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280,
|
||||||
|
0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314,
|
||||||
|
0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0,
|
||||||
|
0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484,
|
||||||
|
0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520,
|
||||||
|
0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4,
|
||||||
|
0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690,
|
||||||
|
0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724,
|
||||||
|
0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4,
|
||||||
|
};
|
||||||
|
return xlut[x % 128] + ylut[y % 128];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) {
|
||||||
|
// Calculates the offset of the position of the pixel in Morton order
|
||||||
|
// Framebuffer images are split into 128x128 tiles.
|
||||||
|
|
||||||
|
const unsigned int block_height = 128;
|
||||||
|
const unsigned int coarse_x = x & ~127;
|
||||||
|
|
||||||
|
u32 i = MortonInterleave128(x, y);
|
||||||
|
|
||||||
|
const unsigned int offset = coarse_x * block_height;
|
||||||
|
|
||||||
|
return (i + offset) * bytes_per_pixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel,
|
||||||
|
u32 gl_bytes_per_pixel, u8* morton_data, u8* gl_data,
|
||||||
|
bool morton_to_gl) {
|
||||||
|
u8* data_ptrs[2];
|
||||||
|
for (unsigned y = 0; y < height; ++y) {
|
||||||
|
for (unsigned x = 0; x < width; ++x) {
|
||||||
|
const u32 coarse_y = y & ~127;
|
||||||
|
u32 morton_offset =
|
||||||
|
GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
|
||||||
|
u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel;
|
||||||
|
|
||||||
|
data_ptrs[morton_to_gl] = morton_data + morton_offset;
|
||||||
|
data_ptrs[!morton_to_gl] = &gl_data[gl_pixel_index];
|
||||||
|
|
||||||
|
memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace VideoCore
|
} // namespace VideoCore
|
||||||
|
|
|
@ -15,6 +15,8 @@ class RendererBase;
|
||||||
|
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
|
|
||||||
|
enum class Renderer { Software, OpenGL };
|
||||||
|
|
||||||
extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin
|
extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin
|
||||||
extern EmuWindow* g_emu_window; ///< Emu window
|
extern EmuWindow* g_emu_window; ///< Emu window
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue