forked from suyu/suyu
41a4090320
Switch games are allowed to bind less data than what they use in a vertex buffer, the expected behavior here is that these values are read as zero. At the moment of writing this only D3D12, OpenGL and NVN through NV_vertex_buffer_unified_memory support vertex buffer with a size limit. In theory this could be emulated on Vulkan creating a new VkBuffer for each (handle, offset, length) tuple and binding the expected data to it. This is likely going to be slow and memory expensive when used on the vertex buffer and we have to do it on all draws because we can't know without analyzing indices when a game is going to read vertex data out of bounds. This is not a problem on OpenGL's BufferAddressRangeNV because it takes a length parameter, unlike Vulkan's CmdBindVertexBuffers that only takes buffers and offsets (the length is implicit in VkBuffer). It isn't a problem on D3D12 either, because D3D12_VERTEX_BUFFER_VIEW on IASetVertexBuffers takes SizeInBytes as a parameter (although I am not familiar with robustness on D3D12). Currently this only implements buffer ranges for vertex buffers, although indices can also be affected. A KHR_robustness profile is not created, but Nvidia's driver reads out of bound vertex data as zero anyway, this might have to be changed in the future. - Fixes SMO random triangles when capturing an enemy, getting hit, or looking at the environment on certain maps.
132 lines
3.7 KiB
C++
132 lines
3.7 KiB
C++
// Copyright 2014 Citra Emulator Project
|
|
// Licensed under GPLv2 or any later version
|
|
// Refer to the license.txt file included.
|
|
|
|
#pragma once
|
|
|
|
#include <vector>
|
|
#include <glad/glad.h>
|
|
#include "common/common_types.h"
|
|
#include "common/math_util.h"
|
|
#include "video_core/renderer_base.h"
|
|
#include "video_core/renderer_opengl/gl_device.h"
|
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
|
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
|
#include "video_core/renderer_opengl/gl_state_tracker.h"
|
|
|
|
namespace Core {
|
|
class System;
|
|
}
|
|
|
|
namespace Core::Frontend {
|
|
class EmuWindow;
|
|
}
|
|
|
|
namespace Layout {
|
|
struct FramebufferLayout;
|
|
}
|
|
|
|
namespace OpenGL {
|
|
|
|
/// Structure used for storing information about the textures for the Switch screen
|
|
struct TextureInfo {
|
|
OGLTexture resource;
|
|
GLsizei width;
|
|
GLsizei height;
|
|
GLenum gl_format;
|
|
GLenum gl_type;
|
|
Tegra::FramebufferConfig::PixelFormat pixel_format;
|
|
};
|
|
|
|
/// Structure used for storing information about the display target for the Switch screen
|
|
struct ScreenInfo {
|
|
GLuint display_texture{};
|
|
bool display_srgb{};
|
|
const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f};
|
|
TextureInfo texture;
|
|
};
|
|
|
|
struct PresentationTexture {
|
|
u32 width = 0;
|
|
u32 height = 0;
|
|
OGLTexture texture;
|
|
};
|
|
|
|
class FrameMailbox;
|
|
|
|
class RendererOpenGL final : public VideoCore::RendererBase {
|
|
public:
|
|
explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system,
|
|
Core::Frontend::GraphicsContext& context);
|
|
~RendererOpenGL() override;
|
|
|
|
bool Init() override;
|
|
void ShutDown() override;
|
|
void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override;
|
|
bool TryPresent(int timeout_ms) override;
|
|
|
|
private:
|
|
/// Initializes the OpenGL state and creates persistent objects.
|
|
void InitOpenGLObjects();
|
|
|
|
void AddTelemetryFields();
|
|
|
|
void CreateRasterizer();
|
|
|
|
void ConfigureFramebufferTexture(TextureInfo& texture,
|
|
const Tegra::FramebufferConfig& framebuffer);
|
|
|
|
/// Draws the emulated screens to the emulator window.
|
|
void DrawScreen(const Layout::FramebufferLayout& layout);
|
|
|
|
void RenderScreenshot();
|
|
|
|
/// Loads framebuffer from emulated memory into the active OpenGL texture.
|
|
void LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer);
|
|
|
|
/// Fills active OpenGL texture with the given RGB color.Since the color is solid, the texture
|
|
/// can be 1x1 but will stretch across whatever it's rendered on.
|
|
void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
|
|
const TextureInfo& texture);
|
|
|
|
void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer);
|
|
|
|
bool Present(int timeout_ms);
|
|
|
|
Core::Frontend::EmuWindow& emu_window;
|
|
Core::System& system;
|
|
Core::Frontend::GraphicsContext& context;
|
|
const Device device;
|
|
|
|
StateTracker state_tracker{system};
|
|
|
|
// OpenGL object IDs
|
|
OGLBuffer vertex_buffer;
|
|
OGLProgram vertex_program;
|
|
OGLProgram fragment_program;
|
|
OGLPipeline pipeline;
|
|
OGLFramebuffer screenshot_framebuffer;
|
|
|
|
// GPU address of the vertex buffer
|
|
GLuint64EXT vertex_buffer_address = 0;
|
|
|
|
/// Display information for Switch screen
|
|
ScreenInfo screen_info;
|
|
|
|
/// Global dummy shader pipeline
|
|
ProgramManager program_manager;
|
|
|
|
/// OpenGL framebuffer data
|
|
std::vector<u8> gl_framebuffer_data;
|
|
|
|
/// Used for transforming the framebuffer orientation
|
|
Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags;
|
|
Common::Rectangle<int> framebuffer_crop_rect;
|
|
|
|
/// Frame presentation mailbox
|
|
std::unique_ptr<FrameMailbox> frame_mailbox;
|
|
|
|
bool has_debug_tool = false;
|
|
};
|
|
|
|
} // namespace OpenGL
|