diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index b8e484321..2fb7c33a0 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -244,6 +244,7 @@
+
@@ -316,6 +317,7 @@
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index 351cfd760..1dcbacabe 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -70,6 +70,9 @@
Vulkan
+
+ Vulkan
+
@@ -127,6 +130,9 @@
Vulkan
+
+ Vulkan
+
diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h
index e6eda6376..8671f2c24 100644
--- a/Common/Vulkan/VulkanContext.h
+++ b/Common/Vulkan/VulkanContext.h
@@ -1,28 +1,3 @@
-/*
- * Vulkan Samples Kit
- *
- * Copyright (C) 2015 Valve Corporation
- * Copyright (C) 2015 Google, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
#ifndef UTIL_INIT
#define UTIL_INIT
@@ -52,7 +27,7 @@
#include "Common/Vulkan/VulkanLoader.h"
- /* Amount of time, in nanoseconds, to wait for a command buffer to complete */
+// Amount of time, in nanoseconds, to wait for a command buffer to complete
#define FENCE_TIMEOUT 10000000000
#if defined(NDEBUG) && defined(__GNUC__)
@@ -88,6 +63,15 @@ public:
void QueueDeletePipelineCache(VkPipelineCache pipelineCache) { pipelineCaches_.push_back(pipelineCache); }
void Take(VulkanDeleteList &del) {
+ assert(descPools_.size() == 0);
+ assert(modules_.size() == 0);
+ assert(buffers_.size() == 0);
+ assert(bufferViews_.size() == 0);
+ assert(images_.size() == 0);
+ assert(imageViews_.size() == 0);
+ assert(deviceMemory_.size() == 0);
+ assert(samplers_.size() == 0);
+ assert(pipelineCaches_.size() == 0);
descPools_ = std::move(del.descPools_);
modules_ = std::move(del.modules_);
buffers_ = std::move(del.buffers_);
@@ -340,106 +324,6 @@ private:
std::vector cmdQueue_;
};
-// Use these to push vertex, index and uniform data. Generally you'll have two of these
-// and alternate on each frame.
-// TODO: Make it possible to suballocate pushbuffers from a large DeviceMemory block.
-// We'll have two of these that we alternate between on each frame.
-// TODO: Make this auto-grow and shrink. Need to be careful about returning and using the new
-// buffer handle on overflow.
-class VulkanPushBuffer {
-public:
- VulkanPushBuffer(VulkanContext *vulkan, size_t size) : offset_(0), size_(size), writePtr_(nullptr), deviceMemory_(0) {
- VkDevice device = vulkan->GetDevice();
-
- VkBufferCreateInfo b = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
- b.size = size;
- b.flags = 0;
- b.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
- b.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- b.queueFamilyIndexCount = 0;
- b.pQueueFamilyIndices = nullptr;
- VkResult res = vkCreateBuffer(device, &b, nullptr, &buffer_);
- assert(VK_SUCCESS == res);
-
- // Okay, that's the buffer. Now let's allocate some memory for it.
- VkMemoryAllocateInfo alloc = {};
- alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- alloc.pNext = nullptr;
- vulkan->MemoryTypeFromProperties(0xFFFFFFFF, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &alloc.memoryTypeIndex);
- alloc.allocationSize = size;
-
- res = vkAllocateMemory(device, &alloc, nullptr, &deviceMemory_);
- assert(VK_SUCCESS == res);
- res = vkBindBufferMemory(device, buffer_, deviceMemory_, 0);
- assert(VK_SUCCESS == res);
- }
-
- void Destroy(VulkanContext *vulkan) {
- vulkan->Delete().QueueDeleteBuffer(buffer_);
- vulkan->Delete().QueueDeleteDeviceMemory(deviceMemory_);
- }
-
- void Reset() { offset_ = 0; }
-
- void Begin(VkDevice device) {
- offset_ = 0;
- VkResult res = vkMapMemory(device, deviceMemory_, 0, size_, 0, (void **)(&writePtr_));
- assert(VK_SUCCESS == res);
- }
-
- void End(VkDevice device) {
- vkUnmapMemory(device, deviceMemory_);
- writePtr_ = nullptr;
- }
-
- size_t Allocate(size_t numBytes) {
- size_t out = offset_;
- offset_ += (numBytes + 3) & ~3; // Round up to 4 bytes.
- if (offset_ >= size_) {
- // TODO: Allocate a second buffer, then combine them on the next frame.
-#ifdef _WIN32
- DebugBreak();
-#endif
- }
- return out;
- }
-
- // TODO: Add alignment support?
- // Returns the offset that should be used when binding this buffer to get this data.
- size_t Push(const void *data, size_t size) {
- size_t off = Allocate(size);
- memcpy(writePtr_ + off, data, size);
- return off;
- }
-
- uint32_t PushAligned(const void *data, size_t size, int align) {
- offset_ = (offset_ + align - 1) & ~(align - 1);
- size_t off = Allocate(size);
- memcpy(writePtr_ + off, data, size);
- return (uint32_t)off;
- }
-
- size_t GetOffset() const {
- return offset_;
- }
-
- // "Zero-copy" variant - you can write the data directly as you compute it.
- void *Push(size_t size, size_t *bindOffset) {
- size_t off = Allocate(size);
- *bindOffset = off;
- return writePtr_ + off;
- }
-
- VkBuffer GetVkBuffer() const { return buffer_; }
-
-private:
- VkDeviceMemory deviceMemory_;
- VkBuffer buffer_;
- size_t offset_;
- size_t size_;
- uint8_t *writePtr_;
-};
-
// Stand-alone utility functions
void VulkanBeginCommandBuffer(VkCommandBuffer cmd);
void TransitionImageLayout(
diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp
new file mode 100644
index 000000000..2ffcc15ed
--- /dev/null
+++ b/Common/Vulkan/VulkanMemory.cpp
@@ -0,0 +1,47 @@
+// Copyright (c) 2016- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+// Additionally, Common/Vulkan/* , including this file, are also licensed
+// under the public domain.
+
+#include "Common/Vulkan/VulkanMemory.h"
+
+VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, size_t size) : offset_(0), size_(size), writePtr_(nullptr), deviceMemory_(0) {
+ VkDevice device = vulkan->GetDevice();
+
+ VkBufferCreateInfo b = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
+ b.size = size;
+ b.flags = 0;
+ b.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ b.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ b.queueFamilyIndexCount = 0;
+ b.pQueueFamilyIndices = nullptr;
+ VkResult res = vkCreateBuffer(device, &b, nullptr, &buffer_);
+ assert(VK_SUCCESS == res);
+
+ // Okay, that's the buffer. Now let's allocate some memory for it.
+ VkMemoryAllocateInfo alloc = {};
+ alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ alloc.pNext = nullptr;
+ vulkan->MemoryTypeFromProperties(0xFFFFFFFF, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &alloc.memoryTypeIndex);
+ alloc.allocationSize = size;
+
+ res = vkAllocateMemory(device, &alloc, nullptr, &deviceMemory_);
+ assert(VK_SUCCESS == res);
+ res = vkBindBufferMemory(device, buffer_, deviceMemory_, 0);
+ assert(VK_SUCCESS == res);
+}
diff --git a/Common/Vulkan/VulkanMemory.h b/Common/Vulkan/VulkanMemory.h
new file mode 100644
index 000000000..eb0ab011c
--- /dev/null
+++ b/Common/Vulkan/VulkanMemory.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#include "Common/Vulkan/VulkanContext.h"
+
+// VulkanMemory
+//
+// Vulkan memory management utils.
+
+// VulkanPushBuffer
+// Simple incrementing allocator.
+// Use these to push vertex, index and uniform data. Generally you'll have two of these
+// and alternate on each frame. Make sure not to reset until the fence from the last time you used it
+// has completed.
+//
+// TODO: Make it possible to suballocate pushbuffers from a large DeviceMemory block.
+// TODO: Make this auto-grow and shrink. Need to be careful about returning and using the new
+// buffer handle on overflow.
+class VulkanPushBuffer {
+public:
+ VulkanPushBuffer(VulkanContext *vulkan, size_t size);
+
+ ~VulkanPushBuffer() {
+ assert(buffer_ == VK_NULL_HANDLE);
+ assert(deviceMemory_ == VK_NULL_HANDLE);
+ }
+
+ void Destroy(VulkanContext *vulkan) {
+ vulkan->Delete().QueueDeleteBuffer(buffer_);
+ vulkan->Delete().QueueDeleteDeviceMemory(deviceMemory_);
+ buffer_ = VK_NULL_HANDLE;
+ deviceMemory_ = VK_NULL_HANDLE;
+ }
+
+ void Reset() { offset_ = 0; }
+
+ void Begin(VkDevice device) {
+ offset_ = 0;
+ VkResult res = vkMapMemory(device, deviceMemory_, 0, size_, 0, (void **)(&writePtr_));
+ assert(VK_SUCCESS == res);
+ }
+
+ void End(VkDevice device) {
+ vkUnmapMemory(device, deviceMemory_);
+ writePtr_ = nullptr;
+ }
+
+ size_t Allocate(size_t numBytes) {
+ size_t out = offset_;
+ offset_ += (numBytes + 3) & ~3; // Round up to 4 bytes.
+ if (offset_ >= size_) {
+ // TODO: Allocate a second buffer, then combine them on the next frame.
+#ifdef _WIN32
+ DebugBreak();
+#endif
+ }
+ return out;
+ }
+
+ // TODO: Add alignment support?
+ // Returns the offset that should be used when binding this buffer to get this data.
+ size_t Push(const void *data, size_t size) {
+ size_t off = Allocate(size);
+ memcpy(writePtr_ + off, data, size);
+ return off;
+ }
+
+ uint32_t PushAligned(const void *data, size_t size, int align) {
+ offset_ = (offset_ + align - 1) & ~(align - 1);
+ size_t off = Allocate(size);
+ memcpy(writePtr_ + off, data, size);
+ return (uint32_t)off;
+ }
+
+ size_t GetOffset() const {
+ return offset_;
+ }
+
+ // "Zero-copy" variant - you can write the data directly as you compute it.
+ void *Push(size_t size, size_t *bindOffset) {
+ size_t off = Allocate(size);
+ *bindOffset = off;
+ return writePtr_ + off;
+ }
+
+ VkBuffer GetVkBuffer() const { return buffer_; }
+
+private:
+ VkDeviceMemory deviceMemory_;
+ VkBuffer buffer_;
+ size_t offset_;
+ size_t size_;
+ uint8_t *writePtr_;
+};
diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp
index f756364f2..673fdb4f5 100644
--- a/GPU/Vulkan/DrawEngineVulkan.cpp
+++ b/GPU/Vulkan/DrawEngineVulkan.cpp
@@ -33,6 +33,9 @@
#include "GPU/GPUState.h"
#include "GPU/ge_constants.h"
+#include "Common/Vulkan/VulkanContext.h"
+#include "Common/Vulkan/VulkanMemory.h"
+
#include "GPU/Common/TextureDecoder.h"
#include "GPU/Common/SplineCommon.h"
#include "GPU/Common/TransformCommon.h"
diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp
index 6bdd619be..13972b6c9 100644
--- a/GPU/Vulkan/ShaderManagerVulkan.cpp
+++ b/GPU/Vulkan/ShaderManagerVulkan.cpp
@@ -27,6 +27,7 @@
#include "math/dataconv.h"
#include "util/text/utf8.h"
#include "Common/Vulkan/VulkanContext.h"
+#include "Common/Vulkan/VulkanMemory.h"
#include "Common/Common.h"
#include "Core/Config.h"
#include "Core/Reporting.h"
diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp
index dc34d05ab..4d5eb0003 100644
--- a/GPU/Vulkan/TextureCacheVulkan.cpp
+++ b/GPU/Vulkan/TextureCacheVulkan.cpp
@@ -31,6 +31,7 @@
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanImage.h"
+#include "Common/Vulkan/VulkanMemory.h"
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h
index 0d256ba3a..8a4998aa3 100644
--- a/GPU/Vulkan/TextureCacheVulkan.h
+++ b/GPU/Vulkan/TextureCacheVulkan.h
@@ -34,6 +34,7 @@ class DrawEngineVulkan;
class VulkanContext;
class VulkanTexture;
+class VulkanPushBuffer;
struct SamplerCacheKey {
SamplerCacheKey() : fullKey(0) {}
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 45d2f9e0f..3e8e1ddc4 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -128,6 +128,7 @@ VULKAN_FILES := \
$(SRC)/Common/Vulkan/VulkanLoader.cpp \
$(SRC)/Common/Vulkan/VulkanContext.cpp \
$(SRC)/Common/Vulkan/VulkanImage.cpp \
+ $(SRC)/Common/Vulkan/VulkanMemory.cpp \
$(SRC)/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp \
$(SRC)/GPU/Vulkan/DrawEngineVulkan.cpp \
$(SRC)/GPU/Vulkan/FramebufferVulkan.cpp \
diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp
index 6a9585c53..9d1397a78 100644
--- a/ext/native/thin3d/thin3d_vulkan.cpp
+++ b/ext/native/thin3d/thin3d_vulkan.cpp
@@ -33,6 +33,7 @@
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanImage.h"
+#include "Common/Vulkan/VulkanMemory.h"
// We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point.
// binding 0 - uniform data