VK: Add extra safety checks around font texture creation. Motivated by some Play crashes.

This commit is contained in:
Henrik Rydgård 2018-11-21 17:33:30 +01:00
parent a30da4b674
commit f2244f789e
4 changed files with 41 additions and 18 deletions

View File

@ -56,10 +56,15 @@ public class TextRenderer {
total.y = (int) (p.descent() - p.ascent()) * lines.length + 2;
// Returning a 0 size can create problems when the caller
// uses the measurement to create a texture.
// Also, clamp to a reasonable maximum size.
if (total.x < 1)
total.x = 1;
if (total.y < 1)
total.y = 1;
if (total.x > 2048)
total.x = 2048;
if (total.y > 2048)
total.y = 2048;
return total;
}

View File

@ -172,7 +172,8 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
if (iter != cache_.end()) {
entry = iter->second.get();
entry->lastUsedFrame = frameCount_;
draw_->BindTexture(0, entry->texture);
if (entry->texture)
draw_->BindTexture(0, entry->texture);
} else {
double size = 0.0;
auto iter = fontMap_.find(fontHash_);
@ -195,8 +196,10 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
env_->DeleteLocalRef(jstr);
entry = new TextStringEntry();
entry->bmWidth = entry->width = imageWidth;
entry->bmHeight = entry->height = imageHeight;
entry->bmWidth = imageWidth;
entry->width = imageWidth;
entry->bmHeight = imageHeight;
entry->height = imageHeight;
entry->lastUsedFrame = frameCount_;
TextureDesc desc{};
@ -206,6 +209,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
desc.height = entry->bmHeight;
desc.depth = 1;
desc.mipLevels = 1;
desc.generateMips = false;
desc.tag = "TextDrawer";
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);
delete[] bitmapData;
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 h = entry->bmHeight * fontScaleY_ * dpiScale_;
DrawBuffer::DoAlign(align, &x, &y, &w, &h);
target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color);
target.Flush(true);
if (entry->texture) {
target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color);
target.Flush(true);
}
}
void TextDrawerAndroid::ClearCache() {

View File

@ -380,7 +380,9 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() {
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
};
VkResult res = vkBeginCommandBuffer(frameData.initCmd, &begin);
_assert_(res == VK_SUCCESS);
if (res != VK_SUCCESS) {
return VK_NULL_HANDLE;
}
frameData.hasInitCommands = true;
}
return frameData_[curFrame].initCmd;

View File

@ -301,11 +301,9 @@ struct DescriptorSetKey {
class VKTexture : public Texture {
public:
VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc)
: vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) {
bool result = Create(cmd, pushBuffer, desc, alloc);
_assert_(result);
}
VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc)
: vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) {}
bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc);
~VKTexture() {
Destroy();
@ -322,8 +320,6 @@ public:
}
private:
bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc);
void Destroy() {
if (vkTex_) {
vkTex_->Destroy();
@ -335,9 +331,9 @@ private:
VulkanContext *vulkan_;
VulkanTexture *vkTex_ = nullptr;
int mipLevels_;
int mipLevels_ = 0;
DataFormat format_;
DataFormat format_ = DataFormat::UNDEFINED;
};
class VKFramebuffer;
@ -698,6 +694,10 @@ enum class TextureState {
bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const TextureDesc &desc, VulkanDeviceAllocator *alloc) {
// Zero-sized textures not allowed.
_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);
format_ = desc.format;
mipLevels_ = desc.mipLevels;
@ -1079,12 +1079,20 @@ InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) {
}
Texture *VKContext::CreateTexture(const TextureDesc &desc) {
if (!push_ || !renderManager_.GetInitCmd()) {
VkCommandBuffer initCmd = renderManager_.GetInitCmd();
if (!push_ || !initCmd) {
// Too early! Fail.
ELOG("Can't create textures before the first frame has started.");
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) {