mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-11-04 12:34:39 +08:00 
			
		
		
		
	
						commit
						a10baacf9e
					
				@ -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,
 | 
			
		||||
                offset, width, height, stride, format);
 | 
			
		||||
 | 
			
		||||
    using PixelFormat = RendererBase::FramebufferInfo::PixelFormat;
 | 
			
		||||
    using Flags = NVFlinger::BufferQueue::BufferTransformFlags;
 | 
			
		||||
    const bool flip_vertical = static_cast<u32>(transform) & static_cast<u32>(Flags::FlipV);
 | 
			
		||||
    const RendererBase::FramebufferInfo framebuffer_info{
 | 
			
		||||
        addr, offset, width, height, stride, static_cast<PixelFormat>(format), flip_vertical};
 | 
			
		||||
    using PixelFormat = Tegra::FramebufferConfig::PixelFormat;
 | 
			
		||||
    const Tegra::FramebufferConfig framebuffer{
 | 
			
		||||
        addr, offset, width, height, stride, static_cast<PixelFormat>(format), transform};
 | 
			
		||||
 | 
			
		||||
    Core::System::GetInstance().perf_stats.EndGameFrame();
 | 
			
		||||
    VideoCore::g_renderer->SwapBuffers(framebuffer_info);
 | 
			
		||||
 | 
			
		||||
    VideoCore::g_renderer->SwapBuffers(framebuffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Devices
 | 
			
		||||
 | 
			
		||||
@ -47,6 +47,8 @@ public:
 | 
			
		||||
    ~BufferQueue() = default;
 | 
			
		||||
 | 
			
		||||
    enum class BufferTransformFlags : u32 {
 | 
			
		||||
        /// No transform flags are set
 | 
			
		||||
        Unset = 0x00,
 | 
			
		||||
        /// Flip source image horizontally (around the vertical axis)
 | 
			
		||||
        FlipH = 0x01,
 | 
			
		||||
        /// 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,
 | 
			
		||||
              (base + size) * PAGE_SIZE);
 | 
			
		||||
 | 
			
		||||
    RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE,
 | 
			
		||||
                                 FlushMode::FlushAndInvalidate);
 | 
			
		||||
 | 
			
		||||
    VAddr end = base + size;
 | 
			
		||||
    while (base != end) {
 | 
			
		||||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
    return Read<u8>(addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,10 @@ enum class PageType : u8 {
 | 
			
		||||
    Unmapped,
 | 
			
		||||
    /// Page is mapped to regular memory. This is the only type you can get pointers to.
 | 
			
		||||
    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,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -242,4 +245,19 @@ boost::optional<VAddr> PhysicalToVirtualAddress(PAddr addr);
 | 
			
		||||
 */
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/bit_field.h"
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
@ -62,6 +63,107 @@ public:
 | 
			
		||||
            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 {
 | 
			
		||||
            struct {
 | 
			
		||||
                INSERT_PADDING_WORDS(0x200);
 | 
			
		||||
@ -112,8 +214,8 @@ public:
 | 
			
		||||
                    BitField<0, 5, u32> buffer;
 | 
			
		||||
                    BitField<6, 1, u32> constant;
 | 
			
		||||
                    BitField<7, 14, u32> offset;
 | 
			
		||||
                    BitField<21, 6, u32> size;
 | 
			
		||||
                    BitField<27, 3, u32> type;
 | 
			
		||||
                    BitField<21, 6, VertexSize> size;
 | 
			
		||||
                    BitField<27, 3, VertexType> type;
 | 
			
		||||
                    BitField<31, 1, u32> bgra;
 | 
			
		||||
                } vertex_attrib_format[NumVertexAttributes];
 | 
			
		||||
 | 
			
		||||
@ -163,13 +265,15 @@ public:
 | 
			
		||||
                    }
 | 
			
		||||
                } code_address;
 | 
			
		||||
                INSERT_PADDING_WORDS(1);
 | 
			
		||||
 | 
			
		||||
                struct {
 | 
			
		||||
                    u32 vertex_end_gl;
 | 
			
		||||
                    union {
 | 
			
		||||
                        u32 vertex_begin_gl;
 | 
			
		||||
                        BitField<0, 16, u32> topology;
 | 
			
		||||
                        BitField<0, 16, PrimitiveTopology> topology;
 | 
			
		||||
                    };
 | 
			
		||||
                } draw;
 | 
			
		||||
 | 
			
		||||
                INSERT_PADDING_WORDS(0x139);
 | 
			
		||||
                struct {
 | 
			
		||||
                    u32 query_address_high;
 | 
			
		||||
 | 
			
		||||
@ -8,10 +8,42 @@
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/service/nvflinger/buffer_queue.h"
 | 
			
		||||
#include "video_core/memory_manager.h"
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
class Fermi2D;
 | 
			
		||||
class Maxwell3D;
 | 
			
		||||
@ -36,6 +68,10 @@ public:
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<MemoryManager> memory_manager;
 | 
			
		||||
 | 
			
		||||
    Engines::Maxwell3D& Maxwell3D() {
 | 
			
		||||
        return *maxwell_3d;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static constexpr u32 InvalidGraphMacroEntry = 0xFFFFFFFF;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/gpu.h"
 | 
			
		||||
 | 
			
		||||
struct ScreenInfo;
 | 
			
		||||
 | 
			
		||||
@ -24,14 +25,14 @@ public:
 | 
			
		||||
    virtual void FlushAll() = 0;
 | 
			
		||||
 | 
			
		||||
    /// 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
 | 
			
		||||
    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
 | 
			
		||||
    /// 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
 | 
			
		||||
    virtual bool AccelerateDisplayTransfer(const void* config) {
 | 
			
		||||
@ -49,7 +50,8 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// 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) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,11 @@
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include "video_core/renderer_base.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_rasterizer.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 "common/assert.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/gpu.h"
 | 
			
		||||
#include "video_core/rasterizer_interface.h"
 | 
			
		||||
 | 
			
		||||
class EmuWindow;
 | 
			
		||||
 | 
			
		||||
@ -16,40 +18,10 @@ public:
 | 
			
		||||
    /// Used to reference a framebuffer
 | 
			
		||||
    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() {}
 | 
			
		||||
 | 
			
		||||
    /// 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
 | 
			
		||||
@ -74,12 +46,16 @@ public:
 | 
			
		||||
        return m_current_frame;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VideoCore::RasterizerInterface* Rasterizer() const {
 | 
			
		||||
        return rasterizer.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void RefreshRasterizerSetting();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    std::unique_ptr<VideoCore::RasterizerInterface> rasterizer;
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool opengl_rasterizer_active = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -54,6 +54,8 @@ static void SetShaderUniformBlockBindings(GLuint shader) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RasterizerOpenGL::RasterizerOpenGL() {
 | 
			
		||||
    shader_dirty = true;
 | 
			
		||||
 | 
			
		||||
    has_ARB_buffer_storage = false;
 | 
			
		||||
    has_ARB_direct_state_access = false;
 | 
			
		||||
    has_ARB_separate_shader_objects = false;
 | 
			
		||||
@ -106,8 +108,6 @@ RasterizerOpenGL::RasterizerOpenGL() {
 | 
			
		||||
        state.draw.vertex_buffer = stream_buffer->GetHandle();
 | 
			
		||||
 | 
			
		||||
        pipeline.Create();
 | 
			
		||||
        vs_input_index_min = 0;
 | 
			
		||||
        vs_input_index_max = 0;
 | 
			
		||||
        state.draw.program_pipeline = pipeline.handle;
 | 
			
		||||
        state.draw.shader_program = 0;
 | 
			
		||||
        state.draw.vertex_array = hw_vao.handle;
 | 
			
		||||
@ -120,20 +120,14 @@ RasterizerOpenGL::RasterizerOpenGL() {
 | 
			
		||||
        glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY);
 | 
			
		||||
        glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle);
 | 
			
		||||
    } else {
 | 
			
		||||
        UNIMPLEMENTED();
 | 
			
		||||
        ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    accelerate_draw = AccelDraw::Disabled;
 | 
			
		||||
 | 
			
		||||
    glEnable(GL_BLEND);
 | 
			
		||||
 | 
			
		||||
    // Sync fixed function OpenGL state
 | 
			
		||||
    SyncClipEnabled();
 | 
			
		||||
    SyncClipCoef();
 | 
			
		||||
    SyncCullMode();
 | 
			
		||||
    SyncBlendEnabled();
 | 
			
		||||
    SyncBlendFuncs();
 | 
			
		||||
    SyncBlendColor();
 | 
			
		||||
    LOG_WARNING(HW_GPU, "Sync fixed function OpenGL state here when ready");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RasterizerOpenGL::~RasterizerOpenGL() {
 | 
			
		||||
@ -167,12 +161,12 @@ void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_FS);
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
 | 
			
		||||
    if (!has_ARB_separate_shader_objects) {
 | 
			
		||||
        UNIMPLEMENTED();
 | 
			
		||||
        ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -194,17 +188,17 @@ void RasterizerOpenGL::FlushAll() {
 | 
			
		||||
    res_cache.FlushAll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) {
 | 
			
		||||
void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_CacheManagement);
 | 
			
		||||
    res_cache.FlushRegion(addr, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) {
 | 
			
		||||
void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_CacheManagement);
 | 
			
		||||
    res_cache.InvalidateRegion(addr, size, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
 | 
			
		||||
void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_CacheManagement);
 | 
			
		||||
    res_cache.FlushRegion(addr, size);
 | 
			
		||||
    res_cache.InvalidateRegion(addr, size, nullptr);
 | 
			
		||||
@ -212,58 +206,144 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
 | 
			
		||||
 | 
			
		||||
bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_Blits);
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RasterizerOpenGL::AccelerateFill(const void* config) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RasterizerOpenGL::AccelerateDisplay(const void* config, PAddr framebuffer_addr,
 | 
			
		||||
                                         u32 pixel_stride, ScreenInfo& screen_info) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer,
 | 
			
		||||
                                         VAddr framebuffer_addr, u32 pixel_stride,
 | 
			
		||||
                                         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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncClipCoef() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncCullMode() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncDepthScale() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncDepthOffset() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncBlendEnabled() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncBlendFuncs() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncBlendColor() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -32,16 +32,22 @@ public:
 | 
			
		||||
    void DrawTriangles() override;
 | 
			
		||||
    void NotifyMaxwellRegisterChanged(u32 id) override;
 | 
			
		||||
    void FlushAll() override;
 | 
			
		||||
    void FlushRegion(PAddr addr, u32 size) override;
 | 
			
		||||
    void InvalidateRegion(PAddr addr, u32 size) override;
 | 
			
		||||
    void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
 | 
			
		||||
    void FlushRegion(VAddr addr, u64 size) override;
 | 
			
		||||
    void InvalidateRegion(VAddr addr, u64 size) override;
 | 
			
		||||
    void FlushAndInvalidateRegion(VAddr addr, u64 size) override;
 | 
			
		||||
    bool AccelerateDisplayTransfer(const void* config) override;
 | 
			
		||||
    bool AccelerateTextureCopy(const void* config) override;
 | 
			
		||||
    bool AccelerateFill(const void* config) override;
 | 
			
		||||
    bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride,
 | 
			
		||||
                           ScreenInfo& screen_info) override;
 | 
			
		||||
    bool AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer, VAddr framebuffer_addr,
 | 
			
		||||
                           u32 pixel_stride, ScreenInfo& screen_info) 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 {
 | 
			
		||||
        OGLShader shader;
 | 
			
		||||
    };
 | 
			
		||||
@ -117,6 +123,12 @@ private:
 | 
			
		||||
 | 
			
		||||
    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 {
 | 
			
		||||
        UniformData data;
 | 
			
		||||
        bool dirty;
 | 
			
		||||
@ -136,8 +148,6 @@ private:
 | 
			
		||||
    static constexpr size_t STREAM_BUFFER_SIZE = 4 * 1024 * 1024;
 | 
			
		||||
    std::unique_ptr<OGLStreamBuffer> stream_buffer;
 | 
			
		||||
 | 
			
		||||
    GLint vs_input_index_min;
 | 
			
		||||
    GLint vs_input_index_max;
 | 
			
		||||
    GLsizeiptr vs_input_size;
 | 
			
		||||
 | 
			
		||||
    void AnalyzeVertexArray(bool is_indexed);
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,7 @@
 | 
			
		||||
#include "common/scope_exit.h"
 | 
			
		||||
#include "common/vector_math.h"
 | 
			
		||||
#include "core/frontend/emu_window.h"
 | 
			
		||||
#include "core/hle/kernel/vm_manager.h"
 | 
			
		||||
#include "core/memory.h"
 | 
			
		||||
#include "core/settings.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>
 | 
			
		||||
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 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, "");
 | 
			
		||||
    gl_buffer += gl_bytes_per_pixel - bytes_per_pixel;
 | 
			
		||||
 | 
			
		||||
    const PAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size);
 | 
			
		||||
    const PAddr aligned_start = base + Common::AlignUp(start - base, tile_size);
 | 
			
		||||
    const PAddr aligned_end = base + Common::AlignDown(end - base, tile_size);
 | 
			
		||||
    const VAddr aligned_down_start = base + Common::AlignDown(start - base, tile_size);
 | 
			
		||||
    const VAddr aligned_start = base + Common::AlignUp(start - base, tile_size);
 | 
			
		||||
    const VAddr aligned_end = base + Common::AlignDown(end - base, tile_size);
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        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::RGB8>,   // 1
 | 
			
		||||
    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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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::RGB8>,   // 1
 | 
			
		||||
    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,
 | 
			
		||||
                        const MathUtil::Rectangle<u32>& fill_rect, GLuint draw_fb_handle) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -298,9 +299,9 @@ SurfaceParams SurfaceParams::FromInterval(SurfaceInterval interval) const {
 | 
			
		||||
    SurfaceParams params = *this;
 | 
			
		||||
    const u32 tiled_size = is_tiled ? 8 : 1;
 | 
			
		||||
    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);
 | 
			
		||||
    PAddr aligned_end =
 | 
			
		||||
    VAddr aligned_end =
 | 
			
		||||
        addr + Common::AlignUp(boost::icl::last_next(interval) - addr, 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));
 | 
			
		||||
void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
 | 
			
		||||
void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) {
 | 
			
		||||
    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)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
@ -539,35 +540,25 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
    ASSERT(load_start >= addr && load_end <= end);
 | 
			
		||||
    const u32 start_offset = load_start - addr;
 | 
			
		||||
    const u64 start_offset = load_start - addr;
 | 
			
		||||
 | 
			
		||||
    if (!is_tiled) {
 | 
			
		||||
        ASSERT(type == SurfaceType::Color);
 | 
			
		||||
        std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset,
 | 
			
		||||
                    load_end - load_start);
 | 
			
		||||
        const u32 bytes_per_pixel{GetFormatBpp() >> 3};
 | 
			
		||||
        VideoCore::MortonCopyPixels128(width, height, bytes_per_pixel, 4,
 | 
			
		||||
                                       texture_src_data + start_offset, &gl_buffer[start_offset],
 | 
			
		||||
                                       true);
 | 
			
		||||
    } else {
 | 
			
		||||
        if (type == SurfaceType::Texture) {
 | 
			
		||||
            UNIMPLEMENTED();
 | 
			
		||||
        } else {
 | 
			
		||||
            morton_to_gl_fns[static_cast<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr,
 | 
			
		||||
                                                                load_start, load_end);
 | 
			
		||||
        }
 | 
			
		||||
        ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
 | 
			
		||||
void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) {
 | 
			
		||||
    u8* const dst_buffer = Memory::GetPhysicalPointer(addr);
 | 
			
		||||
void CachedSurface::FlushGLBuffer(VAddr flush_start, VAddr flush_end) {
 | 
			
		||||
    u8* const dst_buffer = Memory::GetPointer(addr);
 | 
			
		||||
    if (dst_buffer == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
@ -1102,7 +1093,7 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams&
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1113,7 +1104,7 @@ SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Surface RasterizerCacheOpenGL::GetFillSurface(const void* config) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
    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)
 | 
			
		||||
        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)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
@ -1260,10 +1251,10 @@ void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u64 size, Surface flush_surf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
@ -1356,6 +1347,6 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
 | 
			
		||||
    surface_cache.subtract({surface->GetInterval(), SurfaceSet{surface}});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u64 size, int delta) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
void RasterizerCacheOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
 | 
			
		||||
    // ASSERT_MSG(false, "Unimplemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -22,15 +22,16 @@
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/math_util.h"
 | 
			
		||||
#include "video_core/gpu.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
 | 
			
		||||
 | 
			
		||||
struct CachedSurface;
 | 
			
		||||
using Surface = std::shared_ptr<CachedSurface>;
 | 
			
		||||
using SurfaceSet = std::set<Surface>;
 | 
			
		||||
 | 
			
		||||
using SurfaceRegions = boost::icl::interval_set<PAddr>;
 | 
			
		||||
using SurfaceMap = boost::icl::interval_map<PAddr, Surface>;
 | 
			
		||||
using SurfaceCache = boost::icl::interval_map<PAddr, SurfaceSet>;
 | 
			
		||||
using SurfaceRegions = boost::icl::interval_set<VAddr>;
 | 
			
		||||
using SurfaceMap = boost::icl::interval_map<VAddr, Surface>;
 | 
			
		||||
using SurfaceCache = boost::icl::interval_map<VAddr, SurfaceSet>;
 | 
			
		||||
 | 
			
		||||
using SurfaceInterval = SurfaceCache::interval_type;
 | 
			
		||||
static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval_type>() &&
 | 
			
		||||
@ -115,6 +116,15 @@ struct SurfaceParams {
 | 
			
		||||
        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) {
 | 
			
		||||
        SurfaceType a_type = GetFormatType(pixel_format_a);
 | 
			
		||||
        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> GetScaledSubRect(const SurfaceParams& sub_surface) const;
 | 
			
		||||
 | 
			
		||||
    PAddr addr = 0;
 | 
			
		||||
    PAddr end = 0;
 | 
			
		||||
    VAddr addr = 0;
 | 
			
		||||
    VAddr end = 0;
 | 
			
		||||
    u64 size = 0;
 | 
			
		||||
 | 
			
		||||
    u32 width = 0;
 | 
			
		||||
@ -257,9 +267,9 @@ struct CachedSurface : SurfaceParams {
 | 
			
		||||
    std::unique_ptr<u8[]> gl_buffer;
 | 
			
		||||
    size_t gl_buffer_size = 0;
 | 
			
		||||
 | 
			
		||||
    // Read/Write data in 3DS memory to/from gl_buffer
 | 
			
		||||
    void LoadGLBuffer(PAddr load_start, PAddr load_end);
 | 
			
		||||
    void FlushGLBuffer(PAddr flush_start, PAddr flush_end);
 | 
			
		||||
    // Read/Write data in Switch memory to/from gl_buffer
 | 
			
		||||
    void LoadGLBuffer(VAddr load_start, VAddr load_end);
 | 
			
		||||
    void FlushGLBuffer(VAddr flush_start, VAddr flush_end);
 | 
			
		||||
 | 
			
		||||
    // Upload/Download data in gl_buffer in/to this surface's texture
 | 
			
		||||
    void UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
 | 
			
		||||
@ -307,10 +317,10 @@ public:
 | 
			
		||||
    SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params);
 | 
			
		||||
 | 
			
		||||
    /// 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)
 | 
			
		||||
    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
 | 
			
		||||
    void FlushAll();
 | 
			
		||||
@ -319,7 +329,7 @@ private:
 | 
			
		||||
    void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface);
 | 
			
		||||
 | 
			
		||||
    /// 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
 | 
			
		||||
    Surface CreateSurface(const SurfaceParams& params);
 | 
			
		||||
@ -331,7 +341,7 @@ private:
 | 
			
		||||
    void UnregisterSurface(const Surface& surface);
 | 
			
		||||
 | 
			
		||||
    /// 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;
 | 
			
		||||
    PageMap cached_pages;
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
#include "core/tracer/recorder.h"
 | 
			
		||||
#include "video_core/renderer_opengl/renderer_opengl.h"
 | 
			
		||||
#include "video_core/utils.h"
 | 
			
		||||
#include "video_core/video_core.h"
 | 
			
		||||
 | 
			
		||||
static const char vertex_shader[] = R"(
 | 
			
		||||
@ -98,22 +99,22 @@ RendererOpenGL::RendererOpenGL() = default;
 | 
			
		||||
RendererOpenGL::~RendererOpenGL() = default;
 | 
			
		||||
 | 
			
		||||
/// 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
 | 
			
		||||
    OpenGLState prev_state = OpenGLState::GetCurState();
 | 
			
		||||
    state.Apply();
 | 
			
		||||
 | 
			
		||||
    if (framebuffer_info != boost::none) {
 | 
			
		||||
        // If framebuffer_info is provided, reload it from memory to a texture
 | 
			
		||||
        if (screen_info.texture.width != (GLsizei)framebuffer_info->width ||
 | 
			
		||||
            screen_info.texture.height != (GLsizei)framebuffer_info->height ||
 | 
			
		||||
            screen_info.texture.pixel_format != framebuffer_info->pixel_format) {
 | 
			
		||||
    if (framebuffer != boost::none) {
 | 
			
		||||
        // If framebuffer is provided, reload it from memory to a texture
 | 
			
		||||
        if (screen_info.texture.width != (GLsizei)framebuffer->width ||
 | 
			
		||||
            screen_info.texture.height != (GLsizei)framebuffer->height ||
 | 
			
		||||
            screen_info.texture.pixel_format != framebuffer->pixel_format) {
 | 
			
		||||
            // Reallocate texture if the framebuffer size has changed.
 | 
			
		||||
            // This is expected to not happen very often and hence should not be a
 | 
			
		||||
            // performance problem.
 | 
			
		||||
            ConfigureFramebufferTexture(screen_info.texture, *framebuffer_info);
 | 
			
		||||
            ConfigureFramebufferTexture(screen_info.texture, *framebuffer);
 | 
			
		||||
        }
 | 
			
		||||
        LoadFBToScreenInfo(*framebuffer_info, screen_info);
 | 
			
		||||
        LoadFBToScreenInfo(*framebuffer, screen_info);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DrawScreens();
 | 
			
		||||
@ -131,164 +132,59 @@ void RendererOpenGL::SwapBuffers(boost::optional<const FramebufferInfo&> framebu
 | 
			
		||||
    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.
 | 
			
		||||
 */
 | 
			
		||||
void RendererOpenGL::LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info,
 | 
			
		||||
void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer,
 | 
			
		||||
                                        ScreenInfo& screen_info) {
 | 
			
		||||
    const u32 bpp{FramebufferInfo::BytesPerPixel(framebuffer_info.pixel_format)};
 | 
			
		||||
    const u32 size_in_bytes{framebuffer_info.stride * framebuffer_info.height * bpp};
 | 
			
		||||
    const u32 bytes_per_pixel{Tegra::FramebufferConfig::BytesPerPixel(framebuffer.pixel_format)};
 | 
			
		||||
    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,
 | 
			
		||||
                        Memory::GetPointer(framebuffer_info.address), gl_framebuffer_data.data(),
 | 
			
		||||
                        true);
 | 
			
		||||
    // TODO(bunnei): The framebuffer region should only be invalidated if it is written to, not
 | 
			
		||||
    // every frame. When we find the right place for this, the below line can be removed.
 | 
			
		||||
    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_info.address, framebuffer_info.width, framebuffer_info.height,
 | 
			
		||||
              (int)framebuffer_info.pixel_format);
 | 
			
		||||
    // Framebuffer orientation handling
 | 
			
		||||
    framebuffer_transform_flags = framebuffer.transform_flags;
 | 
			
		||||
 | 
			
		||||
    // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
 | 
			
		||||
    // 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
 | 
			
		||||
        screen_info.display_texture = screen_info.texture.resource.handle;
 | 
			
		||||
        screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
 | 
			
		||||
 | 
			
		||||
    // Reset the screen info's display texture to its own permanent texture
 | 
			
		||||
    screen_info.display_texture = screen_info.texture.resource.handle;
 | 
			
		||||
    screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
 | 
			
		||||
        Rasterizer()->FlushRegion(framebuffer_addr, size_in_bytes);
 | 
			
		||||
 | 
			
		||||
    // Memory::RasterizerFlushRegion(framebuffer_info.address, 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.Apply();
 | 
			
		||||
        state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
 | 
			
		||||
        state.Apply();
 | 
			
		||||
 | 
			
		||||
    glActiveTexture(GL_TEXTURE0);
 | 
			
		||||
    glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)framebuffer_info.stride);
 | 
			
		||||
        glActiveTexture(GL_TEXTURE0);
 | 
			
		||||
        glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
 | 
			
		||||
 | 
			
		||||
    // Update existing texture
 | 
			
		||||
    // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
 | 
			
		||||
    //       they differ from the LCD resolution.
 | 
			
		||||
    // TODO: Applications could theoretically crash Citra here by specifying too large
 | 
			
		||||
    //       framebuffer sizes. We should make sure that this cannot happen.
 | 
			
		||||
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer_info.width, framebuffer_info.height,
 | 
			
		||||
                    screen_info.texture.gl_format, screen_info.texture.gl_type,
 | 
			
		||||
                    gl_framebuffer_data.data());
 | 
			
		||||
        // Update existing texture
 | 
			
		||||
        // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
 | 
			
		||||
        //       they differ from the LCD resolution.
 | 
			
		||||
        // TODO: Applications could theoretically crash yuzu here by specifying too large
 | 
			
		||||
        //       framebuffer sizes. We should make sure that this cannot happen.
 | 
			
		||||
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
 | 
			
		||||
                        screen_info.texture.gl_format, screen_info.texture.gl_type,
 | 
			
		||||
                        gl_framebuffer_data.data());
 | 
			
		||||
 | 
			
		||||
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 | 
			
		||||
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 | 
			
		||||
 | 
			
		||||
    state.texture_units[0].texture_2d = 0;
 | 
			
		||||
    state.Apply();
 | 
			
		||||
        state.texture_units[0].texture_2d = 0;
 | 
			
		||||
        state.Apply();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -372,14 +268,14 @@ void RendererOpenGL::InitOpenGLObjects() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
 | 
			
		||||
                                                 const FramebufferInfo& framebuffer_info) {
 | 
			
		||||
                                                 const Tegra::FramebufferConfig& framebuffer) {
 | 
			
		||||
 | 
			
		||||
    texture.width = framebuffer_info.width;
 | 
			
		||||
    texture.height = framebuffer_info.height;
 | 
			
		||||
    texture.width = framebuffer.width;
 | 
			
		||||
    texture.height = framebuffer.height;
 | 
			
		||||
 | 
			
		||||
    GLint internal_format;
 | 
			
		||||
    switch (framebuffer_info.pixel_format) {
 | 
			
		||||
    case FramebufferInfo::PixelFormat::ABGR8:
 | 
			
		||||
    switch (framebuffer.pixel_format) {
 | 
			
		||||
    case Tegra::FramebufferConfig::PixelFormat::ABGR8:
 | 
			
		||||
        // Use RGBA8 and swap in the fragment shader
 | 
			
		||||
        internal_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,
 | 
			
		||||
                                      float h) {
 | 
			
		||||
    const auto& texcoords = screen_info.display_texcoords;
 | 
			
		||||
    const auto& left = framebuffer_flip_vertical ? texcoords.right : texcoords.left;
 | 
			
		||||
    const auto& right = framebuffer_flip_vertical ? texcoords.left : texcoords.right;
 | 
			
		||||
    auto left = texcoords.left;
 | 
			
		||||
    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 = {{
 | 
			
		||||
        ScreenRectVertex(x, y, texcoords.top, right),
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ struct TextureInfo {
 | 
			
		||||
    GLsizei height;
 | 
			
		||||
    GLenum gl_format;
 | 
			
		||||
    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
 | 
			
		||||
@ -37,7 +37,7 @@ public:
 | 
			
		||||
    ~RendererOpenGL() override;
 | 
			
		||||
 | 
			
		||||
    /// 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
 | 
			
		||||
@ -53,13 +53,14 @@ public:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void InitOpenGLObjects();
 | 
			
		||||
    void ConfigureFramebufferTexture(TextureInfo& texture, const FramebufferInfo& framebuffer_info);
 | 
			
		||||
    void ConfigureFramebufferTexture(TextureInfo& texture,
 | 
			
		||||
                                     const Tegra::FramebufferConfig& framebuffer);
 | 
			
		||||
    void DrawScreens();
 | 
			
		||||
    void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h);
 | 
			
		||||
    void UpdateFramerate();
 | 
			
		||||
 | 
			
		||||
    // 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.
 | 
			
		||||
    void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
 | 
			
		||||
                                    const TextureInfo& texture);
 | 
			
		||||
@ -87,6 +88,6 @@ private:
 | 
			
		||||
    GLuint attrib_position;
 | 
			
		||||
    GLuint attrib_tex_coord;
 | 
			
		||||
 | 
			
		||||
    /// Flips the framebuffer vertically when true
 | 
			
		||||
    bool framebuffer_flip_vertical;
 | 
			
		||||
    /// Used for transforming the framebuffer orientation
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,8 @@ class RendererBase;
 | 
			
		||||
 | 
			
		||||
namespace VideoCore {
 | 
			
		||||
 | 
			
		||||
enum class Renderer { Software, OpenGL };
 | 
			
		||||
 | 
			
		||||
extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin
 | 
			
		||||
extern EmuWindow* g_emu_window;                  ///< Emu window
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user