Merge branch 'master' into TemporaryHackishBranch

This commit is contained in:
LunaMoo committed 2017-11-17 14:08:56 +01:00
commit e51bc0b488
43 files changed
+392 -172

No files matched your search

+3 -1
View File
@@ -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
+25 -12
View File
@@ -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.
+3
View File
@@ -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_;
};
+10 -3
View File
@@ -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];
+2 -3
View File
@@ -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();
+10
View File
@@ -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;
+1 -1
View File
@@ -214,7 +214,7 @@ public:
return vfb;
}
}
virtual void RebindFramebuffer() = 0;
virtual void RebindFramebuffer();
std::vector<FramebufferInfo> GetFramebufferList();
void CopyDisplayToOutput();
+2
View File
@@ -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.
-2
View File
@@ -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() {
-9
View File
@@ -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);
-2
View File
@@ -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);
+1 -6
View File
@@ -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();
}
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+12 -10
View File
@@ -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) {
+11 -1
View File
@@ -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_;
+1 -11
View File
@@ -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;
}
}
-1
View File
@@ -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,
+28 -6
View File
@@ -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) {
+4 -1
View File
@@ -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
View File
@@ -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()
+4 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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");
+3
View File
@@ -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;
+11
View File
@@ -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;
}
+4
View File
@@ -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();
+1
View File
@@ -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
+1
View File
@@ -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
+49 -17
View File
@@ -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, &region);
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, &region);
// 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;
+3 -1
View File
@@ -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;
+36 -16
View File
@@ -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) {
+4 -1
View File
@@ -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;
};
+19
View File
@@ -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;
+17 -2
View File
@@ -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) {
+6 -2
View File
@@ -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"))
+2 -2
View File
@@ -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():