Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows UWP: Enable color emoji rendering through DirectWrite #17856

Merged
merged 2 commits into from
Aug 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Common/Data/Encoding/Utf8.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ int u8_strlen(const char *s);
void u8_inc(const char *s, int *i);
void u8_dec(const char *s, int *i);

// ranges grabbed from https://stackoverflow.com/a/62898106, ignoring the two bogus ranges.
// there's probably more. Doesn't need to be perfect.
inline bool CodepointIsProbablyEmoji(uint32_t c) {
return (c >= 127744 && c <= 129782) || (c >= 126980 && c <= 127569);
// Original check was some ranges grabbed from https://stackoverflow.com/a/62898106.
// But let's just go with checking if outside the BMP, it's not a big deal if we accidentally
// switch to color when not needed if someone uses a weird glyph.
return c > 0xFFFF;
}

bool AnyEmojiInString(const char *s, size_t byteCount);
Expand Down
2 changes: 1 addition & 1 deletion Common/GPU/D3D11/thin3d_d3d11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ class D3D11DrawContext : public DrawContext {

HWND hWnd_;
ID3D11Device *device_;
ID3D11DeviceContext *context_;
ID3D11Device1 *device1_;
ID3D11DeviceContext *context_;
ID3D11DeviceContext1 *context1_;

ID3D11Texture2D *bbRenderTargetTex_ = nullptr; // NOT OWNED
Expand Down
3 changes: 1 addition & 2 deletions Common/Render/Text/draw_text_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,6 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
if (text.empty())
return;

bool emoji = AnyEmojiInString(text.c_str(), text.size());

CacheKey key{ std::string(str), fontHash_ };
target.Flush(true);

Expand All @@ -263,6 +261,7 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x,
entry->lastUsedFrame = frameCount_;
} else {
DataFormat texFormat = use4444Format_ ? Draw::DataFormat::R4G4B4A4_UNORM_PACK16 : Draw::DataFormat::R8_UNORM;
bool emoji = AnyEmojiInString(text.c_str(), text.size());
if (emoji) {
texFormat = Draw::DataFormat::R8G8B8A8_UNORM;
}
Expand Down
15 changes: 12 additions & 3 deletions Common/Render/Text/draw_text_uwp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ void TextDrawerUWP::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStrin

m_d2dContext->BeginDraw();
m_d2dContext->Clear();
m_d2dContext->DrawTextLayout(D2D1::Point2F(0.0f, 0.0f), layout, m_d2dWhiteBrush);
m_d2dContext->DrawTextLayout(D2D1::Point2F(0.0f, 0.0f), layout, m_d2dWhiteBrush, texFormat == Draw::DataFormat::R8G8B8A8_UNORM ? D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT : D2D1_DRAW_TEXT_OPTIONS_NONE);
m_d2dContext->EndDraw();

layout->Release();
Expand All @@ -395,11 +395,15 @@ void TextDrawerUWP::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStrin
// because we need white. Well, we could using swizzle, but not all our backends support that.
if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM || texFormat == Draw::DataFormat::B8G8R8A8_UNORM) {
bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint32_t));
bool swap = texFormat == Draw::DataFormat::R8G8B8A8_UNORM;
uint32_t *bitmapData32 = (uint32_t *)&bitmapData[0];
for (int y = 0; y < entry.bmHeight; y++) {
uint32_t *bmpLine = (uint32_t *)&map.bits[map.pitch * y];
for (int x = 0; x < entry.bmWidth; x++) {
uint8_t bAlpha = (uint8_t)(map.bits[map.pitch * y + x * 4] & 0xff);
bitmapData32[entry.bmWidth * y + x] = (bAlpha << 24) | 0x00ffffff;
uint32_t v = bmpLine[x];
if (swap)
v = (v & 0xFF00FF00) | ((v >> 16) & 0xFF) | ((v << 16) & 0xFF0000);
bitmapData32[entry.bmWidth * y + x] = v;
}
}
} else if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) {
Expand Down Expand Up @@ -451,6 +455,7 @@ void TextDrawerUWP::DrawString(DrawBuffer &target, const char *str, float x, flo
entry->lastUsedFrame = frameCount_;
} else {
DataFormat texFormat;

// For our purposes these are equivalent, so just choose the supported one. D3D can emulate them.
if (draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16) & FMT_TEXTURE)
texFormat = Draw::DataFormat::A4R4G4B4_UNORM_PACK16;
Expand All @@ -459,6 +464,10 @@ void TextDrawerUWP::DrawString(DrawBuffer &target, const char *str, float x, flo
else
texFormat = Draw::DataFormat::R8G8B8A8_UNORM;

bool emoji = AnyEmojiInString(key.text.c_str(), key.text.size());
if (emoji)
texFormat = Draw::DataFormat::R8G8B8A8_UNORM;

entry = new TextStringEntry();

// Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format
Expand Down
2 changes: 1 addition & 1 deletion UI/MiscScreens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ void LogoScreen::render() {
int ppsspp_org_y = bounds.h / 2 + 130;
dc.DrawText("www.ppsspp.org", bounds.centerX(), ppsspp_org_y, textColor, ALIGN_CENTER);

#if !PPSSPP_PLATFORM(UWP)
#if !PPSSPP_PLATFORM(UWP) || defined(_DEBUG)
// Draw the graphics API, except on UWP where it's always D3D11
std::string apiName = screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME);
#ifdef _DEBUG
Expand Down
5 changes: 2 additions & 3 deletions Windows/GPU/D3D11Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,9 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
GetRes(hWnd_, width, height);

// Obtain DXGI factory from device (since we used nullptr for pAdapter above)
IDXGIFactory1* dxgiFactory = nullptr;
IDXGIFactory1 *dxgiFactory = nullptr;
IDXGIDevice *dxgiDevice = nullptr;
IDXGIDevice1* dxgiDevice1 = nullptr;
IDXGIAdapter* adapter = nullptr;
IDXGIAdapter *adapter = nullptr;
hr = device_->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));
if (SUCCEEDED(hr)) {
hr = dxgiDevice->GetAdapter(&adapter);
Expand Down