mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-17 08:57:53 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ba504b19c |
@@ -40,12 +40,6 @@ bool IsConnectionBased(Type type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size of a real BSD sockaddr_in. The guest SockAddrIn struct is padded to 0x100 so that longer
|
|
||||||
// input addresses can be read, but an address handed back to the game is always this long.
|
|
||||||
// Reporting 0x100 lets a game that trusts the length copy 240 bytes past its 16-byte sockaddr
|
|
||||||
// (suspected cause of Crysis Remastered crashing ~30 s after its getsockname() call).
|
|
||||||
constexpr size_t GuestSockAddrInSize = 16;
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T GetValue(std::span<const u8> buffer) {
|
T GetValue(std::span<const u8> buffer) {
|
||||||
T t{};
|
T t{};
|
||||||
@@ -661,9 +655,6 @@ std::pair<s32, Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& write_buffer)
|
|||||||
new_descriptor.is_connection_based = descriptor.is_connection_based;
|
new_descriptor.is_connection_based = descriptor.is_connection_based;
|
||||||
|
|
||||||
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
|
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
|
||||||
if (write_buffer.size() > GuestSockAddrInSize) {
|
|
||||||
write_buffer.resize(GuestSockAddrInSize);
|
|
||||||
}
|
|
||||||
PutValue(write_buffer, guest_addr_in);
|
PutValue(write_buffer, guest_addr_in);
|
||||||
|
|
||||||
return {new_fd, Errno::SUCCESS};
|
return {new_fd, Errno::SUCCESS};
|
||||||
@@ -723,8 +714,8 @@ Errno BSD_USA::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
|||||||
}
|
}
|
||||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
const SockAddrIn guest_addrin = Translate(addr_in);
|
||||||
|
|
||||||
// The reported length must be that of a real sockaddr_in, not of the padded guest struct.
|
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
||||||
write_buffer.resize(GuestSockAddrInSize);
|
write_buffer.resize(sizeof(guest_addrin));
|
||||||
PutValue(write_buffer, guest_addrin);
|
PutValue(write_buffer, guest_addrin);
|
||||||
return Translate(bsd_errno);
|
return Translate(bsd_errno);
|
||||||
}
|
}
|
||||||
@@ -745,8 +736,8 @@ Errno BSD_USA::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
|||||||
}
|
}
|
||||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
const SockAddrIn guest_addrin = Translate(addr_in);
|
||||||
|
|
||||||
// The reported length must be that of a real sockaddr_in, not of the padded guest struct.
|
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
||||||
write_buffer.resize(GuestSockAddrInSize);
|
write_buffer.resize(sizeof(guest_addrin));
|
||||||
PutValue(write_buffer, guest_addrin);
|
PutValue(write_buffer, guest_addrin);
|
||||||
return Translate(bsd_errno);
|
return Translate(bsd_errno);
|
||||||
}
|
}
|
||||||
@@ -958,9 +949,8 @@ std::pair<s32, Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>&
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
addr.clear();
|
addr.clear();
|
||||||
} else {
|
} else {
|
||||||
ASSERT(addr.size() >= GuestSockAddrInSize);
|
ASSERT(addr.size() >= 16);
|
||||||
const SockAddrIn result = Translate(addr_in);
|
const SockAddrIn result = Translate(addr_in);
|
||||||
addr.resize(GuestSockAddrInSize);
|
|
||||||
PutValue(addr, result);
|
PutValue(addr, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -563,8 +563,10 @@ void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BeginRenderPass(vk::CommandBuffer& cmdbuf, VkRenderPass render_pass,
|
void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
|
||||||
VkFramebuffer framebuffer_handle, VkExtent2D render_area) {
|
const VkRenderPass render_pass = framebuffer->RenderPass();
|
||||||
|
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
||||||
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
const VkRenderPassBeginInfo renderpass_bi{
|
const VkRenderPassBeginInfo renderpass_bi{
|
||||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
@@ -677,67 +679,27 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
|
|||||||
void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
|
void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
|
||||||
VkImage src_image, VkSampler src_sampler,
|
VkImage src_image, VkSampler src_sampler,
|
||||||
const Region2D& dst_region, const Region2D& src_region,
|
const Region2D& dst_region, const Region2D& src_region,
|
||||||
const Extent3D& src_size,
|
const Extent3D& src_size) {
|
||||||
const std::optional<VkRect2D>& scissor) {
|
|
||||||
const BlitImagePipelineKey key{
|
const BlitImagePipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.operation = Tegra::Engines::Fermi2D::Operation::SrcCopy,
|
.operation = Tegra::Engines::Fermi2D::Operation::SrcCopy,
|
||||||
};
|
};
|
||||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||||
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
|
||||||
|
|
||||||
// Clip the destination rectangle to the scissor; the viewport keeps the full rectangle so
|
|
||||||
// the texture coordinates are unchanged.
|
|
||||||
std::optional<VkRect2D> clip;
|
|
||||||
if (scissor) {
|
|
||||||
const s64 x0 = (std::max)(s64{(std::min)(dst_region.start.x, dst_region.end.x)},
|
|
||||||
s64{scissor->offset.x});
|
|
||||||
const s64 y0 = (std::max)(s64{(std::min)(dst_region.start.y, dst_region.end.y)},
|
|
||||||
s64{scissor->offset.y});
|
|
||||||
const s64 x1 = (std::min)(s64{(std::max)(dst_region.start.x, dst_region.end.x)},
|
|
||||||
s64{scissor->offset.x} + scissor->extent.width);
|
|
||||||
const s64 y1 = (std::min)(s64{(std::max)(dst_region.start.y, dst_region.end.y)},
|
|
||||||
s64{scissor->offset.y} + scissor->extent.height);
|
|
||||||
if (x1 <= x0 || y1 <= y0) {
|
|
||||||
return; // Fully scissored out.
|
|
||||||
}
|
|
||||||
clip = VkRect2D{
|
|
||||||
.offset = {static_cast<s32>(x0), static_cast<s32>(y0)},
|
|
||||||
.extent = {static_cast<u32>(x1 - x0), static_cast<u32>(y1 - y0)},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the framebuffer now: by the time the worker runs this, the texture cache may have
|
|
||||||
// retired it (moved into its delayed-destruction ring), leaving a null handle behind - Turnip
|
|
||||||
// then crashed in vkCmdBeginRenderPass (Crysis Remastered, DrawTexture).
|
|
||||||
const VkRenderPass render_pass = dst_framebuffer->RenderPass();
|
|
||||||
const VkFramebuffer framebuffer_handle = dst_framebuffer->Handle();
|
|
||||||
const VkExtent2D render_area = dst_framebuffer->RenderArea();
|
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([this, render_pass, framebuffer_handle, render_area, src_image_view,
|
scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region,
|
||||||
src_image, src_sampler, dst_region, src_region, src_size, pipeline, layout,
|
src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
|
||||||
clip](vk::CommandBuffer cmdbuf) {
|
TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
// Images stay in GENERAL everywhere (the descriptor below says so too): only make the
|
BeginRenderPass(cmdbuf, dst_framebuffer);
|
||||||
// earlier writes visible. Moving the source to SHADER_READ_ONLY_OPTIMAL left it there
|
|
||||||
// for good, so every later render pass used it in the wrong layout.
|
|
||||||
TransitionImageLayout(cmdbuf, src_image, VK_IMAGE_LAYOUT_GENERAL);
|
|
||||||
BeginRenderPass(cmdbuf, render_pass, framebuffer_handle, render_area);
|
|
||||||
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
|
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
|
||||||
UpdateOneTextureDescriptorSet(device, descriptor_set, src_sampler, src_image_view);
|
UpdateOneTextureDescriptorSet(device, descriptor_set, src_sampler, src_image_view);
|
||||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||||
nullptr);
|
nullptr);
|
||||||
BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
|
BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
|
||||||
if (clip) {
|
|
||||||
cmdbuf.SetScissor(0, *clip);
|
|
||||||
}
|
|
||||||
cmdbuf.Draw(3, 1, 0, 0);
|
cmdbuf.Draw(3, 1, 0, 0);
|
||||||
cmdbuf.EndRenderPass();
|
cmdbuf.EndRenderPass();
|
||||||
});
|
});
|
||||||
// The blit set its own pipeline, viewport and scissor: make the next draw set its own again,
|
|
||||||
// as every other helper here does. Without this the next draw kept the blit's viewport and
|
|
||||||
// scissor: Crysis Remastered drew its 256x256 minimap map over the whole screen.
|
|
||||||
scheduler.InvalidateState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::BlitImpl(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::BlitImpl(const Framebuffer* dst_framebuffer,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <optional>
|
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
#include "video_core/engines/fermi_2d.h"
|
#include "video_core/engines/fermi_2d.h"
|
||||||
@@ -79,12 +78,9 @@ public:
|
|||||||
Tegra::Engines::Fermi2D::Filter filter,
|
Tegra::Engines::Fermi2D::Filter filter,
|
||||||
Tegra::Engines::Fermi2D::Operation operation);
|
Tegra::Engines::Fermi2D::Operation operation);
|
||||||
|
|
||||||
/// @param scissor Optional clip rectangle in framebuffer pixels (DrawTexture honours the
|
|
||||||
/// guest scissor like any other draw).
|
|
||||||
void BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
|
void BlitColor(const Framebuffer* dst_framebuffer, VkImageView src_image_view,
|
||||||
VkImage src_image, VkSampler src_sampler, const Region2D& dst_region,
|
VkImage src_image, VkSampler src_sampler, const Region2D& dst_region,
|
||||||
const Region2D& src_region, const Extent3D& src_size,
|
const Region2D& src_region, const Extent3D& src_size);
|
||||||
const std::optional<VkRect2D>& scissor = std::nullopt);
|
|
||||||
|
|
||||||
void BlitColorMSAA(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
void BlitColorMSAA(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
||||||
const Region2D& dst_region, const Region2D& src_region);
|
const Region2D& dst_region, const Region2D& src_region);
|
||||||
|
|||||||
@@ -82,7 +82,12 @@ VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t in
|
|||||||
|
|
||||||
if (lower_left) {
|
if (lower_left) {
|
||||||
// Flip by surface clip height
|
// Flip by surface clip height
|
||||||
y += conv(static_cast<f32>(regs.surface_clip.height));
|
const float clip_height = conv(static_cast<f32>(regs.surface_clip.height));
|
||||||
|
if (src.scale_y < 0.0f && y >= clip_height) {
|
||||||
|
y = clip_height - y;
|
||||||
|
} else {
|
||||||
|
y += clip_height;
|
||||||
|
}
|
||||||
height = -height;
|
height = -height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,35 +398,8 @@ void RasterizerVulkan::DrawTexture() {
|
|||||||
.y = ScaleSrc(draw_texture_state.src_y1)}};
|
.y = ScaleSrc(draw_texture_state.src_y1)}};
|
||||||
Extent3D src_size = {static_cast<u32>(ScaleSrc(texture.size.width)),
|
Extent3D src_size = {static_cast<u32>(ScaleSrc(texture.size.width)),
|
||||||
static_cast<u32>(ScaleSrc(texture.size.height)), texture.size.depth};
|
static_cast<u32>(ScaleSrc(texture.size.height)), texture.size.depth};
|
||||||
// DrawTexture rectangles go through the fragment pipeline, scissor included.
|
|
||||||
std::optional<VkRect2D> scissor;
|
|
||||||
if (maxwell3d->regs.scissor_test[0].enable) {
|
|
||||||
u32 up_scale = 1;
|
|
||||||
u32 down_shift = 0;
|
|
||||||
if (dst_rescaling) {
|
|
||||||
up_scale = Settings::values.resolution_info.up_scale;
|
|
||||||
down_shift = Settings::values.resolution_info.down_shift;
|
|
||||||
}
|
|
||||||
scissor = GetScissorState(maxwell3d->regs, 0, up_scale, down_shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drawing a texture 1:1 onto itself without blending changes nothing on hardware, but here
|
|
||||||
// it samples the image the render pass is writing to: undefined in Vulkan, and on tiled GPUs
|
|
||||||
// it reads whatever the image memory last held. Crysis Remastered does this every frame for
|
|
||||||
// its post-processing buffers (suspected cause of its map covering the whole screen).
|
|
||||||
const auto& fb_images = framebuffer->Images();
|
|
||||||
const bool src_is_target =
|
|
||||||
std::find(fb_images.begin(), fb_images.begin() + framebuffer->NumImages(),
|
|
||||||
texture.ImageHandle()) != fb_images.begin() + framebuffer->NumImages();
|
|
||||||
if (src_is_target && src_rescaling == dst_rescaling &&
|
|
||||||
src_region.start.x == dst_region.start.x && src_region.start.y == dst_region.start.y &&
|
|
||||||
src_region.end.x == dst_region.end.x && src_region.end.y == dst_region.end.y &&
|
|
||||||
maxwell3d->regs.blend.enable[0] == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
blit_image.BlitColor(framebuffer, texture.RenderTarget(), texture.ImageHandle(),
|
blit_image.BlitColor(framebuffer, texture.RenderTarget(), texture.ImageHandle(),
|
||||||
sampler->Handle(), dst_region, src_region, src_size, scissor);
|
sampler->Handle(), dst_region, src_region, src_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::Clear(u32 layer_count) {
|
void RasterizerVulkan::Clear(u32 layer_count) {
|
||||||
|
|||||||
Reference in New Issue
Block a user