summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Brad Hughes <bradhugh@outlook.com>2016-11-10 18:58:22 -0500
committer Brad Hughes <bradhugh@outlook.com>2016-11-10 18:58:22 -0500
commit477e47ee5f6c52df72b1a98a4ee472e6842a697c (patch)
tree87a918aaef85c56249d4dbab1697f73c9f25f8ce
parentbcabf45f0875833a1c3253b513d9862c01d0026b (diff)
More UWP work - the UI actually renders (nw)
-rw-r--r--src/osd/modules/font/font_dwrite.cpp4
-rw-r--r--src/osd/modules/lib/osdlib_uwp.cpp146
-rw-r--r--src/osd/modules/monitor/monitor_dxgi.cpp18
-rw-r--r--src/osd/uwp/window.cpp87
-rw-r--r--src/osd/uwp/window.h4
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();