Skip to content

Commit

Permalink
Merge pull request #17856 from hrydgard/uwp-color-emoji
Browse files Browse the repository at this point in the history
Windows UWP: Enable color emoji rendering through DirectWrite
  • Loading branch information
unknownbrackets committed Aug 6, 2023
2 parents d90dbcb + ab685be commit 014fbea
Show file tree
Hide file tree
Showing 6 changed files with 21 additions and 13 deletions.
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

0 comments on commit 014fbea

Please sign in to comment.