mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
VK: Add extra safety checks around font texture creation. Motivated by some Play crashes.
This commit is contained in:
parent
c73b13781c
commit
7af93d08cf
4 changed files with 41 additions and 18 deletions
|
@ -56,10 +56,15 @@ public class TextRenderer {
|
||||||
total.y = (int) (p.descent() - p.ascent()) * lines.length + 2;
|
total.y = (int) (p.descent() - p.ascent()) * lines.length + 2;
|
||||||
// Returning a 0 size can create problems when the caller
|
// Returning a 0 size can create problems when the caller
|
||||||
// uses the measurement to create a texture.
|
// uses the measurement to create a texture.
|
||||||
|
// Also, clamp to a reasonable maximum size.
|
||||||
if (total.x < 1)
|
if (total.x < 1)
|
||||||
total.x = 1;
|
total.x = 1;
|
||||||
if (total.y < 1)
|
if (total.y < 1)
|
||||||
total.y = 1;
|
total.y = 1;
|
||||||
|
if (total.x > 2048)
|
||||||
|
total.x = 2048;
|
||||||
|
if (total.y > 2048)
|
||||||
|
total.y = 2048;
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -172,7 +172,8 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
|
||||||
if (iter != cache_.end()) {
|
if (iter != cache_.end()) {
|
||||||
entry = iter->second.get();
|
entry = iter->second.get();
|
||||||
entry->lastUsedFrame = frameCount_;
|
entry->lastUsedFrame = frameCount_;
|
||||||
draw_->BindTexture(0, entry->texture);
|
if (entry->texture)
|
||||||
|
draw_->BindTexture(0, entry->texture);
|
||||||
} else {
|
} else {
|
||||||
double size = 0.0;
|
double size = 0.0;
|
||||||
auto iter = fontMap_.find(fontHash_);
|
auto iter = fontMap_.find(fontHash_);
|
||||||
|
@ -195,8 +196,10 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
|
||||||
env_->DeleteLocalRef(jstr);
|
env_->DeleteLocalRef(jstr);
|
||||||
|
|
||||||
entry = new TextStringEntry();
|
entry = new TextStringEntry();
|
||||||
entry->bmWidth = entry->width = imageWidth;
|
entry->bmWidth = imageWidth;
|
||||||
entry->bmHeight = entry->height = imageHeight;
|
entry->width = imageWidth;
|
||||||
|
entry->bmHeight = imageHeight;
|
||||||
|
entry->height = imageHeight;
|
||||||
entry->lastUsedFrame = frameCount_;
|
entry->lastUsedFrame = frameCount_;
|
||||||
|
|
||||||
TextureDesc desc{};
|
TextureDesc desc{};
|
||||||
|
@ -206,6 +209,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
|
||||||
desc.height = entry->bmHeight;
|
desc.height = entry->bmHeight;
|
||||||
desc.depth = 1;
|
desc.depth = 1;
|
||||||
desc.mipLevels = 1;
|
desc.mipLevels = 1;
|
||||||
|
desc.generateMips = false;
|
||||||
desc.tag = "TextDrawer";
|
desc.tag = "TextDrawer";
|
||||||
|
|
||||||
uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight];
|
uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight];
|
||||||
|
@ -224,13 +228,17 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
|
||||||
entry->texture = draw_->CreateTexture(desc);
|
entry->texture = draw_->CreateTexture(desc);
|
||||||
delete[] bitmapData;
|
delete[] bitmapData;
|
||||||
cache_[key] = std::unique_ptr<TextStringEntry>(entry);
|
cache_[key] = std::unique_ptr<TextStringEntry>(entry);
|
||||||
draw_->BindTexture(0, entry->texture);
|
if (entry->texture) {
|
||||||
|
draw_->BindTexture(0, entry->texture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
float w = entry->bmWidth * fontScaleX_ * dpiScale_;
|
float w = entry->bmWidth * fontScaleX_ * dpiScale_;
|
||||||
float h = entry->bmHeight * fontScaleY_ * dpiScale_;
|
float h = entry->bmHeight * fontScaleY_ * dpiScale_;
|
||||||
DrawBuffer::DoAlign(align, &x, &y, &w, &h);
|
DrawBuffer::DoAlign(align, &x, &y, &w, &h);
|
||||||
target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color);
|
if (entry->texture) {
|
||||||
target.Flush(true);
|
target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color);
|
||||||
|
target.Flush(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextDrawerAndroid::ClearCache() {
|
void TextDrawerAndroid::ClearCache() {
|
||||||
|
|
|
@ -380,7 +380,9 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() {
|
||||||
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
|
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
|
||||||
};
|
};
|
||||||
VkResult res = vkBeginCommandBuffer(frameData.initCmd, &begin);
|
VkResult res = vkBeginCommandBuffer(frameData.initCmd, &begin);
|
||||||
_assert_(res == VK_SUCCESS);
|
if (res != VK_SUCCESS) {
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
frameData.hasInitCommands = true;
|
frameData.hasInitCommands = true;
|
||||||
}
|
}
|
||||||
return frameData_[curFrame].initCmd;
|
return frameData_[curFrame].initCmd;
|
||||||
|
|
|
@ -301,11 +301,9 @@ struct DescriptorSetKey {
|
||||||
|
|
||||||
class VKTexture : public Texture {
|
class VKTexture : public Texture {
|
||||||
public:
|
public:
|
||||||
VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc)
|
VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc)
|
||||||
: vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) {
|
: vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) {}
|
||||||
bool result = Create(cmd, pushBuffer, desc, alloc);
|
bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc);
|
||||||
_assert_(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
~VKTexture() {
|
~VKTexture() {
|
||||||
Destroy();
|
Destroy();
|
||||||
|
@ -322,8 +320,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc);
|
|
||||||
|
|
||||||
void Destroy() {
|
void Destroy() {
|
||||||
if (vkTex_) {
|
if (vkTex_) {
|
||||||
vkTex_->Destroy();
|
vkTex_->Destroy();
|
||||||
|
@ -335,9 +331,9 @@ private:
|
||||||
VulkanContext *vulkan_;
|
VulkanContext *vulkan_;
|
||||||
VulkanTexture *vkTex_ = nullptr;
|
VulkanTexture *vkTex_ = nullptr;
|
||||||
|
|
||||||
int mipLevels_;
|
int mipLevels_ = 0;
|
||||||
|
|
||||||
DataFormat format_;
|
DataFormat format_ = DataFormat::UNDEFINED;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VKFramebuffer;
|
class VKFramebuffer;
|
||||||
|
@ -698,6 +694,10 @@ enum class TextureState {
|
||||||
bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const TextureDesc &desc, VulkanDeviceAllocator *alloc) {
|
bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const TextureDesc &desc, VulkanDeviceAllocator *alloc) {
|
||||||
// Zero-sized textures not allowed.
|
// Zero-sized textures not allowed.
|
||||||
_assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1!
|
_assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1!
|
||||||
|
if (desc.width * desc.height * desc.depth <= 0) {
|
||||||
|
ELOG("Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
_assert_(push);
|
_assert_(push);
|
||||||
format_ = desc.format;
|
format_ = desc.format;
|
||||||
mipLevels_ = desc.mipLevels;
|
mipLevels_ = desc.mipLevels;
|
||||||
|
@ -1079,12 +1079,20 @@ InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture *VKContext::CreateTexture(const TextureDesc &desc) {
|
Texture *VKContext::CreateTexture(const TextureDesc &desc) {
|
||||||
if (!push_ || !renderManager_.GetInitCmd()) {
|
VkCommandBuffer initCmd = renderManager_.GetInitCmd();
|
||||||
|
if (!push_ || !initCmd) {
|
||||||
// Too early! Fail.
|
// Too early! Fail.
|
||||||
ELOG("Can't create textures before the first frame has started.");
|
ELOG("Can't create textures before the first frame has started.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return new VKTexture(vulkan_, renderManager_.GetInitCmd(), push_, desc, allocator_);
|
VKTexture *tex = new VKTexture(vulkan_, initCmd, push_, desc);
|
||||||
|
if (tex->Create(initCmd, push_, desc, allocator_)) {
|
||||||
|
return tex;
|
||||||
|
} else {
|
||||||
|
ELOG("Failed to create texture");
|
||||||
|
delete tex;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void CopySide(VkStencilOpState &dest, const StencilSide &src) {
|
static inline void CopySide(VkStencilOpState &dest, const StencilSide &src) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue