diff options
author | 2016-11-10 18:58:22 -0500 | |
---|---|---|
committer | 2016-11-10 18:58:22 -0500 | |
commit | 477e47ee5f6c52df72b1a98a4ee472e6842a697c (patch) | |
tree | 87a918aaef85c56249d4dbab1697f73c9f25f8ce | |
parent | bcabf45f0875833a1c3253b513d9862c01d0026b (diff) |
More UWP work - the UI actually renders (nw)
-rw-r--r-- | src/osd/modules/font/font_dwrite.cpp | 4 | ||||
-rw-r--r-- | src/osd/modules/lib/osdlib_uwp.cpp | 146 | ||||
-rw-r--r-- | src/osd/modules/monitor/monitor_dxgi.cpp | 18 | ||||
-rw-r--r-- | src/osd/uwp/window.cpp | 87 | ||||
-rw-r--r-- | src/osd/uwp/window.h | 4 |
5 files changed, 226 insertions, 33 deletions
diff --git a/src/osd/modules/font/font_dwrite.cpp b/src/osd/modules/font/font_dwrite.cpp index 6e66ccf320b..db85f96790f 100644 --- a/src/osd/modules/font/font_dwrite.cpp +++ b/src/osd/modules/font/font_dwrite.cpp @@ -9,7 +9,7 @@ #include "modules/osdmodule.h" #include "modules/lib/osdlib.h" -#if defined(OSD_WINDOWS) +#if defined(OSD_WINDOWS) || defined(OSD_UWP) #define WIN32_LEAN_AND_MEAN #include <windows.h> @@ -429,7 +429,7 @@ public: uint32_t tempChar = chnum; uint16_t glyphIndex; - HR_RET0(face->GetGlyphIndicesW(&tempChar, 1, &glyphIndex)); + HR_RET0(face->GetGlyphIndices(&tempChar, 1, &glyphIndex)); // get the width of this character DWRITE_GLYPH_METRICS glyph_metrics = { 0 }; diff --git a/src/osd/modules/lib/osdlib_uwp.cpp b/src/osd/modules/lib/osdlib_uwp.cpp index 66f753444b6..484ed3fb44c 100644 --- a/src/osd/modules/lib/osdlib_uwp.cpp +++ b/src/osd/modules/lib/osdlib_uwp.cpp @@ -315,7 +315,148 @@ char *osd_get_clipboard_text(void) #define load_library(filename) LoadLibrary(filename) #else // for Windows Store universal applications -#define load_library(filename) LoadPackagedLibrary(filename, 0) + +// This needs to change ASAP as it won't be allowed in the store +typedef HMODULE __stdcall t_LLA(const char *); +typedef FARPROC __stdcall t_GPA(HMODULE H, const char *); + +PIMAGE_NT_HEADERS WINAPI ImageNtHeader(PVOID Base) +{ + return (PIMAGE_NT_HEADERS) + ((LPBYTE)Base + ((PIMAGE_DOS_HEADER)Base)->e_lfanew); +} + +PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection(const IMAGE_NT_HEADERS *nt, + HMODULE module, DWORD_PTR rva) +{ + int i; + const IMAGE_SECTION_HEADER *sec; + + sec = (const IMAGE_SECTION_HEADER*)((const char*)&nt->OptionalHeader + + nt->FileHeader.SizeOfOptionalHeader); + for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) + { + if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva)) + return (PIMAGE_SECTION_HEADER)sec; + } + return NULL; +} + +PVOID WINAPI RtlImageRvaToVa(const IMAGE_NT_HEADERS *nt, HMODULE module, + DWORD_PTR rva, IMAGE_SECTION_HEADER **section) +{ + IMAGE_SECTION_HEADER *sec; + + if (section && *section) /* try this section first */ + { + sec = *section; + if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva)) + goto found; + } + if (!(sec = RtlImageRvaToSection(nt, module, rva))) return NULL; +found: + if (section) *section = sec; + return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress); +} + +PVOID WINAPI ImageDirectoryEntryToDataEx(PVOID base, BOOLEAN image, USHORT dir, PULONG size, PIMAGE_SECTION_HEADER *section) +{ + const IMAGE_NT_HEADERS *nt; + DWORD_PTR addr; + + *size = 0; + if (section) *section = NULL; + + if (!(nt = ImageNtHeader(base))) return NULL; + if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL; + if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL; + + *size = nt->OptionalHeader.DataDirectory[dir].Size; + if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)base + addr; + + return RtlImageRvaToVa(nt, (HMODULE)base, addr, section); +} + +// == Windows API GetProcAddress +void *PeGetProcAddressA(void *Base, LPCSTR Name) +{ + DWORD Tmp; + + IMAGE_NT_HEADERS *NT = ImageNtHeader(Base); + IMAGE_EXPORT_DIRECTORY *Exp = (IMAGE_EXPORT_DIRECTORY*)ImageDirectoryEntryToDataEx(Base, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &Tmp, 0); + if (Exp == 0 || Exp->NumberOfFunctions == 0) + { + SetLastError(ERROR_NOT_FOUND); + return 0; + } + + DWORD *Names = (DWORD*)(Exp->AddressOfNames + (DWORD_PTR)Base); + WORD *Ordinals = (WORD*)(Exp->AddressOfNameOrdinals + (DWORD_PTR)Base); + DWORD *Functions = (DWORD*)(Exp->AddressOfFunctions + (DWORD_PTR)Base); + + FARPROC Ret = 0; + + if ((DWORD_PTR)Name<65536) + { + if ((DWORD_PTR)Name - Exp->Base<Exp->NumberOfFunctions) + Ret = (FARPROC)(Functions[(DWORD_PTR)Name - Exp->Base] + (DWORD_PTR)Base); + } + else + { + for (DWORD i = 0; i<Exp->NumberOfNames && Ret == 0; i++) + { + char *Func = (char*)(Names[i] + (DWORD_PTR)Base); + if (Func && strcmp(Func, Name) == 0) + Ret = (FARPROC)(Functions[Ordinals[i]] + (DWORD_PTR)Base); + } + } + + if (Ret) + { + DWORD ExpStart = NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (DWORD)Base; + DWORD ExpSize = NT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + if ((DWORD)Ret >= ExpStart && (DWORD)Ret <= ExpStart + ExpSize) + { + // Forwarder + return 0; + } + return Ret; + } + + return 0; +} + +t_LLA* g_LoadLibraryA = 0; +t_GPA* g_GetProcAddressA = 0; + +void find_load_exports() +{ + char *Tmp = (char*)GetTickCount64; + Tmp = (char*)((~0xFFF)&(DWORD_PTR)Tmp); + + while (Tmp) + { + __try + { + if (Tmp[0] == 'M' && Tmp[1] == 'Z') + break; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + Tmp -= 0x1000; + } + + if (Tmp == 0) + return; + + g_LoadLibraryA = (t_LLA*)PeGetProcAddressA(Tmp, "LoadLibraryA"); + g_GetProcAddressA = (t_GPA*)PeGetProcAddressA(Tmp, "GetProcAddress"); +} + +#define load_library(filename) g_LoadLibraryA(osd::text::from_wstring(filename).c_str()) +#define get_proc_address(mod, proc) g_GetProcAddressA(mod, proc) + #endif namespace osd { @@ -326,6 +467,9 @@ public: : m_module(nullptr) { m_libraries = libraries; +#if defined(OSD_UWP) + find_load_exports(); +#endif } virtual ~dynamic_module_win32_impl() override diff --git a/src/osd/modules/monitor/monitor_dxgi.cpp b/src/osd/modules/monitor/monitor_dxgi.cpp index d506a00e95a..9fbc32a25bc 100644 --- a/src/osd/modules/monitor/monitor_dxgi.cpp +++ b/src/osd/modules/monitor/monitor_dxgi.cpp @@ -8,7 +8,7 @@ #include "modules/osdmodule.h" #include "monitor_module.h" -#if defined(OSD_WINDOWS) +#if defined(OSD_WINDOWS) || defined(OSD_UWP) // standard windows headers #define WIN32_LEAN_AND_MEAN @@ -86,6 +86,7 @@ public: if (!m_initialized) return nullptr; +#if defined(OSD_WINDOWS) RECT p; p.top = rect.top(); p.left = rect.left(); @@ -95,6 +96,13 @@ public: auto nearest = monitor_from_handle(reinterpret_cast<std::uintptr_t>(MonitorFromRect(&p, MONITOR_DEFAULTTONEAREST))); assert(nearest != nullptr); return nearest; +#elif defined(OSD_UWP) + if (list().size() == 0) + return nullptr; + + // For now just return first monitor + return list()[0]; +#endif } // Currently this method implementation is duplicated from the win32 module @@ -104,9 +112,17 @@ public: if (!m_initialized) return nullptr; +#if defined(OSD_WINDOWS) auto nearest = monitor_from_handle(reinterpret_cast<std::uintptr_t>(MonitorFromWindow(window.platform_window<HWND>(), MONITOR_DEFAULTTONEAREST))); assert(nearest != nullptr); return nearest; +#elif defined(OSD_UWP) + if (list().size() == 0) + return nullptr; + + // For now just return first monitor + return list()[0]; +#endif } protected: diff --git a/src/osd/uwp/window.cpp b/src/osd/uwp/window.cpp index d6bc8294c05..1e46490848b 100644 --- a/src/osd/uwp/window.cpp +++ b/src/osd/uwp/window.cpp @@ -104,7 +104,7 @@ static int ui_temp_was_paused; static HANDLE window_thread; static DWORD window_threadid; -static DWORD last_update_time; +static std::chrono::time_point<std::chrono::high_resolution_clock> last_update_time; static HANDLE ui_pause_event; @@ -559,33 +559,64 @@ void uwp_window_info::update() } // if we're visible and running and not in the middle of a resize, draw -// if (platform_window<HWND>() != nullptr && m_target != nullptr && has_renderer()) -// { -// bool got_lock = true; -// -// // only block if we're throttled -// //if (machine().video().throttled() || timeGetTime() - last_update_time > 250) -//// m_render_lock.lock(); -// // else -// got_lock = m_render_lock.try_lock(); -// -// // only render if we were able to get the lock -// if (got_lock) -// { -// render_primitive_list *primlist; -// -// // don't hold the lock; we just used it to see if rendering was still happening -// m_render_lock.unlock(); -// -// // ensure the target bounds are up-to-date, and then get the primitives -// primlist = renderer().get_primitives(); -// -// // post a redraw request with the primitive list as a parameter -// // last_update_time = timeGetTime(); -// -// //SendMessage(platform_window<HWND>(), WM_USER_REDRAW, 0, (LPARAM)primlist); -// } -// } + if (platform_window<HWND>() != nullptr && m_target != nullptr && has_renderer()) + { + bool got_lock = true; + auto clock = std::chrono::high_resolution_clock(); + + // only block if we're throttled + if (machine().video().throttled() || clock.now() - last_update_time > std::chrono::milliseconds(250)) + m_render_lock.lock(); + else + got_lock = m_render_lock.try_lock(); + + // only render if we were able to get the lock + if (got_lock) + { + render_primitive_list *primlist; + + // don't hold the lock; we just used it to see if rendering was still happening + m_render_lock.unlock(); + + // ensure the target bounds are up-to-date, and then get the primitives + primlist = renderer().get_primitives(); + + // post a redraw request with the primitive list as a parameter + last_update_time = clock.now(); + + // Actually perform the redraw + m_primlist = primlist; + draw_video_contents(FALSE); + } + } +} + +//============================================================ +// draw_video_contents +// (window thread) +//============================================================ + +void uwp_window_info::draw_video_contents(int update) +{ + assert(GetCurrentThreadId() == window_threadid); + + std::lock_guard<std::mutex> lock(m_render_lock); + + // if we're iconic, don't bother + if (platform_window<HWND>() != nullptr) + { + // if no bitmap, just fill + if (m_primlist == nullptr) + { + // For now do nothing, eventually we need to clear the window + } + + // otherwise, render with our drawing system + else + { + renderer().draw(update); + } + } } diff --git a/src/osd/uwp/window.h b/src/osd/uwp/window.h index fe8d2a47379..dcff102bda2 100644 --- a/src/osd/uwp/window.h +++ b/src/osd/uwp/window.h @@ -60,7 +60,8 @@ public: virtual osd_dim get_size() override { - throw ref new Platform::NotImplementedException(); + auto bounds = uwp_window()->Bounds; + return osd_dim(bounds.Width, bounds.Height); } bool win_has_menu() override @@ -123,6 +124,7 @@ public: private: int complete_create(); + void draw_video_contents(int update); void set_starting_view(int index, const char *defview, const char *view); int wnd_extra_width(); int wnd_extra_height(); |