mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
Merge branch 'master' into TemporaryHackishBranch
This commit is contained in:
commit
e51bc0b488
43 files changed
+392
-172
No files matched your search
+3
-1
@@ -62,7 +62,6 @@ build*/
|
||||
# Temp file used by jenkins windows build (TODO: remove)
|
||||
desc.txt
|
||||
|
||||
|
||||
Logs
|
||||
Memstick
|
||||
memstick
|
||||
@@ -96,5 +95,8 @@ debian/files
|
||||
debian/ppsspp.substvars
|
||||
debian/ppsspp/
|
||||
|
||||
# Libretro build
|
||||
*.o
|
||||
|
||||
# YouCompleteMe file
|
||||
.ycm_extra_conf.pyc
|
||||
@@ -431,6 +431,10 @@ void VulkanContext::ChooseDevice(int physical_device) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (deviceInfo_.preferredDepthStencilFormat == VK_FORMAT_UNDEFINED) {
|
||||
// WTF? This is bad.
|
||||
ELOG("Could not find a usable depth stencil format.");
|
||||
}
|
||||
|
||||
// This is as good a place as any to do this
|
||||
vkGetPhysicalDeviceMemoryProperties(physical_devices_[physical_device_], &memory_properties);
|
||||
@@ -708,9 +712,8 @@ bool VulkanContext::InitQueue() {
|
||||
|
||||
bool VulkanContext::InitSwapchain() {
|
||||
VkResult U_ASSERT_ONLY res;
|
||||
VkSurfaceCapabilitiesKHR surfCapabilities;
|
||||
|
||||
res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices_[physical_device_], surface_, &surfCapabilities);
|
||||
res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices_[physical_device_], surface_, &surfCapabilities_);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
uint32_t presentModeCount;
|
||||
@@ -723,7 +726,7 @@ bool VulkanContext::InitSwapchain() {
|
||||
|
||||
VkExtent2D swapChainExtent;
|
||||
// width and height are either both -1, or both not -1.
|
||||
if (surfCapabilities.currentExtent.width == (uint32_t)-1) {
|
||||
if (surfCapabilities_.currentExtent.width == (uint32_t)-1) {
|
||||
// If the surface size is undefined, the size is set to
|
||||
// the size of the images requested.
|
||||
ILOG("initSwapchain: %dx%d", width_, height_);
|
||||
@@ -731,7 +734,7 @@ bool VulkanContext::InitSwapchain() {
|
||||
swapChainExtent.height = height_;
|
||||
} else {
|
||||
// If the surface size is defined, the swap chain size must match
|
||||
swapChainExtent = surfCapabilities.currentExtent;
|
||||
swapChainExtent = surfCapabilities_.currentExtent;
|
||||
}
|
||||
|
||||
// TODO: Find a better way to specify the prioritized present mode while being able
|
||||
@@ -767,20 +770,20 @@ bool VulkanContext::InitSwapchain() {
|
||||
// Determine the number of VkImage's to use in the swap chain (we desire to
|
||||
// own only 1 image at a time, besides the images being displayed and
|
||||
// queued for display):
|
||||
uint32_t desiredNumberOfSwapChainImages = surfCapabilities.minImageCount + 1;
|
||||
uint32_t desiredNumberOfSwapChainImages = surfCapabilities_.minImageCount + 1;
|
||||
ILOG("numSwapChainImages: %d", desiredNumberOfSwapChainImages);
|
||||
if ((surfCapabilities.maxImageCount > 0) &&
|
||||
(desiredNumberOfSwapChainImages > surfCapabilities.maxImageCount))
|
||||
if ((surfCapabilities_.maxImageCount > 0) &&
|
||||
(desiredNumberOfSwapChainImages > surfCapabilities_.maxImageCount))
|
||||
{
|
||||
// Application must settle for fewer images than desired:
|
||||
desiredNumberOfSwapChainImages = surfCapabilities.maxImageCount;
|
||||
desiredNumberOfSwapChainImages = surfCapabilities_.maxImageCount;
|
||||
}
|
||||
|
||||
VkSurfaceTransformFlagBitsKHR preTransform;
|
||||
if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
|
||||
if (surfCapabilities_.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
|
||||
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
} else {
|
||||
preTransform = surfCapabilities.currentTransform;
|
||||
preTransform = surfCapabilities_.currentTransform;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR swap_chain_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
|
||||
@@ -795,12 +798,22 @@ bool VulkanContext::InitSwapchain() {
|
||||
swap_chain_info.presentMode = swapchainPresentMode;
|
||||
swap_chain_info.oldSwapchain = VK_NULL_HANDLE;
|
||||
swap_chain_info.clipped = true;
|
||||
swap_chain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
swap_chain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
if (surfCapabilities_.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
|
||||
swap_chain_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
|
||||
#ifndef ANDROID
|
||||
// We don't support screenshots on Android
|
||||
// Add more usage flags if they're supported.
|
||||
if (surfCapabilities_.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
|
||||
swap_chain_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
#endif
|
||||
|
||||
swap_chain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
swap_chain_info.queueFamilyIndexCount = 0;
|
||||
swap_chain_info.pQueueFamilyIndices = NULL;
|
||||
// OPAQUE is not supported everywhere.
|
||||
if (surfCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
|
||||
if (surfCapabilities_.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
|
||||
swap_chain_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
} else {
|
||||
// This should be supported anywhere, and is the only thing supported on the SHIELD TV, for example.
|
||||
|
||||
@@ -198,6 +198,7 @@ public:
|
||||
const VkPhysicalDeviceFeatures &GetFeaturesAvailable() const { return featuresAvailable_; }
|
||||
const VkPhysicalDeviceFeatures &GetFeaturesEnabled() const { return featuresEnabled_; }
|
||||
const VulkanPhysicalDeviceInfo &GetDeviceInfo() const { return deviceInfo_; }
|
||||
const VkSurfaceCapabilitiesKHR &GetSurfaceCapabilities() const { return surfCapabilities_; }
|
||||
|
||||
bool IsDeviceExtensionAvailable(const char *name) const {
|
||||
for (auto &iter : device_extension_properties_) {
|
||||
@@ -302,6 +303,8 @@ private:
|
||||
VkPhysicalDeviceFeatures featuresAvailable_{};
|
||||
VkPhysicalDeviceFeatures featuresEnabled_{};
|
||||
|
||||
VkSurfaceCapabilitiesKHR surfCapabilities_{};
|
||||
|
||||
std::vector<VkCommandBuffer> cmdQueue_;
|
||||
};
|
||||
|
||||
|
||||
@@ -140,9 +140,11 @@ void DrawEngineCommon::Resized() {
|
||||
ClearTrackedVertexArrays();
|
||||
}
|
||||
|
||||
u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType) {
|
||||
u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType, int *vertexSize) {
|
||||
const u32 vertTypeID = (vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24);
|
||||
VertexDecoder *dec = GetVertexDecoder(vertTypeID);
|
||||
if (vertexSize)
|
||||
*vertexSize = dec->VertexSize();
|
||||
return DrawEngineCommon::NormalizeVertices(outPtr, bufPtr, inPtr, dec, lowerBound, upperBound, vertType);
|
||||
}
|
||||
|
||||
@@ -150,7 +152,7 @@ u32 DrawEngineCommon::NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr,
|
||||
//
|
||||
// It does the simplest and safest test possible: If all points of a bbox is outside a single of
|
||||
// our clipping planes, we reject the box. Tighter bounds would be desirable but would take more calculations.
|
||||
bool DrawEngineCommon::TestBoundingBox(void* control_points, int vertexCount, u32 vertType) {
|
||||
bool DrawEngineCommon::TestBoundingBox(void* control_points, int vertexCount, u32 vertType, int *bytesRead) {
|
||||
SimpleVertex *corners = (SimpleVertex *)(decoded + 65536 * 12);
|
||||
float *verts = (float *)(decoded + 65536 * 18);
|
||||
|
||||
@@ -158,25 +160,30 @@ bool DrawEngineCommon::TestBoundingBox(void* control_points, int vertexCount, u3
|
||||
// and a large vertex format.
|
||||
if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_FLOAT) {
|
||||
verts = (float *)control_points;
|
||||
*bytesRead = 3 * sizeof(float) * vertexCount;
|
||||
} else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_8BIT) {
|
||||
const s8 *vtx = (const s8 *)control_points;
|
||||
for (int i = 0; i < vertexCount * 3; i++) {
|
||||
verts[i] = vtx[i] * (1.0f / 128.0f);
|
||||
}
|
||||
*bytesRead = 3 * sizeof(s8) * vertexCount;
|
||||
} else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_16BIT) {
|
||||
const s16 *vtx = (const s16*)control_points;
|
||||
for (int i = 0; i < vertexCount * 3; i++) {
|
||||
verts[i] = vtx[i] * (1.0f / 32768.0f);
|
||||
}
|
||||
*bytesRead = 3 * sizeof(s16) * vertexCount;
|
||||
} else {
|
||||
// Simplify away bones and morph before proceeding
|
||||
u8 *temp_buffer = decoded + 65536 * 24;
|
||||
NormalizeVertices((u8 *)corners, temp_buffer, (u8 *)control_points, 0, vertexCount, vertType);
|
||||
int vertexSize = 0;
|
||||
NormalizeVertices((u8 *)corners, temp_buffer, (u8 *)control_points, 0, vertexCount, vertType, &vertexSize);
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
verts[i * 3] = corners[i].pos.x;
|
||||
verts[i * 3 + 1] = corners[i].pos.y;
|
||||
verts[i * 3 + 2] = corners[i].pos.z;
|
||||
}
|
||||
*bytesRead = vertexSize * vertexCount;
|
||||
}
|
||||
|
||||
Plane planes[6];
|
||||
|
||||
@@ -49,8 +49,6 @@ public:
|
||||
DrawEngineCommon();
|
||||
virtual ~DrawEngineCommon();
|
||||
|
||||
bool TestBoundingBox(void* control_points, int vertexCount, u32 vertType);
|
||||
|
||||
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices);
|
||||
|
||||
static u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, VertexDecoder *dec, int lowerBound, int upperBound, u32 vertType);
|
||||
@@ -61,6 +59,7 @@ public:
|
||||
// Same for SubmitPrim
|
||||
virtual void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) = 0;
|
||||
|
||||
bool TestBoundingBox(void* control_points, int vertexCount, u32 vertType, int *bytesRead);
|
||||
void SubmitSpline(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, int type_u, int type_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead);
|
||||
void SubmitBezier(const void *control_points, const void *indices, int tess_u, int tess_v, int count_u, int count_v, GEPatchPrimType prim_type, bool computeNormals, bool patchFacing, u32 vertType, int *bytesRead);
|
||||
|
||||
@@ -79,7 +78,7 @@ protected:
|
||||
virtual void ClearTrackedVertexArrays() {}
|
||||
|
||||
// Preprocessing for spline/bezier
|
||||
u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType);
|
||||
u32 NormalizeVertices(u8 *outPtr, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, u32 vertType, int *vertexSize = nullptr);
|
||||
|
||||
// Utility for vertex caching
|
||||
u32 ComputeMiniHash();
|
||||
|
||||
@@ -2106,6 +2106,16 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::RebindFramebuffer() {
|
||||
if (currentRenderVfb_ && currentRenderVfb_->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP });
|
||||
} else {
|
||||
// Should this even happen?
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP });
|
||||
}
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
}
|
||||
|
||||
std::vector<FramebufferInfo> FramebufferManagerCommon::GetFramebufferList() {
|
||||
std::vector<FramebufferInfo> list;
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ public:
|
||||
return vfb;
|
||||
}
|
||||
}
|
||||
virtual void RebindFramebuffer() = 0;
|
||||
virtual void RebindFramebuffer();
|
||||
std::vector<FramebufferInfo> GetFramebufferList();
|
||||
|
||||
void CopyDisplayToOutput();
|
||||
|
||||
@@ -855,6 +855,7 @@ void DrawEngineCommon::SubmitSpline(const void *control_points, const void *indi
|
||||
GetIndexBounds(indices, count_u * count_v, vertType, &index_lower_bound, &index_upper_bound);
|
||||
|
||||
VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24));
|
||||
// TODO: If indexing is on, this may be wrong!
|
||||
*bytesRead = count_u * count_v * origVDecoder->VertexSize();
|
||||
|
||||
// Real hardware seems to draw nothing when given < 4 either U or V.
|
||||
@@ -971,6 +972,7 @@ void DrawEngineCommon::SubmitBezier(const void *control_points, const void *indi
|
||||
GetIndexBounds(indices, count_u*count_v, vertType, &index_lower_bound, &index_upper_bound);
|
||||
|
||||
VertexDecoder *origVDecoder = GetVertexDecoder((vertType & 0xFFFFFF) | (gstate.getUVGenMode() << 24));
|
||||
// TODO: If indexing is on, this may be wrong!
|
||||
*bytesRead = count_u * count_v * origVDecoder->VertexSize();
|
||||
|
||||
// Real hardware seems to draw nothing when given < 4 either U or V.
|
||||
|
||||
@@ -459,8 +459,6 @@ void FramebufferManagerD3D11::BindPostShader(const PostShaderUniforms &uniforms)
|
||||
context_->Unmap(postConstants_, 0);
|
||||
context_->VSSetConstantBuffers(0, 1, &postConstants_); // Probably not necessary
|
||||
context_->PSSetConstantBuffers(0, 1, &postConstants_);
|
||||
|
||||
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
|
||||
}
|
||||
|
||||
void FramebufferManagerD3D11::RebindFramebuffer() {
|
||||
|
||||
@@ -304,15 +304,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerDX9::RebindFramebuffer() {
|
||||
if (currentRenderVfb_ && currentRenderVfb_->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP });
|
||||
} else {
|
||||
// Should this even happen?
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP });
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerDX9::Bind2DShader() {
|
||||
device_->SetVertexDeclaration(pFramebufferVertexDecl);
|
||||
device_->SetPixelShader(pFramebufferPixelShader);
|
||||
|
||||
@@ -66,8 +66,6 @@ public:
|
||||
bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override;
|
||||
bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
|
||||
|
||||
virtual void RebindFramebuffer() override;
|
||||
|
||||
LPDIRECT3DSURFACE9 GetOffscreenSurface(LPDIRECT3DSURFACE9 similarSurface, VirtualFramebuffer *vfb);
|
||||
LPDIRECT3DSURFACE9 GetOffscreenSurface(D3DFORMAT fmt, u32 w, u32 h);
|
||||
|
||||
|
||||
@@ -438,12 +438,7 @@ void FramebufferManagerGLES::DrawActiveTexture(float x, float y, float w, float
|
||||
}
|
||||
|
||||
void FramebufferManagerGLES::RebindFramebuffer() {
|
||||
if (currentRenderVfb_ && currentRenderVfb_->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP });
|
||||
} else {
|
||||
// Should this even happen?
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP });
|
||||
}
|
||||
FramebufferManagerCommon::RebindFramebuffer();
|
||||
if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE)
|
||||
glstate.viewport.restore();
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ public:
|
||||
bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
|
||||
|
||||
bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
|
||||
|
||||
virtual void RebindFramebuffer() override;
|
||||
|
||||
protected:
|
||||
|
||||
+11
-7
@@ -1511,13 +1511,17 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) {
|
||||
|
||||
void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) {
|
||||
// Just resetting, nothing to check bounds for.
|
||||
const u32 data = op & 0x00FFFFFF;
|
||||
if (data == 0) {
|
||||
const u32 count = op & 0xFFFFFF;
|
||||
if (count == 0) {
|
||||
currentList->bboxResult = false;
|
||||
return;
|
||||
}
|
||||
if (((data & 7) == 0) && data <= 64) { // Sanity check
|
||||
if (((count & 7) == 0) && count <= 64) { // Sanity check
|
||||
void *control_points = Memory::GetPointer(gstate_c.vertexAddr);
|
||||
if (!control_points) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gstate.vertType & GE_VTYPE_IDX_MASK) {
|
||||
ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Indexed bounding box data not supported.");
|
||||
// Data seems invalid. Let's assume the box test passed.
|
||||
@@ -1526,11 +1530,11 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) {
|
||||
}
|
||||
|
||||
// Test if the bounding box is within the drawing region.
|
||||
if (control_points) {
|
||||
currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, data, gstate.vertType);
|
||||
}
|
||||
int bytesRead;
|
||||
currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, count, gstate.vertType, &bytesRead);
|
||||
AdvanceVerts(gstate.vertType, count, bytesRead);
|
||||
} else {
|
||||
ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Bad bounding box data: %06x", data);
|
||||
ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Bad bounding box data: %06x", count);
|
||||
// Data seems invalid. Let's assume the box test passed.
|
||||
currentList->bboxResult = true;
|
||||
}
|
||||
|
||||
+12
-2
@@ -15,7 +15,7 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
|
||||
#include "GPU/Common/DrawEngineCommon.h"
|
||||
#include "GPU/Null/NullGpu.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/ge_constants.h"
|
||||
@@ -25,7 +25,17 @@
|
||||
#include "Core/HLE/sceKernelInterrupt.h"
|
||||
#include "Core/HLE/sceGe.h"
|
||||
|
||||
NullGPU::NullGPU() : GPUCommon(nullptr, nullptr) { }
|
||||
class NullDrawEngine : public DrawEngineCommon {
|
||||
public:
|
||||
void DispatchFlush() override {
|
||||
}
|
||||
void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) override {
|
||||
}
|
||||
};
|
||||
|
||||
NullGPU::NullGPU() : GPUCommon(nullptr, nullptr) {
|
||||
drawEngineCommon_ = new NullDrawEngine();
|
||||
}
|
||||
NullGPU::~NullGPU() { }
|
||||
|
||||
void NullGPU::FastRunLoop(DisplayList &list) {
|
||||
|
||||
@@ -516,23 +516,23 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
|
||||
descAlloc.descriptorSetCount = 1;
|
||||
VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc);
|
||||
// Even in release mode, this is bad.
|
||||
_assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptors in pool. sz=%d", (int)frame->descSets.size());
|
||||
_assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptor space in pool. sz=%d", (int)frame->descSets.size());
|
||||
|
||||
// We just don't write to the slots we don't care about.
|
||||
// We need 8 now that we support secondary texture bindings.
|
||||
VkWriteDescriptorSet writes[8]{};
|
||||
// Main texture
|
||||
int n = 0;
|
||||
VkDescriptorImageInfo tex{};
|
||||
VkDescriptorImageInfo tex[2]{};
|
||||
if (imageView) {
|
||||
// TODO: Also support LAYOUT_GENERAL to be able to texture from framebuffers without transitioning them?
|
||||
tex.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
tex.imageView = imageView;
|
||||
tex.sampler = sampler;
|
||||
tex[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
tex[0].imageView = imageView;
|
||||
tex[0].sampler = sampler;
|
||||
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
writes[n].pNext = nullptr;
|
||||
writes[n].dstBinding = DRAW_BINDING_TEXTURE;
|
||||
writes[n].pImageInfo = &tex;
|
||||
writes[n].pImageInfo = &tex[0];
|
||||
writes[n].descriptorCount = 1;
|
||||
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
writes[n].dstSet = desc;
|
||||
@@ -541,13 +541,13 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
|
||||
|
||||
if (boundSecondary_) {
|
||||
// TODO: Also support LAYOUT_GENERAL to be able to texture from framebuffers without transitioning them?
|
||||
tex.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
tex.imageView = boundSecondary_;
|
||||
tex.sampler = samplerSecondary_;
|
||||
tex[1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
tex[1].imageView = boundSecondary_;
|
||||
tex[1].sampler = samplerSecondary_;
|
||||
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
writes[n].pNext = nullptr;
|
||||
writes[n].dstBinding = DRAW_BINDING_2ND_TEXTURE;
|
||||
writes[n].pImageInfo = &tex;
|
||||
writes[n].pImageInfo = &tex[1];
|
||||
writes[n].descriptorCount = 1;
|
||||
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
writes[n].dstSet = desc;
|
||||
@@ -877,6 +877,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
// Already logged, let's bail out.
|
||||
return;
|
||||
}
|
||||
BindShaderBlendTex(); // This might cause copies so important to do before BindPipeline.
|
||||
renderManager->BindPipeline(pipeline->pipeline);
|
||||
if (pipeline != lastPipeline_) {
|
||||
if (lastPipeline_ && !lastPipeline_->useBlendConstant && pipeline->useBlendConstant) {
|
||||
@@ -976,6 +977,7 @@ void DrawEngineVulkan::DoFlush() {
|
||||
// Already logged, let's bail out.
|
||||
return;
|
||||
}
|
||||
BindShaderBlendTex(); // This might cause copies so super important to do before BindPipeline.
|
||||
renderManager->BindPipeline(pipeline->pipeline);
|
||||
if (pipeline != lastPipeline_) {
|
||||
if (lastPipeline_ && !lastPipeline_->useBlendConstant && pipeline->useBlendConstant) {
|
||||
|
||||
@@ -147,6 +147,15 @@ public:
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
void FinishDeferred() {
|
||||
if (!numDrawCalls)
|
||||
return;
|
||||
// Decode any pending vertices. And also flush while we're at it, for simplicity.
|
||||
// It might be possible to only decode like in the other backends, but meh, it can't matter.
|
||||
// Issue #10095 has a nice example of where this is required.
|
||||
DoFlush();
|
||||
}
|
||||
|
||||
void DispatchFlush() override { Flush(); }
|
||||
void DispatchSubmitPrim(void *verts, void *inds, GEPrimitiveType prim, int vertexCount, u32 vertType, int *bytesRead) override {
|
||||
SubmitPrim(verts, inds, prim, vertexCount, vertType, bytesRead);
|
||||
@@ -179,6 +188,7 @@ private:
|
||||
struct FrameData;
|
||||
void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant);
|
||||
void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState);
|
||||
void BindShaderBlendTex();
|
||||
void ResetShaderBlending();
|
||||
|
||||
void InitDeviceObjects();
|
||||
@@ -203,7 +213,7 @@ private:
|
||||
|
||||
// Secondary texture for shader blending
|
||||
VkImageView boundSecondary_ = VK_NULL_HANDLE;
|
||||
VkSampler samplerSecondary_ = VK_NULL_HANDLE;
|
||||
VkSampler samplerSecondary_ = VK_NULL_HANDLE; // This one is actually never used since we use fetch.
|
||||
|
||||
PrehashMap<VertexArrayInfoVulkan *, nullptr> vai_;
|
||||
VulkanPushBuffer *vertexCache_;
|
||||
|
||||
@@ -367,16 +367,6 @@ void FramebufferManagerVulkan::BindPostShader(const PostShaderUniforms &uniforms
|
||||
gstate_c.Dirty(DIRTY_VERTEXSHADER_STATE);
|
||||
}
|
||||
|
||||
void FramebufferManagerVulkan::RebindFramebuffer() {
|
||||
if (currentRenderVfb_ && currentRenderVfb_->fbo) {
|
||||
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP });
|
||||
} else {
|
||||
// Should this even happen?
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP });
|
||||
}
|
||||
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
|
||||
}
|
||||
|
||||
int FramebufferManagerVulkan::GetLineWidth() {
|
||||
if (g_Config.iInternalResolution == 0) {
|
||||
return std::max(1, (int)(renderWidth_ / 480));
|
||||
@@ -699,4 +689,4 @@ void FramebufferManagerVulkan::CompilePostShader() {
|
||||
|
||||
|
||||
usePostShader_ = true;
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,6 @@ public:
|
||||
|
||||
bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
|
||||
|
||||
virtual void RebindFramebuffer() override;
|
||||
VkImageView BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
|
||||
|
||||
// If within a render pass, this will just issue a regular clear. If beginning a new render pass,
|
||||
|
||||
@@ -181,8 +181,13 @@ void GPU_Vulkan::CheckGPUFeatures() {
|
||||
}
|
||||
if (vulkan_->GetFeaturesEnabled().dualSrcBlend) {
|
||||
switch (vulkan_->GetPhysicalDeviceProperties().vendorID) {
|
||||
case VULKAN_VENDOR_NVIDIA:
|
||||
// Workaround for Shield TV driver bug.
|
||||
if (strcmp(vulkan_->GetPhysicalDeviceProperties().deviceName, "NVIDIA Tegra X1") != 0)
|
||||
features |= GPU_SUPPORTS_DUALSOURCE_BLEND;
|
||||
break;
|
||||
case VULKAN_VENDOR_INTEL:
|
||||
// Work around for Intel driver bug.
|
||||
// Workaround for Intel driver bug.
|
||||
break;
|
||||
case VULKAN_VENDOR_AMD:
|
||||
// See issue #10074, and also #10065 (AMD) and #10109 for the choice of the driver version to check for
|
||||
@@ -205,6 +210,17 @@ void GPU_Vulkan::CheckGPUFeatures() {
|
||||
features |= GPU_USE_CLEAR_RAM_HACK;
|
||||
}
|
||||
|
||||
if (!g_Config.bHighQualityDepth && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) {
|
||||
features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT;
|
||||
}
|
||||
else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) {
|
||||
// Use fragment rounding on desktop and GLES3, most accurate.
|
||||
features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;
|
||||
}
|
||||
else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) {
|
||||
features |= GPU_ROUND_DEPTH_TO_16BIT;
|
||||
}
|
||||
|
||||
// Mandatory features on Vulkan, which may be checked in "centralized" code
|
||||
features |= GPU_SUPPORTS_ACCURATE_DEPTH;
|
||||
features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
|
||||
@@ -214,6 +230,9 @@ void GPU_Vulkan::CheckGPUFeatures() {
|
||||
features |= GPU_SUPPORTS_OES_TEXTURE_NPOT;
|
||||
features |= GPU_SUPPORTS_LARGE_VIEWPORTS;
|
||||
features |= GPU_SUPPORTS_16BIT_FORMATS;
|
||||
features |= GPU_SUPPORTS_INSTANCE_RENDERING;
|
||||
features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH;
|
||||
features |= GPU_SUPPORTS_TEXTURE_FLOAT;
|
||||
gstate_c.featureFlags = features;
|
||||
}
|
||||
|
||||
@@ -454,6 +473,7 @@ void GPU_Vulkan::FastRunLoop(DisplayList &list) {
|
||||
}
|
||||
|
||||
void GPU_Vulkan::FinishDeferred() {
|
||||
drawEngine_.FinishDeferred();
|
||||
}
|
||||
|
||||
inline void GPU_Vulkan::CheckFlushOp(int cmd, u32 diff) {
|
||||
@@ -525,12 +545,14 @@ void GPU_Vulkan::Execute_Prim(u32 op, u32 diff) {
|
||||
|
||||
void *verts = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
|
||||
void *inds = 0;
|
||||
u32 vertexType = gstate.vertType;
|
||||
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
|
||||
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
|
||||
ERROR_LOG_REPORT(G3D, "Bad index address %08x!", gstate_c.indexAddr);
|
||||
u32 indexAddr = gstate_c.indexAddr;
|
||||
if (!Memory::IsValidAddress(indexAddr)) {
|
||||
ERROR_LOG_REPORT(G3D, "Bad index address %08x!", indexAddr);
|
||||
return;
|
||||
}
|
||||
inds = Memory::GetPointerUnchecked(gstate_c.indexAddr);
|
||||
inds = Memory::GetPointerUnchecked(indexAddr);
|
||||
}
|
||||
|
||||
#ifndef MOBILE_DEVICE
|
||||
@@ -547,12 +569,12 @@ void GPU_Vulkan::Execute_Prim(u32 op, u32 diff) {
|
||||
|
||||
int bytesRead = 0;
|
||||
UpdateUVScaleOffset();
|
||||
drawEngine_.SubmitPrim(verts, inds, prim, count, gstate.vertType, &bytesRead);
|
||||
drawEngine_.SubmitPrim(verts, inds, prim, count, vertexType, &bytesRead);
|
||||
|
||||
// After drawing, we advance the vertexAddr (when non indexed) or indexAddr (when indexed).
|
||||
// Some games rely on this, they don't bother reloading VADDR and IADDR.
|
||||
// The VADDR/IADDR registers are NOT updated.
|
||||
AdvanceVerts(gstate.vertType, count, bytesRead);
|
||||
AdvanceVerts(vertexType, count, bytesRead);
|
||||
}
|
||||
|
||||
void GPU_Vulkan::Execute_LoadClut(u32 op, u32 diff) {
|
||||
|
||||
@@ -362,7 +362,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant) {
|
||||
void DrawEngineVulkan::BindShaderBlendTex() {
|
||||
// At this point, we know if the vertices are full alpha or not.
|
||||
// TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)?
|
||||
if (!gstate.isModeClear()) {
|
||||
@@ -377,6 +377,9 @@ void DrawEngineVulkan::ApplyDrawStateLate(VulkanRenderManager *renderManager, bo
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DrawEngineVulkan::ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant) {
|
||||
if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {
|
||||
renderManager->SetScissor(dynState_.scissor);
|
||||
renderManager->SetViewport(dynState_.viewport);
|
||||
|
||||
+2
-2
@@ -391,12 +391,12 @@ void MainWindow::fullscrAct()
|
||||
|
||||
void MainWindow::websiteAct()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl("http://www.ppsspp.org/"));
|
||||
QDesktopServices::openUrl(QUrl("https://www.ppsspp.org/"));
|
||||
}
|
||||
|
||||
void MainWindow::forumAct()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl("http://forums.ppsspp.org/"));
|
||||
QDesktopServices::openUrl(QUrl("https://forums.ppsspp.org/"));
|
||||
}
|
||||
|
||||
void MainWindow::gitAct()
|
||||
|
||||
@@ -694,8 +694,8 @@ void GameSettingsScreen::CreateViews() {
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
|
||||
static const char *screenRotation[] = {"Auto", "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed"};
|
||||
PopupMultiChoice *rot = systemSettings->Add(new PopupMultiChoice(&g_Config.iScreenRotation, co->T("Screen Rotation"), screenRotation, 0, ARRAY_SIZE(screenRotation), co->GetName(), screenManager()));
|
||||
static const char *screenRotation[] = {"Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed"};
|
||||
PopupMultiChoice *rot = systemSettings->Add(new PopupMultiChoice(&g_Config.iScreenRotation, co->T("Screen Rotation"), screenRotation, 1, ARRAY_SIZE(screenRotation), co->GetName(), screenManager()));
|
||||
rot->OnChoice.Handle(this, &GameSettingsScreen::OnScreenRotation);
|
||||
|
||||
if (System_GetPropertyBool(SYSPROP_SUPPORTS_SUSTAINED_PERF_MODE)) {
|
||||
@@ -866,7 +866,7 @@ static void RecreateActivity() {
|
||||
}
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnAdhocGuides(UI::EventParams &e) {
|
||||
LaunchBrowser("http://forums.ppsspp.org/forumdisplay.php?fid=34");
|
||||
LaunchBrowser("https://forums.ppsspp.org/forumdisplay.php?fid=34");
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
@@ -1136,6 +1136,7 @@ UI::EventReturn GameSettingsScreen::OnChangeNickname(UI::EventParams &e) {
|
||||
g_Config.sNickName = StripSpaces(name);
|
||||
}
|
||||
#elif defined(__ANDROID__)
|
||||
// TODO: The return value is handled in NativeApp::inputbox_completed. This is horrific.
|
||||
System_SendMessage("inputbox", ("nickname:" + g_Config.sNickName).c_str());
|
||||
#endif
|
||||
return UI::EVENT_DONE;
|
||||
|
||||
+4
-4
@@ -921,7 +921,7 @@ UI::EventReturn MainScreen::OnDownloadUpgrade(UI::EventParams &e) {
|
||||
}
|
||||
#else
|
||||
// Go directly to ppsspp.org and let the user sort it out
|
||||
LaunchBrowser("http://www.ppsspp.org/downloads.html");
|
||||
LaunchBrowser("https://www.ppsspp.org/downloads.html");
|
||||
#endif
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
@@ -1132,18 +1132,18 @@ UI::EventReturn MainScreen::OnSupport(UI::EventParams &e) {
|
||||
#ifdef __ANDROID__
|
||||
LaunchBrowser("market://details?id=org.ppsspp.ppssppgold");
|
||||
#else
|
||||
LaunchBrowser("http://central.ppsspp.org/buygold");
|
||||
LaunchBrowser("https://central.ppsspp.org/buygold");
|
||||
#endif
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MainScreen::OnPPSSPPOrg(UI::EventParams &e) {
|
||||
LaunchBrowser("http://www.ppsspp.org");
|
||||
LaunchBrowser("https://www.ppsspp.org");
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn MainScreen::OnForums(UI::EventParams &e) {
|
||||
LaunchBrowser("http://forums.ppsspp.org");
|
||||
LaunchBrowser("https://forums.ppsspp.org");
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -530,9 +530,9 @@ void CreditsScreen::CreateViews() {
|
||||
Button *back = root_->Add(new Button(di->T("Back"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, 10, false)));
|
||||
back->OnClick.Handle(this, &CreditsScreen::OnOK);
|
||||
root_->SetDefaultFocusView(back);
|
||||
#ifndef GOLD
|
||||
root_->Add(new Button(cr->T("Buy Gold"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 10, false)))->OnClick.Handle(this, &CreditsScreen::OnSupport);
|
||||
#endif
|
||||
if (!System_GetPropertyBool(SYSPROP_APP_GOLD)) {
|
||||
root_->Add(new Button(cr->T("Buy Gold"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 10, false)))->OnClick.Handle(this, &CreditsScreen::OnSupport);
|
||||
}
|
||||
root_->Add(new Button(cr->T("PPSSPP Forums"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 84, false)))->OnClick.Handle(this, &CreditsScreen::OnForums);
|
||||
root_->Add(new Button("www.ppsspp.org", new AnchorLayoutParams(260, 64, 10, NONE, NONE, 158, false)))->OnClick.Handle(this, &CreditsScreen::OnPPSSPPOrg);
|
||||
#ifdef __ANDROID__
|
||||
@@ -550,7 +550,7 @@ UI::EventReturn CreditsScreen::OnSupport(UI::EventParams &e) {
|
||||
#ifdef __ANDROID__
|
||||
LaunchBrowser("market://details?id=org.ppsspp.ppssppgold");
|
||||
#else
|
||||
LaunchBrowser("http://central.ppsspp.org/buygold");
|
||||
LaunchBrowser("https://central.ppsspp.org/buygold");
|
||||
#endif
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
@@ -565,12 +565,12 @@ UI::EventReturn CreditsScreen::OnTwitter(UI::EventParams &e) {
|
||||
}
|
||||
|
||||
UI::EventReturn CreditsScreen::OnPPSSPPOrg(UI::EventParams &e) {
|
||||
LaunchBrowser("http://www.ppsspp.org");
|
||||
LaunchBrowser("https://www.ppsspp.org");
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn CreditsScreen::OnForums(UI::EventParams &e) {
|
||||
LaunchBrowser("http://forums.ppsspp.org");
|
||||
LaunchBrowser("https://forums.ppsspp.org");
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
@@ -689,7 +689,7 @@ void CreditsScreen::render() {
|
||||
"",
|
||||
"",
|
||||
cr->T("check", "Also check out Dolphin, the best Wii/GC emu around:"),
|
||||
"http://www.dolphin-emu.org",
|
||||
"https://www.dolphin-emu.org",
|
||||
"",
|
||||
"",
|
||||
cr->T("info1", "PPSSPP is only intended to play games you own."),
|
||||
|
||||
+7
-8
@@ -302,12 +302,6 @@ bool CheckFontIsUsable(const wchar_t *fontFace) {
|
||||
#endif
|
||||
|
||||
void NativeInit(int argc, const char *argv[], const char *savegame_dir, const char *external_dir, const char *cache_dir, bool fs) {
|
||||
#ifdef ANDROID_NDK_PROFILER
|
||||
setenv("CPUPROFILE_FREQUENCY", "500", 1);
|
||||
setenv("CPUPROFILE", "/sdcard/gmon.out", 1);
|
||||
monstartup("ppsspp_jni.so");
|
||||
#endif
|
||||
|
||||
net::Init(); // This needs to happen before we load the config. So on Windows we also run it in Main. It's fine to call multiple times.
|
||||
|
||||
InitFastMath(cpu_info.bNEON);
|
||||
@@ -442,6 +436,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
}
|
||||
} else {
|
||||
if (boot_filename.empty()) {
|
||||
ILOG("Boot filename found in args: %s", argv[i]);
|
||||
boot_filename = argv[i];
|
||||
#ifdef _WIN32
|
||||
boot_filename = ReplaceAll(boot_filename, "\\", "/");
|
||||
@@ -460,7 +455,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
}
|
||||
}
|
||||
|
||||
if (fileToLog != NULL)
|
||||
if (fileToLog)
|
||||
LogManager::GetInstance()->ChangeFileLog(fileToLog);
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -874,8 +869,12 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) {
|
||||
std::string setString = inputboxValue.size() > 1 ? inputboxValue[1] : "";
|
||||
if (inputboxValue[0] == "IP")
|
||||
g_Config.proAdhocServer = setString;
|
||||
if (inputboxValue[0] == "nickname")
|
||||
else if (inputboxValue[0] == "nickname")
|
||||
g_Config.sNickName = setString;
|
||||
else if (inputboxValue[0] == "remoteiso_subdir")
|
||||
g_Config.sRemoteISOSubdir = setString;
|
||||
else if (inputboxValue[0] == "remoteiso_server")
|
||||
g_Config.sLastRemoteISOServer = setString;
|
||||
inputboxValue.clear();
|
||||
}
|
||||
if (msg == "bgImage_updated") {
|
||||
|
||||
+23
-1
@@ -675,13 +675,25 @@ void RemoteISOSettingsScreen::CreateViews() {
|
||||
|
||||
remoteisoSettings->Add(new ItemHeader(ri->T("Remote disc streaming")));
|
||||
remoteisoSettings->Add(new CheckBox(&g_Config.bRemoteISOManual, ri->T("Manual Mode Client", "Manual Mode Client")));
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
PopupTextInputChoice *remoteServer = remoteisoSettings->Add(new PopupTextInputChoice(&g_Config.sLastRemoteISOServer, ri->T("Remote Server"), "", 255, screenManager()));
|
||||
#else
|
||||
ChoiceWithValueDisplay *remoteServer = new ChoiceWithValueDisplay(&g_Config.sLastRemoteISOServer, ri->T("Remote Server"), nullptr);
|
||||
remoteisoSettings->Add(remoteServer);
|
||||
remoteServer->OnClick.Handle(this, &RemoteISOSettingsScreen::OnClickRemoteServer);
|
||||
#endif
|
||||
remoteServer->SetEnabledPtr(&g_Config.bRemoteISOManual);
|
||||
PopupSliderChoice *remotePort = remoteisoSettings->Add(new PopupSliderChoice(&g_Config.iLastRemoteISOPort, 0, 65535, ri->T("Remote Port", "Remote Port"), 100, screenManager()));
|
||||
remotePort->SetEnabledPtr(&g_Config.bRemoteISOManual);
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
PopupTextInputChoice *remoteSubdir = remoteisoSettings->Add(new PopupTextInputChoice(&g_Config.sRemoteISOSubdir, ri->T("Remote Subdirectory"), "", 255, screenManager()));
|
||||
remoteSubdir->SetEnabledPtr(&g_Config.bRemoteISOManual);
|
||||
remoteSubdir->OnChange.Handle(this, &RemoteISOSettingsScreen::OnChangeRemoteISOSubdir);
|
||||
#else
|
||||
ChoiceWithValueDisplay *remoteSubdir = remoteisoSettings->Add(
|
||||
new ChoiceWithValueDisplay(&g_Config.sRemoteISOSubdir, ri->T("Remote Subdirectory"), nullptr));
|
||||
remoteSubdir->OnClick.Handle(this, &RemoteISOSettingsScreen::OnClickRemoteISOSubdir);
|
||||
#endif
|
||||
remoteSubdir->SetEnabledPtr(&g_Config.bRemoteISOManual);
|
||||
|
||||
PopupSliderChoice *portChoice = new PopupSliderChoice(&g_Config.iRemoteISOPort, 0, 65535, ri->T("Local Server Port", "Local Server Port"), 100, screenManager());
|
||||
remoteisoSettings->Add(portChoice);
|
||||
@@ -693,6 +705,16 @@ void RemoteISOSettingsScreen::CreateViews() {
|
||||
AddStandardBack(root_);
|
||||
}
|
||||
|
||||
UI::EventReturn RemoteISOSettingsScreen::OnClickRemoteServer(UI::EventParams &e) {
|
||||
System_SendMessage("inputbox", ("remoteiso_server:" + g_Config.sLastRemoteISOServer).c_str());
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn RemoteISOSettingsScreen::OnClickRemoteISOSubdir(UI::EventParams &e) {
|
||||
System_SendMessage("inputbox", ("remoteiso_subdir:" + g_Config.sRemoteISOSubdir).c_str());
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn RemoteISOSettingsScreen::OnChangeRemoteISOSubdir(UI::EventParams &e) {
|
||||
//Conform to HTTP standards
|
||||
ReplaceAll(g_Config.sRemoteISOSubdir, " ", "%20");
|
||||
|
||||
@@ -89,7 +89,10 @@ class RemoteISOSettingsScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
RemoteISOSettingsScreen();
|
||||
|
||||
UI::EventReturn OnClickRemoteISOSubdir(UI::EventParams &e);
|
||||
UI::EventReturn OnClickRemoteServer(UI::EventParams &e);
|
||||
protected:
|
||||
|
||||
void update() override;
|
||||
void CreateViews() override;
|
||||
|
||||
|
||||
@@ -173,6 +173,12 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
|
||||
|
||||
Version gitVer(PPSSPP_GIT_VERSION);
|
||||
g_Vulkan = new VulkanContext();
|
||||
if (g_Vulkan->InitError().size()) {
|
||||
*error_message = g_Vulkan->InitError();
|
||||
delete g_Vulkan;
|
||||
g_Vulkan = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// int vulkanFlags = VULKAN_FLAG_PRESENT_FIFO_RELAXED;
|
||||
int vulkanFlags = VULKAN_FLAG_PRESENT_MAILBOX;
|
||||
@@ -181,6 +187,8 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
|
||||
}
|
||||
if (VK_SUCCESS != g_Vulkan->CreateInstance("PPSSPP", gitVer.ToInteger(), vulkanFlags)) {
|
||||
*error_message = g_Vulkan->InitError();
|
||||
delete g_Vulkan;
|
||||
g_Vulkan = nullptr;
|
||||
return false;
|
||||
}
|
||||
g_Vulkan->ChooseDevice(g_Vulkan->GetBestPhysicalDevice());
|
||||
@@ -189,6 +197,8 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
|
||||
}
|
||||
if (g_Vulkan->CreateDevice() != VK_SUCCESS) {
|
||||
*error_message = g_Vulkan->InitError();
|
||||
delete g_Vulkan;
|
||||
g_Vulkan = nullptr;
|
||||
return false;
|
||||
}
|
||||
if (g_validate_) {
|
||||
@@ -197,6 +207,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
|
||||
}
|
||||
g_Vulkan->InitSurfaceWin32(hInst, hWnd);
|
||||
if (!g_Vulkan->InitObjects()) {
|
||||
*error_message = g_Vulkan->InitError();
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -291,6 +291,7 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX,
|
||||
}
|
||||
if (VK_SUCCESS != g_Vulkan->CreateInstance("PPSSPP", gitVer.ToInteger(), VULKAN_FLAG_PRESENT_MAILBOX | VULKAN_FLAG_PRESENT_FIFO_RELAXED)) {
|
||||
ELOG("Failed to create vulkan context: %s", g_Vulkan->InitError().c_str());
|
||||
System_SendMessage("toast", "No Vulkan compatible device found. Using OpenGL instead.");
|
||||
delete g_Vulkan;
|
||||
g_Vulkan = nullptr;
|
||||
return false;
|
||||
@@ -964,13 +965,16 @@ extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_sendMessage(JNIEnv *env
|
||||
if (msg == "moga") {
|
||||
mogaVersion = prm;
|
||||
} else if (msg == "permission_pending") {
|
||||
ILOG("STORAGE PERMISSION: PENDING");
|
||||
// TODO: Add support for other permissions
|
||||
permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_PENDING;
|
||||
NativePermissionStatus(SYSTEM_PERMISSION_STORAGE, PERMISSION_STATUS_PENDING);
|
||||
} else if (msg == "permission_denied") {
|
||||
ILOG("STORAGE PERMISSION: DENIED");
|
||||
permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_DENIED;
|
||||
NativePermissionStatus(SYSTEM_PERMISSION_STORAGE, PERMISSION_STATUS_PENDING);
|
||||
} else if (msg == "permission_granted") {
|
||||
ILOG("STORAGE PERMISSION: GRANTED");
|
||||
permissions[SYSTEM_PERMISSION_STORAGE] = PERMISSION_STATUS_GRANTED;
|
||||
NativePermissionStatus(SYSTEM_PERMISSION_STORAGE, PERMISSION_STATUS_PENDING);
|
||||
} else if (msg == "sustained_perf_supported") {
|
||||
|
||||
@@ -310,7 +310,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
|
||||
// OK, config should be initialized, we can query for screen rotation.
|
||||
if (Build.VERSION.SDK_INT >= 9) {
|
||||
updateScreenRotation();
|
||||
updateScreenRotation("Initialize");
|
||||
}
|
||||
|
||||
// Detect OpenGL support.
|
||||
@@ -355,7 +355,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
}
|
||||
|
||||
@TargetApi(9)
|
||||
private void updateScreenRotation() {
|
||||
private void updateScreenRotation(String cause) {
|
||||
// Query the native application on the desired rotation.
|
||||
int rot = 0;
|
||||
String rotString = NativeApp.queryConfig("screenRotation");
|
||||
@@ -365,11 +365,12 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
Log.e(TAG, "Invalid rotation: " + rotString);
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Setting requested rotation: " + rot + " ('" + rotString + "')");
|
||||
Log.i(TAG, "Setting requested rotation: " + rot + " ('" + rotString + "') (" + cause + ")");
|
||||
|
||||
switch (rot) {
|
||||
case 0:
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
// Auto is no longer supported.
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
break;
|
||||
case 1:
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
@@ -462,7 +463,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
refreshRate = display.getRefreshRate();
|
||||
|
||||
// OK, config should be initialized, we can query for screen rotation.
|
||||
updateScreenRotation();
|
||||
updateScreenRotation("onCreate");
|
||||
updateSustainedPerformanceMode();
|
||||
|
||||
// Keep the screen bright - very annoying if it goes dark when tilting away
|
||||
@@ -519,12 +520,26 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
}
|
||||
|
||||
private Point desiredSize = new Point();
|
||||
|
||||
private int badOrientationCount = 0;
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
pixelWidth = holder.getSurfaceFrame().width();
|
||||
pixelHeight = holder.getSurfaceFrame().height();
|
||||
Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight + " holder: " + holder.toString());
|
||||
|
||||
// Workaround for terrible bug when locking and unlocking the screen in landscape mode on Nexus 5X.
|
||||
int requestedOr = getRequestedOrientation();
|
||||
boolean requestedPortrait = requestedOr == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOr == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
|
||||
boolean detectedPortrait = pixelHeight > pixelWidth;
|
||||
if (badOrientationCount < 3 && requestedPortrait != detectedPortrait) {
|
||||
Log.e(TAG, "Bad orientation detected (w=" + pixelWidth + " h=" + pixelHeight + "! Recreating activity.");
|
||||
badOrientationCount++;
|
||||
recreate();;
|
||||
return;
|
||||
} else if (requestedPortrait == detectedPortrait) {
|
||||
badOrientationCount = 0;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight + " holder: " + holder.toString() + " or: " + requestedOr);
|
||||
NativeApp.setDisplayParameters(pixelWidth, pixelHeight, (int)densityDpi, refreshRate);
|
||||
getDesiredBackbufferSize(desiredSize);
|
||||
|
||||
@@ -687,7 +702,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
}
|
||||
// OK, config should be initialized, we can query for screen rotation.
|
||||
if (javaGL || Build.VERSION.SDK_INT >= 9) {
|
||||
updateScreenRotation();
|
||||
updateScreenRotation("onResume");
|
||||
}
|
||||
|
||||
Log.i(TAG, "onResume");
|
||||
@@ -840,10 +855,10 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
return input.getDescriptor();
|
||||
} else {
|
||||
List<InputDevice.MotionRange> motions = input.getMotionRanges();
|
||||
String fakeid = "";
|
||||
StringBuilder fakeid = new StringBuilder();
|
||||
for (InputDevice.MotionRange range : motions)
|
||||
fakeid += range.getAxis();
|
||||
return fakeid;
|
||||
fakeid.append(range.getAxis());
|
||||
return fakeid.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -999,7 +1014,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
input.selectAll();
|
||||
|
||||
// Lovely!
|
||||
AlertDialog.Builder bld = null;
|
||||
AlertDialog.Builder bld;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
|
||||
bld = new AlertDialog.Builder(this);
|
||||
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
@@ -1181,13 +1196,13 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
|
||||
finish();
|
||||
} else if (command.equals("rotate")) {
|
||||
if (javaGL) {
|
||||
updateScreenRotation();
|
||||
updateScreenRotation("rotate");
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
Log.i(TAG, "Must recreate activity on rotation");
|
||||
}
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= 9) {
|
||||
updateScreenRotation();
|
||||
updateScreenRotation("rotate");
|
||||
}
|
||||
}
|
||||
} else if (command.equals("sustainedPerfMode")) {
|
||||
|
||||
@@ -75,23 +75,27 @@ public class PpssppActivity extends NativeActivity {
|
||||
// using Intent extra string. Intent extra will be null if launch normal
|
||||
// (from app drawer or file explorer).
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
if (Intent.ACTION_VIEW.equals(action)) {
|
||||
Uri data = intent.getData();
|
||||
if (data != null) {
|
||||
String path = intent.getData().getPath();
|
||||
super.setShortcutParam(path);
|
||||
Toast.makeText(getApplicationContext(), path, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Log.e(TAG, "Got ACTION_VIEW without a valid uri");
|
||||
}
|
||||
// String action = intent.getAction();
|
||||
Uri data = intent.getData();
|
||||
if (data != null) {
|
||||
String path = intent.getData().getPath();
|
||||
Log.i(TAG, "Found Shortcut Parameter in data: " + path);
|
||||
super.setShortcutParam(path);
|
||||
// Toast.makeText(getApplicationContext(), path, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
super.setShortcutParam(getIntent().getStringExtra(SHORTCUT_EXTRA_KEY));
|
||||
String param = getIntent().getStringExtra(SHORTCUT_EXTRA_KEY);
|
||||
Log.e(TAG, "Got ACTION_VIEW without a valid uri, trying param");
|
||||
if (param != null) {
|
||||
Log.i(TAG, "Found Shortcut Parameter in extra-data: " + param);
|
||||
super.setShortcutParam(getIntent().getStringExtra(SHORTCUT_EXTRA_KEY));
|
||||
} else {
|
||||
Log.e(TAG, "Shortcut missing parameter!");
|
||||
}
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
|
||||
// called by the C++ code through JNI. Dispatch anything we can't directly handle
|
||||
// on the gfx thread to the UI thread.
|
||||
public void postCommand(String command, String parameter) {
|
||||
|
||||
@@ -6,15 +6,18 @@ import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.Intent.ShortcutIconResource;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* This class will respond to android.intent.action.CREATE_SHORTCUT intent from
|
||||
* launcher homescreen. Register this class in AndroidManifest.xml.
|
||||
*/
|
||||
public class ShortcutActivity extends Activity {
|
||||
private static final String TAG = "PPSSPP";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -33,8 +36,12 @@ public class ShortcutActivity extends Activity {
|
||||
private void respondToShortcutRequest(String path) {
|
||||
// This is Intent that will be sent when user execute our shortcut on
|
||||
// homescreen. Set our app as target Context. Set Main activity as
|
||||
// target class. Add any parameter to extra.
|
||||
// target class. Add any parameter as data.
|
||||
Intent shortcutIntent = new Intent(this, PpssppActivity.class);
|
||||
Uri uri = Uri.fromFile(new File(path));
|
||||
Log.i(TAG, "Shortcut URI: " + uri.toString());
|
||||
shortcutIntent.setData(uri);
|
||||
|
||||
shortcutIntent.putExtra(PpssppActivity.SHORTCUT_EXTRA_KEY, path);
|
||||
|
||||
PpssppActivity.CheckABIAndLoadLibrary();
|
||||
|
||||
@@ -148,6 +148,7 @@ UCES00373 = true
|
||||
# Crash Tag Team Racing needs it to pass checking memory stick screen.
|
||||
ULUS10044 = true
|
||||
ULES00168 = true
|
||||
ULES00172 = true
|
||||
ULJM05036 = true
|
||||
# Gundam Battle Royale might need it to avoid crashes when certain Ace enemies shows up
|
||||
ULJS00083 = true
|
||||
|
||||
@@ -73,6 +73,7 @@ inline bool DataFormatIsColor(DataFormat fmt) {
|
||||
}
|
||||
|
||||
void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format);
|
||||
void ConvertFromBGRA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format);
|
||||
void ConvertToD32F(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format);
|
||||
|
||||
} // namespace
|
||||
@@ -837,22 +837,6 @@ void VulkanQueueRunner::SetupTransitionToTransferDst(VKRImage &img, VkImageMemor
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
VKRImage *srcImage;
|
||||
if (step.readback.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
srcImage = &step.readback.src->color;
|
||||
} else if (step.readback.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
srcImage = &step.readback.src->depth;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
VkPipelineStageFlags stage = 0;
|
||||
if (srcImage->layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
|
||||
SetupTransitionToTransferSrc(*srcImage, barrier, stage, step.readback.aspectMask);
|
||||
vkCmdPipelineBarrier(cmd, stage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
|
||||
ResizeReadbackBuffer(sizeof(uint32_t) * step.readback.srcRect.extent.width * step.readback.srcRect.extent.height);
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
@@ -863,9 +847,55 @@ void VulkanQueueRunner::PerformReadback(const VKRStep &step, VkCommandBuffer cmd
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = step.readback.srcRect.extent.width;
|
||||
region.bufferImageHeight = step.readback.srcRect.extent.height;
|
||||
vkCmdCopyImageToBuffer(cmd, srcImage->image, srcImage->layout, readbackBuffer_, 1, ®ion);
|
||||
|
||||
VkImage image;
|
||||
VkImageLayout copyLayout;
|
||||
// Special case for backbuffer readbacks.
|
||||
if (step.readback.src == nullptr) {
|
||||
// We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT,
|
||||
// and then back into it.
|
||||
TransitionImageLayout2(cmd, backbufferImage_, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
copyLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
image = backbufferImage_;
|
||||
} else {
|
||||
VKRImage *srcImage;
|
||||
if (step.readback.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
srcImage = &step.readback.src->color;
|
||||
}
|
||||
else if (step.readback.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
srcImage = &step.readback.src->depth;
|
||||
}
|
||||
else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
VkPipelineStageFlags stage = 0;
|
||||
if (srcImage->layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
|
||||
SetupTransitionToTransferSrc(*srcImage, barrier, stage, step.readback.aspectMask);
|
||||
vkCmdPipelineBarrier(cmd, stage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
image = srcImage->image;
|
||||
copyLayout = srcImage->layout;
|
||||
}
|
||||
|
||||
vkCmdCopyImageToBuffer(cmd, image, copyLayout, readbackBuffer_, 1, ®ion);
|
||||
|
||||
// NOTE: Can't read the buffer using the CPU here - need to sync first.
|
||||
|
||||
// If we copied from the backbuffer, transition it back.
|
||||
if (step.readback.src == nullptr) {
|
||||
// We only take screenshots after the main render pass (anything else would be stupid) so we need to transition out of PRESENT,
|
||||
// and then back into it.
|
||||
TransitionImageLayout2(cmd, backbufferImage_, VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
VK_ACCESS_TRANSFER_READ_BIT, 0);
|
||||
copyLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffer cmd) {
|
||||
@@ -911,6 +941,8 @@ void VulkanQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataForm
|
||||
assert(res == VK_SUCCESS);
|
||||
if (srcFormat == Draw::DataFormat::R8G8B8A8_UNORM) {
|
||||
ConvertFromRGBA8888(pixels, (const uint8_t *)mappedData, pixelStride, width, width, height, destFormat);
|
||||
} else if (srcFormat == Draw::DataFormat::B8G8R8A8_UNORM) {
|
||||
ConvertFromBGRA8888(pixels, (const uint8_t *)mappedData, pixelStride, width, width, height, destFormat);
|
||||
} else if (srcFormat == destFormat) {
|
||||
uint8_t *dst = pixels;
|
||||
const uint8_t *src = (const uint8_t *)mappedData;
|
||||
|
||||
@@ -145,8 +145,9 @@ struct VKRStep {
|
||||
class VulkanQueueRunner {
|
||||
public:
|
||||
VulkanQueueRunner(VulkanContext *vulkan) : vulkan_(vulkan) {}
|
||||
void SetBackbuffer(VkFramebuffer fb) {
|
||||
void SetBackbuffer(VkFramebuffer fb, VkImage img) {
|
||||
backbuffer_ = fb;
|
||||
backbufferImage_ = img;
|
||||
}
|
||||
void RunSteps(VkCommandBuffer cmd, const std::vector<VKRStep *> &steps);
|
||||
void LogSteps(const std::vector<VKRStep *> &steps);
|
||||
@@ -192,6 +193,7 @@ private:
|
||||
VulkanContext *vulkan_;
|
||||
|
||||
VkFramebuffer backbuffer_;
|
||||
VkImage backbufferImage_;
|
||||
VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE;
|
||||
|
||||
VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE;
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
#define VLOG(...)
|
||||
#endif
|
||||
|
||||
// This works great. Not much reason to disable so let's not even bother with an option.
|
||||
const bool useThread = true;
|
||||
|
||||
#ifndef UINT64_MAX
|
||||
#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
|
||||
#endif
|
||||
@@ -127,6 +124,11 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan
|
||||
}
|
||||
|
||||
queueRunner_.CreateDeviceObjects();
|
||||
|
||||
// Temporary AMD hack for issue #10097
|
||||
if (vulkan_->GetPhysicalDeviceProperties().vendorID == VULKAN_VENDOR_AMD) {
|
||||
useThread_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderManager::CreateBackbuffers() {
|
||||
@@ -188,7 +190,7 @@ void VulkanRenderManager::CreateBackbuffers() {
|
||||
}
|
||||
|
||||
// Start the thread.
|
||||
if (useThread && HasBackbuffers()) {
|
||||
if (useThread_ && HasBackbuffers()) {
|
||||
run_ = true;
|
||||
// Won't necessarily be 0.
|
||||
threadInitFrame_ = vulkan_->GetCurFrame();
|
||||
@@ -198,7 +200,7 @@ void VulkanRenderManager::CreateBackbuffers() {
|
||||
}
|
||||
|
||||
void VulkanRenderManager::StopThread() {
|
||||
if (useThread && run_) {
|
||||
if (useThread_ && run_) {
|
||||
run_ = false;
|
||||
// Stop the thread.
|
||||
for (int i = 0; i < vulkan_->GetInflightFrames(); i++) {
|
||||
@@ -337,7 +339,7 @@ void VulkanRenderManager::BeginFrame() {
|
||||
FrameData &frameData = frameData_[curFrame];
|
||||
|
||||
// Make sure the very last command buffer from the frame before the previous has been fully executed.
|
||||
if (useThread) {
|
||||
if (useThread_) {
|
||||
std::unique_lock<std::mutex> lock(frameData.push_mutex);
|
||||
while (!frameData.readyForFence) {
|
||||
VLOG("PUSH: Waiting for frame[%d].readyForFence = 1", curFrame);
|
||||
@@ -413,7 +415,7 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
|
||||
curHeight_ = fb ? fb->height : vulkan_->GetBackbufferHeight();
|
||||
}
|
||||
|
||||
void VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride) {
|
||||
bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride) {
|
||||
VKRStep *step = new VKRStep{ VKRStepType::READBACK };
|
||||
step->readback.aspectMask = aspectBits;
|
||||
step->readback.src = src;
|
||||
@@ -427,9 +429,26 @@ void VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int a
|
||||
|
||||
Draw::DataFormat srcFormat;
|
||||
if (aspectBits & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
switch (src->color.format) {
|
||||
case VK_FORMAT_R8G8B8A8_UNORM: srcFormat = Draw::DataFormat::R8G8B8A8_UNORM; break;
|
||||
default: assert(false);
|
||||
if (src) {
|
||||
switch (src->color.format) {
|
||||
case VK_FORMAT_R8G8B8A8_UNORM: srcFormat = Draw::DataFormat::R8G8B8A8_UNORM; break;
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Backbuffer.
|
||||
if (!(vulkan_->GetSurfaceCapabilities().supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
|
||||
ELOG("Copying from backbuffer not supported, can't take screenshots");
|
||||
return false;
|
||||
}
|
||||
switch (vulkan_->GetSwapchainFormat()) {
|
||||
case VK_FORMAT_B8G8R8A8_UNORM: srcFormat = Draw::DataFormat::B8G8R8A8_UNORM; break;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM: srcFormat = Draw::DataFormat::R8G8B8A8_UNORM; break;
|
||||
// NOTE: If you add supported formats here, make sure to also support them in VulkanQueueRunner::CopyReadbackBuffer.
|
||||
default:
|
||||
ELOG("Unsupported backbuffer format for screenshots");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (aspectBits & VK_IMAGE_ASPECT_STENCIL_BIT) {
|
||||
// Copies from stencil are always S8.
|
||||
@@ -446,6 +465,7 @@ void VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, int a
|
||||
}
|
||||
// Need to call this after FlushSync so the pixels are guaranteed to be ready in CPU-accessible VRAM.
|
||||
queueRunner_.CopyReadbackBuffer(w, h, srcFormat, destFormat, pixelStride, pixels);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanRenderManager::CopyImageToMemorySync(VkImage image, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride) {
|
||||
@@ -675,7 +695,7 @@ void VulkanRenderManager::Finish() {
|
||||
curRenderStep_ = nullptr;
|
||||
int curFrame = vulkan_->GetCurFrame();
|
||||
FrameData &frameData = frameData_[curFrame];
|
||||
if (!useThread) {
|
||||
if (!useThread_) {
|
||||
frameData.steps = std::move(steps_);
|
||||
frameData.type = VKRRunType::END;
|
||||
Run(curFrame);
|
||||
@@ -724,7 +744,7 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) {
|
||||
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
queueRunner_.SetBackbuffer(framebuffers_[frameData.curSwapchainImage]);
|
||||
queueRunner_.SetBackbuffer(framebuffers_[frameData.curSwapchainImage], swapchainImages_[frameData.curSwapchainImage].image);
|
||||
|
||||
frameData.hasBegun = true;
|
||||
}
|
||||
@@ -782,7 +802,7 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) {
|
||||
}
|
||||
|
||||
// When !triggerFence, we notify after syncing with Vulkan.
|
||||
if (useThread && triggerFence) {
|
||||
if (useThread_ && triggerFence) {
|
||||
VLOG("PULL: Frame %d.readyForFence = true", frame);
|
||||
std::unique_lock<std::mutex> lock(frameData.push_mutex);
|
||||
frameData.readyForFence = true;
|
||||
@@ -862,7 +882,7 @@ void VulkanRenderManager::EndSyncFrame(int frame) {
|
||||
VkResult res = vkBeginCommandBuffer(frameData.mainCmd, &begin);
|
||||
assert(res == VK_SUCCESS);
|
||||
|
||||
if (useThread) {
|
||||
if (useThread_) {
|
||||
std::unique_lock<std::mutex> lock(frameData.push_mutex);
|
||||
frameData.readyForFence = true;
|
||||
frameData.push_condVar.notify_all();
|
||||
@@ -873,7 +893,7 @@ void VulkanRenderManager::FlushSync() {
|
||||
// TODO: Reset curRenderStep_?
|
||||
int curFrame = vulkan_->GetCurFrame();
|
||||
FrameData &frameData = frameData_[curFrame];
|
||||
if (!useThread) {
|
||||
if (!useThread_) {
|
||||
frameData.steps = std::move(steps_);
|
||||
frameData.type = VKRRunType::SYNC;
|
||||
Run(curFrame);
|
||||
@@ -887,7 +907,7 @@ void VulkanRenderManager::FlushSync() {
|
||||
frameData.pull_condVar.notify_all();
|
||||
}
|
||||
|
||||
if (useThread) {
|
||||
if (useThread_) {
|
||||
std::unique_lock<std::mutex> lock(frameData.push_mutex);
|
||||
// Wait for the flush to be hit, since we're syncing.
|
||||
while (!frameData.readyForFence) {
|
||||
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
|
||||
void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil);
|
||||
VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment);
|
||||
void CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride);
|
||||
bool CopyFramebufferToMemorySync(VKRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride);
|
||||
void CopyImageToMemorySync(VkImage image, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride);
|
||||
|
||||
void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, int aspectMask);
|
||||
@@ -283,4 +283,7 @@ private:
|
||||
VkImageView view = VK_NULL_HANDLE;
|
||||
};
|
||||
DepthBufferInfo depth_;
|
||||
|
||||
// This works great - except see issue #10097. WTF?
|
||||
bool useThread_ = true;
|
||||
};
|
||||
@@ -381,6 +381,25 @@ void ConvertFromRGBA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, u
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: SSE/NEON
|
||||
// Could also make C fake-simd for 64-bit, two 8888 pixels fit in a register :)
|
||||
void ConvertFromBGRA8888(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) {
|
||||
// Must skip stride in the cases below. Some games pack data into the cracks, like MotoGP.
|
||||
const uint32_t *src32 = (const uint32_t *)src;
|
||||
|
||||
if (format == Draw::DataFormat::R8G8B8A8_UNORM) {
|
||||
uint32_t *dst32 = (uint32_t *)dst;
|
||||
for (uint32_t y = 0; y < height; ++y) {
|
||||
ConvertBGRA8888ToRGBA8888(dst32, src32, width);
|
||||
src32 += srcStride;
|
||||
dst32 += dstStride;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Don't even bother with these, this path only happens in screenshots and we don't save those to 16-bit.
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
void ConvertToD32F(uint8_t *dst, const uint8_t *src, uint32_t dstStride, uint32_t srcStride, uint32_t width, uint32_t height, DataFormat format) {
|
||||
if (format == Draw::DataFormat::D32F) {
|
||||
const float *src32 = (const float *)src;
|
||||
|
||||
@@ -1187,6 +1187,20 @@ void AddFeature(std::vector<std::string> &features, const char *name, VkBool32 a
|
||||
features.push_back(buf);
|
||||
}
|
||||
|
||||
// Limited to depth buffer formats as that's what we need right now.
|
||||
static const char *VulkanFormatToString(VkFormat fmt) {
|
||||
switch (fmt) {
|
||||
case VkFormat::VK_FORMAT_D24_UNORM_S8_UINT: return "D24S8";
|
||||
case VkFormat::VK_FORMAT_D16_UNORM: return "D16";
|
||||
case VkFormat::VK_FORMAT_D16_UNORM_S8_UINT: return "D16S8";
|
||||
case VkFormat::VK_FORMAT_D32_SFLOAT: return "D32f";
|
||||
case VkFormat::VK_FORMAT_D32_SFLOAT_S8_UINT: return "D32fS8";
|
||||
case VkFormat::VK_FORMAT_S8_UINT: return "S8";
|
||||
case VkFormat::VK_FORMAT_UNDEFINED: return "UNDEFINED (BAD!)";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> VKContext::GetFeatureList() const {
|
||||
const VkPhysicalDeviceFeatures &available = vulkan_->GetFeaturesAvailable();
|
||||
const VkPhysicalDeviceFeatures &enabled = vulkan_->GetFeaturesEnabled();
|
||||
@@ -1210,6 +1224,8 @@ std::vector<std::string> VKContext::GetFeatureList() const {
|
||||
AddFeature(features, "occlusionQueryPrecise", available.occlusionQueryPrecise, enabled.occlusionQueryPrecise);
|
||||
AddFeature(features, "multiDrawIndirect", available.multiDrawIndirect, enabled.multiDrawIndirect);
|
||||
|
||||
features.push_back(std::string("Preferred depth buffer format: ") + VulkanFormatToString(vulkan_->GetDeviceInfo().preferredDepthStencilFormat));
|
||||
|
||||
// Also list texture formats and their properties.
|
||||
for (int i = VK_FORMAT_BEGIN_RANGE; i <= VK_FORMAT_END_RANGE; i++) {
|
||||
// TODO
|
||||
@@ -1321,8 +1337,7 @@ bool VKContext::CopyFramebufferToMemorySync(Framebuffer *srcfb, int channelBits,
|
||||
if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
renderManager_.CopyFramebufferToMemorySync(src->GetFB(), aspectMask, x, y, w, h, format, (uint8_t *)pixels, pixelStride);
|
||||
return true;
|
||||
return renderManager_.CopyFramebufferToMemorySync(src ? src->GetFB() : nullptr, aspectMask, x, y, w, h, format, (uint8_t *)pixels, pixelStride);
|
||||
}
|
||||
|
||||
void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) {
|
||||
|
||||
@@ -161,6 +161,8 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, bool
|
||||
Core_UpdateDebugStats(g_Config.bShowDebugStats || g_Config.bLogFrameDrops);
|
||||
|
||||
PSP_BeginHostFrame();
|
||||
if (coreParameter.thin3d)
|
||||
coreParameter.thin3d->BeginFrame();
|
||||
|
||||
coreState = CORE_RUNNING;
|
||||
while (coreState == CORE_RUNNING)
|
||||
@@ -184,9 +186,11 @@ bool RunAutoTest(HeadlessHost *headlessHost, CoreParameter &coreParameter, bool
|
||||
Core_Stop();
|
||||
}
|
||||
}
|
||||
|
||||
PSP_EndHostFrame();
|
||||
|
||||
if (coreParameter.thin3d)
|
||||
coreParameter.thin3d->EndFrame();
|
||||
|
||||
PSP_Shutdown();
|
||||
|
||||
headlessHost->FlushDebugOutput();
|
||||
@@ -268,7 +272,7 @@ int main(int argc, const char* argv[])
|
||||
else if (!strcasecmp(gpuName, "null"))
|
||||
gpuCore = GPUCORE_NULL;
|
||||
else
|
||||
return printUsage(argv[0], "Unknown gpu backend specified after --graphics=");
|
||||
return printUsage(argv[0], "Unknown gpu backend specified after --graphics=. Allowed: software, directx9, directx11, vulkan, gles, null.");
|
||||
}
|
||||
// Default to GLES if no value selected.
|
||||
else if (!strcmp(argv[i], "--graphics"))
|
||||
|
||||
@@ -40,7 +40,7 @@ class Command(object):
|
||||
def run(self, timeout):
|
||||
def target():
|
||||
self.process = subprocess.Popen(self.cmd, bufsize=1, stdin=subprocess.PIPE, stdout=sys.stdout, stderr=subprocess.STDOUT)
|
||||
self.process.stdin.write(self.data)
|
||||
self.process.stdin.write(self.data.encode('utf-8'))
|
||||
self.process.stdin.close()
|
||||
self.process.communicate()
|
||||
|
||||
@@ -397,7 +397,7 @@ def run_tests(test_list, args):
|
||||
c = Command(cmdline, '\n'.join(test_filenames))
|
||||
c.run(TIMEOUT * len(test_filenames))
|
||||
|
||||
print("Ran " + PPSSPP_EXE)
|
||||
print("Ran " + ' '.join(cmdline))
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
Reference in new issue
Block a user