Source

Target

Showing with 1519 additions and 145 deletions
//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// angle_windowsstore.h:
#ifndef ANGLE_WINDOWSSTORE_H_
#define ANGLE_WINDOWSSTORE_H_
// The following properties can be set on the CoreApplication to support additional
// ANGLE configuration options.
//
// The Visual Studio sample templates provided with this version of ANGLE have examples
// of how to set these property values.
//
// Property: EGLNativeWindowTypeProperty
// Type: IInspectable
// Description: Set this property to specify the window type to use for creating a surface.
// If this property is missing, surface creation will fail.
//
const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty";
//
// Property: EGLRenderSurfaceSizeProperty
// Type: Size
// Description: Set this property to specify a preferred size in pixels of the render surface.
// The render surface size width and height must be greater than 0.
// If this property is set, then the render surface size is fixed.
// If this property is missing, a default behavior will be provided.
// The default behavior uses the window size if a CoreWindow is specified or
// the size of the SwapChainPanel control if one is specified.
//
const wchar_t EGLRenderSurfaceSizeProperty[] = L"EGLRenderSurfaceSizeProperty";
#endif // ANGLE_WINDOWSSTORE_H_
......@@ -7,6 +7,6 @@
// This is a default commit hash header, when git is not available.
//
#define ANGLE_COMMIT_HASH "abce76206141"
#define ANGLE_COMMIT_HASH "30d6c255d238"
#define ANGLE_COMMIT_HASH_SIZE 12
#define ANGLE_COMMIT_DATE "2014-09-23 19:37:05 +0000"
#define ANGLE_COMMIT_DATE "2014-11-13 17:37:03 +0000"
//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// NativeWindow.h: Defines NativeWindow, a class for managing and
// performing operations on an EGLNativeWindowType.
// It is used for HWND (Desktop Windows) and IInspectable objects
//(Windows Store Applications).
#ifndef COMMON_NATIVEWINDOW_H_
#define COMMON_NATIVEWINDOW_H_
#include <EGL/eglplatform.h>
#include "common/debug.h"
#include "common/platform.h"
// DXGISwapChain and DXGIFactory are typedef'd to specific required
// types. The HWND NativeWindow implementation requires IDXGISwapChain
// and IDXGIFactory and the Windows Store NativeWindow
// implementation requires IDXGISwapChain1 and IDXGIFactory2.
#if defined(ANGLE_ENABLE_WINDOWS_STORE)
typedef IDXGISwapChain1 DXGISwapChain;
typedef IDXGIFactory2 DXGIFactory;
#include <wrl.h>
#include <wrl/wrappers/corewrappers.h>
#include <windows.applicationmodel.core.h>
#include <memory>
namespace rx
{
class InspectableNativeWindow;
}
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
#else
typedef IDXGISwapChain DXGISwapChain;
typedef IDXGIFactory DXGIFactory;
#endif
namespace rx
{
class NativeWindow
{
public:
explicit NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display);
bool initialize();
bool getClientRect(LPRECT rect);
bool isIconic();
# if defined(ANGLE_ENABLE_D3D11)
typedef ID3D11Device Device;
#else
typedef IDirect3DDevice9 Device;
#endif
HRESULT createSwapChain(Device* device, DXGIFactory* factory,
DXGI_FORMAT format, UINT width, UINT height,
DXGISwapChain** swapChain);
inline EGLNativeWindowType getNativeWindow() const { return mWindow; }
inline EGLNativeDisplayType getNativeDisplay() const { return mDisplay; }
private:
EGLNativeWindowType mWindow;
EGLNativeDisplayType mDisplay;
#if defined(ANGLE_ENABLE_WINDOWS_STORE)
std::shared_ptr<InspectableNativeWindow> mImpl;
#endif
};
bool IsValidEGLNativeWindowType(EGLNativeWindowType window);
}
#endif // COMMON_NATIVEWINDOW_H_
......@@ -5,26 +5,33 @@
//
#include "common/angleutils.h"
#include "debug.h"
#include <stdio.h>
#include <vector>
std::string FormatString(const char *fmt, va_list vararg)
size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char>& outBuffer)
{
static std::vector<char> buffer(512);
// Attempt to just print to the current buffer
int len = vsnprintf(&buffer[0], buffer.size(), fmt, vararg);
if (len < 0 || static_cast<size_t>(len) >= buffer.size())
int len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, vararg);
if (len < 0 || static_cast<size_t>(len) >= outBuffer.size())
{
// Buffer was not large enough, calculate the required size and resize the buffer
len = vsnprintf(NULL, 0, fmt, vararg);
buffer.resize(len + 1);
outBuffer.resize(len + 1);
// Print again
vsnprintf(&buffer[0], buffer.size(), fmt, vararg);
len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, vararg);
}
ASSERT(len >= 0);
return static_cast<size_t>(len);
}
std::string FormatString(const char *fmt, va_list vararg)
{
static std::vector<char> buffer(512);
return std::string(buffer.data(), len);
size_t len = FormatStringIntoVector(fmt, vararg, buffer);
return std::string(&buffer[0], len);
}
std::string FormatString(const char *fmt, ...)
......
......@@ -17,6 +17,7 @@
#include <set>
#include <sstream>
#include <cstdarg>
#include <vector>
// A macro to disallow the copy constructor and operator= functions
// This must be used in the private: declarations for a class
......@@ -95,6 +96,13 @@ inline void StructZero(T *obj)
memset(obj, 0, sizeof(T));
}
template <typename T>
inline bool IsMaskFlagSet(T mask, T flag)
{
// Handles multibit flags as well
return (mask & flag) == flag;
}
inline const char* MakeStaticString(const std::string &str)
{
static std::set<std::string> strings;
......@@ -132,9 +140,12 @@ inline std::string Str(int i)
return strstr.str();
}
size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char>& buffer);
std::string FormatString(const char *fmt, va_list vararg);
std::string FormatString(const char *fmt, ...);
// snprintf is not defined with MSVC prior to to msvc14
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
......
......@@ -17,41 +17,211 @@
namespace gl
{
#if defined(ANGLE_ENABLE_PERF)
typedef void (WINAPI *PerfOutputFunction)(D3DCOLOR, LPCWSTR);
#else
typedef void (*PerfOutputFunction)(unsigned int, const wchar_t*);
#endif
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
// Wraps the D3D9/D3D11 debug annotation functions.
class DebugAnnotationWrapper
{
public:
DebugAnnotationWrapper() { };
virtual ~DebugAnnotationWrapper() { };
virtual void beginEvent(const std::wstring &eventName) = 0;
virtual void endEvent() = 0;
virtual void setMarker(const std::wstring &markerName) = 0;
virtual bool getStatus() = 0;
};
static void output(bool traceFileDebugOnly, PerfOutputFunction perfFunc, const char *format, va_list vararg)
#if defined(ANGLE_ENABLE_D3D9)
class D3D9DebugAnnotationWrapper : public DebugAnnotationWrapper
{
#if defined(ANGLE_ENABLE_PERF) || defined(ANGLE_ENABLE_TRACE)
std::string formattedMessage = FormatString(format, vararg);
public:
void beginEvent(const std::wstring &eventName)
{
D3DPERF_BeginEvent(0, eventName.c_str());
}
void endEvent()
{
D3DPERF_EndEvent();
}
void setMarker(const std::wstring &markerName)
{
D3DPERF_SetMarker(0, markerName.c_str());
}
bool getStatus()
{
return !!D3DPERF_GetStatus();
}
};
#endif // ANGLE_ENABLE_D3D9
#if defined(ANGLE_ENABLE_D3D11)
class D3D11DebugAnnotationWrapper : public DebugAnnotationWrapper
{
public:
D3D11DebugAnnotationWrapper()
: mInitialized(false),
mD3d11Module(NULL),
mUserDefinedAnnotation(NULL)
{
// D3D11 devices can't be created during DllMain.
// We defer device creation until the object is actually used.
}
~D3D11DebugAnnotationWrapper()
{
if (mInitialized)
{
SafeRelease(mUserDefinedAnnotation);
FreeLibrary(mD3d11Module);
}
}
virtual void beginEvent(const std::wstring &eventName)
{
initializeDevice();
mUserDefinedAnnotation->BeginEvent(eventName.c_str());
}
virtual void endEvent()
{
initializeDevice();
mUserDefinedAnnotation->EndEvent();
}
virtual void setMarker(const std::wstring &markerName)
{
initializeDevice();
mUserDefinedAnnotation->SetMarker(markerName.c_str());
}
virtual bool getStatus()
{
// ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in Visual Studio 2013.
#if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE)
// In the Windows Store, we can use IDXGraphicsAnalysis. The call to GetDebugInterface1 only succeeds if the app is under capture.
// This should only be called in DEBUG mode.
// If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows Store ingestion checks.
IDXGraphicsAnalysis* graphicsAnalysis;
DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis));
bool underCapture = (graphicsAnalysis != NULL);
SafeRelease(graphicsAnalysis);
return underCapture;
#endif
#if defined(ANGLE_ENABLE_PERF)
if (perfActive())
// Otherwise, we have to return true here.
return true;
}
protected:
void initializeDevice()
{
// The perf function only accepts wide strings, widen the ascii message
static std::wstring wideMessage;
if (wideMessage.capacity() < formattedMessage.length())
if (!mInitialized)
{
wideMessage.reserve(formattedMessage.size());
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
ASSERT(mD3d11Module);
PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice");
ASSERT(D3D11CreateDevice != NULL);
#endif // !ANGLE_ENABLE_WINDOWS_STORE
ID3D11Device* device = NULL;
ID3D11DeviceContext* context = NULL;
HRESULT hr = E_FAIL;
// Create a D3D_DRIVER_TYPE_NULL device, which is much cheaper than other types of device.
hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, NULL, &context);
ASSERT(SUCCEEDED(hr));
hr = context->QueryInterface(__uuidof(mUserDefinedAnnotation), reinterpret_cast<void**>(&mUserDefinedAnnotation));
ASSERT(SUCCEEDED(hr) && mUserDefinedAnnotation != NULL);
SafeRelease(device);
SafeRelease(context);
mInitialized = true;
}
}
bool mInitialized;
HMODULE mD3d11Module;
ID3DUserDefinedAnnotation* mUserDefinedAnnotation;
};
#endif // ANGLE_ENABLE_D3D11
static DebugAnnotationWrapper* g_DebugAnnotationWrapper = NULL;
void InitializeDebugAnnotations()
{
#if defined(ANGLE_ENABLE_D3D9)
g_DebugAnnotationWrapper = new D3D9DebugAnnotationWrapper();
#elif defined(ANGLE_ENABLE_D3D11)
// If the project uses D3D9 then we can use the D3D9 debug annotations, even with the D3D11 renderer.
// However, if D3D9 is unavailable (e.g. in Windows Store), then we use D3D11 debug annotations.
// The D3D11 debug annotations are methods on ID3DUserDefinedAnnotation, which is implemented by the DeviceContext.
// This doesn't have to be the same DeviceContext that the renderer uses, though.
g_DebugAnnotationWrapper = new D3D11DebugAnnotationWrapper();
#endif
}
void UninitializeDebugAnnotations()
{
if (g_DebugAnnotationWrapper != NULL)
{
SafeDelete(g_DebugAnnotationWrapper);
}
}
#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
wideMessage.assign(formattedMessage.begin(), formattedMessage.end());
enum DebugTraceOutputType
{
DebugTraceOutputTypeNone,
DebugTraceOutputTypeSetMarker,
DebugTraceOutputTypeBeginEvent
};
static void output(bool traceInDebugOnly, DebugTraceOutputType outputType, const char *format, va_list vararg)
{
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
static std::vector<char> buffer(512);
perfFunc(0, wideMessage.c_str());
if (perfActive())
{
size_t len = FormatStringIntoVector(format, vararg, buffer);
std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len);
switch (outputType)
{
case DebugTraceOutputTypeNone:
break;
case DebugTraceOutputTypeBeginEvent:
g_DebugAnnotationWrapper->beginEvent(formattedWideMessage);
break;
case DebugTraceOutputTypeSetMarker:
g_DebugAnnotationWrapper->setMarker(formattedWideMessage);
break;
}
}
#endif // ANGLE_ENABLE_PERF
#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
#if defined(ANGLE_ENABLE_TRACE)
#if defined(ANGLE_ENABLE_DEBUG_TRACE)
#if defined(NDEBUG)
if (traceFileDebugOnly)
if (traceInDebugOnly)
{
return;
}
#endif // NDEBUG
std::string formattedMessage = FormatString(format, vararg);
static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app);
if (file)
......@@ -60,25 +230,29 @@ static void output(bool traceFileDebugOnly, PerfOutputFunction perfFunc, const c
file.flush();
}
#endif // ANGLE_ENABLE_TRACE
#if defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER)
OutputDebugStringA(formattedMessage.c_str());
#endif // ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER
#endif // ANGLE_ENABLE_DEBUG_TRACE
}
void trace(bool traceFileDebugOnly, const char *format, ...)
void trace(bool traceInDebugOnly, const char *format, ...)
{
va_list vararg;
va_start(vararg, format);
#if defined(ANGLE_ENABLE_PERF)
output(traceFileDebugOnly, D3DPERF_SetMarker, format, vararg);
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
output(traceInDebugOnly, DebugTraceOutputTypeSetMarker, format, vararg);
#else
output(traceFileDebugOnly, NULL, format, vararg);
output(traceInDebugOnly, DebugTraceOutputTypeNone, format, vararg);
#endif
va_end(vararg);
}
bool perfActive()
{
#if defined(ANGLE_ENABLE_PERF)
static bool active = D3DPERF_GetStatus() != 0;
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
static bool active = g_DebugAnnotationWrapper->getStatus();
return active;
#else
return false;
......@@ -87,26 +261,28 @@ bool perfActive()
ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...)
{
#if defined(ANGLE_ENABLE_PERF)
#if !defined(ANGLE_ENABLE_TRACE)
#if !defined(ANGLE_ENABLE_DEBUG_TRACE)
if (!perfActive())
{
return;
}
#endif // !ANGLE_ENABLE_TRACE
#endif // !ANGLE_ENABLE_DEBUG_TRACE
va_list vararg;
va_start(vararg, format);
output(true, reinterpret_cast<PerfOutputFunction>(D3DPERF_BeginEvent), format, vararg);
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
output(true, DebugTraceOutputTypeBeginEvent, format, vararg);
#else
output(true, DebugTraceOutputTypeNone, format, vararg);
#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
va_end(vararg);
#endif // ANGLE_ENABLE_PERF
}
ScopedPerfEventHelper::~ScopedPerfEventHelper()
{
#if defined(ANGLE_ENABLE_PERF)
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
if (perfActive())
{
D3DPERF_EndEvent();
g_DebugAnnotationWrapper->endEvent();
}
#endif
}
......
......@@ -20,8 +20,8 @@
namespace gl
{
// Outputs text to the debugging log
void trace(bool traceFileDebugOnly, const char *format, ...);
// Outputs text to the debugging log, or the debugging window
void trace(bool traceInDebugOnly, const char *format, ...);
// Returns whether D3DPERF is active.
bool perfActive();
......@@ -36,31 +36,34 @@ namespace gl
private:
DISALLOW_COPY_AND_ASSIGN(ScopedPerfEventHelper);
};
void InitializeDebugAnnotations();
void UninitializeDebugAnnotations();
}
// A macro to output a trace of a function call and its arguments to the debugging log
#if defined(ANGLE_ENABLE_TRACE) || defined(ANGLE_ENABLE_PERF)
#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
#define TRACE(message, ...) gl::trace(true, "trace: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define TRACE(message, ...) (void(0))
#endif
// A macro to output a function call and its arguments to the debugging log, to denote an item in need of fixing.
#if defined(ANGLE_ENABLE_TRACE) || defined(ANGLE_ENABLE_PERF)
#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
#define FIXME(message, ...) gl::trace(false, "fixme: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define FIXME(message, ...) (void(0))
#endif
// A macro to output a function call and its arguments to the debugging log, in case of error.
#if defined(ANGLE_ENABLE_TRACE) || defined(ANGLE_ENABLE_PERF)
#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
#define ERR(message, ...) gl::trace(false, "err: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define ERR(message, ...) (void(0))
#endif
// A macro to log a performance event around a scope.
#if defined(ANGLE_ENABLE_TRACE) || defined(ANGLE_ENABLE_PERF)
#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
#if defined(_MSC_VER)
#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper ## __LINE__("%s" message "\n", __FUNCTION__, __VA_ARGS__);
#else
......@@ -83,7 +86,7 @@ namespace gl
#define UNUSED_ASSERTION_VARIABLE(variable) ((void)variable)
#endif
#ifndef ANGLE_ENABLE_TRACE
#ifndef ANGLE_ENABLE_DEBUG_TRACE
#define UNUSED_TRACE_VARIABLE(variable) ((void)variable)
#else
#define UNUSED_TRACE_VARIABLE(variable)
......@@ -128,7 +131,7 @@ namespace gl
#endif
// A macro functioning as a compile-time assert to validate constant conditions
#if defined(_MSC_VER) && _MSC_VER >= 1600
#if (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__GNUC__) && (__GNUC__ > 4 || __GNUC_MINOR__ >= 3))
#define META_ASSERT_MSG(condition, msg) static_assert(condition, msg)
#else
#define META_ASSERT_CONCAT(a, b) a ## b
......
//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#define ANGLE_DISABLED 0
#define ANGLE_ENABLED 1
// Feature defaults
// Direct3D9EX
// The "Debug This Pixel..." feature in PIX often fails when using the
// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7
// machine, define "ANGLE_D3D9EX=0" in your project file.
#if !defined(ANGLE_D3D9EX)
#define ANGLE_D3D9EX ANGLE_ENABLED
#endif
// Vsync
// ENABLED allows Vsync to be configured at runtime
// DISABLED disallows Vsync
#if !defined(ANGLE_VSYNC)
#define ANGLE_VSYNC ANGLE_ENABLED
#endif
// Program binary loading
#if !defined(ANGLE_PROGRAM_BINARY_LOAD)
#define ANGLE_PROGRAM_BINARY_LOAD ANGLE_ENABLED
#endif
// Shader debug info
#if !defined(ANGLE_SHADER_DEBUG_INFO)
#define ANGLE_SHADER_DEBUG_INFO ANGLE_DISABLED
#endif
......@@ -109,7 +109,7 @@ inline unsigned int unorm(float x)
inline bool supportsSSE2()
{
#ifdef ANGLE_PLATFORM_WINDOWS
#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM)
static bool checked = false;
static bool supports = false;
......@@ -118,7 +118,6 @@ inline bool supportsSSE2()
return supports;
}
#if defined(_M_IX86) || defined(_M_AMD64) // ARM doesn't provide __cpuid()
int info[4];
__cpuid(info, 0);
......@@ -128,7 +127,6 @@ inline bool supportsSSE2()
supports = (info[3] >> 26) & 1;
}
#endif
checked = true;
......
......@@ -11,9 +11,6 @@
#if defined(_WIN32) || defined(_WIN64)
# define ANGLE_PLATFORM_WINDOWS 1
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
# define ANGLE_PLATFORM_WINRT 1
# endif
#elif defined(__APPLE__)
# define ANGLE_PLATFORM_APPLE 1
# define ANGLE_PLATFORM_POSIX 1
......@@ -37,6 +34,9 @@
#endif
#ifdef ANGLE_PLATFORM_WINDOWS
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
# define ANGLE_ENABLE_WINDOWS_STORE 1
# endif
# ifndef STRICT
# define STRICT 1
# endif
......@@ -50,8 +50,9 @@
# include <windows.h>
# include <intrin.h>
# if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_PERF)
# if defined(ANGLE_ENABLE_D3D9)
# include <d3d9.h>
# include <dxgi.h>
# if !defined(COMPILER_IMPLEMENTATION)
# include <d3dcompiler.h>
# endif
......@@ -62,13 +63,26 @@
# include <d3d10.h>
# include <d3d11.h>
# include <dxgi.h>
# if _MSC_VER >= 1700
# if defined(_MSC_VER) && (_MSC_VER >= 1700)
# include <d3d11_1.h>
# include <dxgi1_2.h>
# endif
# if !defined(COMPILER_IMPLEMENTATION)
# include <d3dcompiler.h>
# endif
# if defined(__MINGW32__)
# endif
# if defined(ANGLE_ENABLE_WINDOWS_STORE)
# include <dxgi1_3.h>
# if defined(_DEBUG)
# if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
# include <DXProgrammableCapture.h>
# endif
# include <dxgidebug.h>
# endif
# endif
# if defined(__MINGW32__) // Missing defines on MinGW
typedef enum D3D11_MAP_FLAG
{
D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000L
......@@ -78,8 +92,68 @@ typedef struct D3D11_QUERY_DATA_SO_STATISTICS
UINT64 NumPrimitivesWritten;
UINT64 PrimitivesStorageNeeded;
} D3D11_QUERY_DATA_SO_STATISTICS;
# endif
# endif
typedef HRESULT (WINAPI *PFN_D3D11_CREATE_DEVICE)(
IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL *,
UINT FeatureLevels, UINT, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **);
#define D3D11_MESSAGE_CATEGORY UINT
#define D3D11_MESSAGE_SEVERITY UINT
#define D3D11_MESSAGE_ID UINT
struct D3D11_MESSAGE;
typedef struct D3D11_INFO_QUEUE_FILTER_DESC
{
UINT NumCategories;
D3D11_MESSAGE_CATEGORY *pCategoryList;
UINT NumSeverities;
D3D11_MESSAGE_SEVERITY *pSeverityList;
UINT NumIDs;
D3D11_MESSAGE_ID *pIDList;
} D3D11_INFO_QUEUE_FILTER_DESC;
typedef struct D3D11_INFO_QUEUE_FILTER
{
D3D11_INFO_QUEUE_FILTER_DESC AllowList;
D3D11_INFO_QUEUE_FILTER_DESC DenyList;
} D3D11_INFO_QUEUE_FILTER;
static const IID IID_ID3D11InfoQueue = { 0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6 };
MIDL_INTERFACE("6543dbb6-1b48-42f5-ab82-e97ec74326f6") ID3D11InfoQueue : public IUnknown
{
public:
virtual HRESULT __stdcall SetMessageCountLimit(UINT64) = 0;
virtual void __stdcall ClearStoredMessages() = 0;
virtual HRESULT __stdcall GetMessage(UINT64, D3D11_MESSAGE *, SIZE_T *) = 0;
virtual UINT64 __stdcall GetNumMessagesAllowedByStorageFilter() = 0;
virtual UINT64 __stdcall GetNumMessagesDeniedByStorageFilter() = 0;
virtual UINT64 __stdcall GetNumStoredMessages() = 0;
virtual UINT64 __stdcall GetNumStoredMessagesAllowedByRetrievalFilter() = 0;
virtual UINT64 __stdcall GetNumMessagesDiscardedByMessageCountLimit() = 0;
virtual UINT64 __stdcall GetMessageCountLimit() = 0;
virtual HRESULT __stdcall AddStorageFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0;
virtual HRESULT __stdcall GetStorageFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0;
virtual void __stdcall ClearStorageFilter() = 0;
virtual HRESULT __stdcall PushEmptyStorageFilter() = 0;
virtual HRESULT __stdcall PushCopyOfStorageFilter() = 0;
virtual HRESULT __stdcall PushStorageFilter(D3D11_INFO_QUEUE_FILTER *) = 0;
virtual void __stdcall PopStorageFilter() = 0;
virtual UINT __stdcall GetStorageFilterStackSize() = 0;
virtual HRESULT __stdcall AddRetrievalFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0;
virtual HRESULT __stdcall GetRetrievalFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0;
virtual void __stdcall ClearRetrievalFilter() = 0;
virtual HRESULT __stdcall PushEmptyRetrievalFilter() = 0;
virtual HRESULT __stdcall PushCopyOfRetrievalFilter() = 0;
virtual HRESULT __stdcall PushRetrievalFilter(D3D11_INFO_QUEUE_FILTER *) = 0;
virtual void __stdcall PopRetrievalFilter() = 0;
virtual UINT __stdcall GetRetrievalFilterStackSize() = 0;
virtual HRESULT __stdcall AddMessage(D3D11_MESSAGE_CATEGORY, D3D11_MESSAGE_SEVERITY, D3D11_MESSAGE_ID, LPCSTR) = 0;
virtual HRESULT __stdcall AddApplicationMessage(D3D11_MESSAGE_SEVERITY, LPCSTR) = 0;
virtual HRESULT __stdcall SetBreakOnCategory(D3D11_MESSAGE_CATEGORY, BOOL) = 0;
virtual HRESULT __stdcall SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY, BOOL) = 0;
virtual HRESULT __stdcall SetBreakOnID(D3D11_MESSAGE_ID, BOOL) = 0;
virtual BOOL __stdcall GetBreakOnCategory(D3D11_MESSAGE_CATEGORY) = 0;
virtual BOOL __stdcall GetBreakOnSeverity(D3D11_MESSAGE_SEVERITY) = 0;
virtual BOOL __stdcall GetBreakOnID(D3D11_MESSAGE_ID) = 0;
virtual void __stdcall SetMuteDebugOutput(BOOL) = 0;
virtual BOOL __stdcall GetMuteDebugOutput() = 0;
};
#endif // __MINGW32__
# undef near
# undef far
......
......@@ -10,29 +10,50 @@
#include <assert.h>
#if defined(ANGLE_PLATFORM_WINRT)
#ifdef ANGLE_ENABLE_WINDOWS_STORE
#include <vector>
std::vector<void *> *tls = nullptr;
std::vector<TLSIndex> *freeIndices = nullptr;
#include <set>
#include <map>
#include <mutex>
#include <wrl/client.h>
#include <wrl/async.h>
#include <Windows.System.Threading.h>
using namespace std;
using namespace Windows::Foundation;
using namespace ABI::Windows::System::Threading;
// Thread local storage for Windows Store support
typedef vector<void*> ThreadLocalData;
static __declspec(thread) ThreadLocalData* currentThreadData = nullptr;
static set<ThreadLocalData*> allThreadData;
static DWORD nextTlsIndex = 0;
static vector<DWORD> freeTlsIndices;
#endif
TLSIndex CreateTLSIndex()
{
TLSIndex index;
#if defined(ANGLE_PLATFORM_WINRT)
if (!tls)
tls = new std::vector<void *>;
if (freeIndices && !freeIndices->empty()) {
index = freeIndices->back();
freeIndices->pop_back();
return index;
} else {
tls->push_back(nullptr);
return tls->size() - 1;
#ifdef ANGLE_PLATFORM_WINDOWS
#ifdef ANGLE_ENABLE_WINDOWS_STORE
if (!freeTlsIndices.empty())
{
DWORD result = freeTlsIndices.back();
freeTlsIndices.pop_back();
index = result;
}
#elif defined(ANGLE_PLATFORM_WINDOWS)
else
{
index = nextTlsIndex++;
}
#else
index = TlsAlloc();
#endif
#elif defined(ANGLE_PLATFORM_POSIX)
// Create global pool key
if ((pthread_key_create(&index, NULL)) != 0)
......@@ -53,13 +74,23 @@ bool DestroyTLSIndex(TLSIndex index)
return false;
}
#if defined(ANGLE_PLATFORM_WINRT)
if (!freeIndices)
freeIndices = new std::vector<TLSIndex>;
freeIndices->push_back(index);
#ifdef ANGLE_PLATFORM_WINDOWS
#ifdef ANGLE_ENABLE_WINDOWS_STORE
assert(index < nextTlsIndex);
assert(find(freeTlsIndices.begin(), freeTlsIndices.end(), index) == freeTlsIndices.end());
freeTlsIndices.push_back(index);
for (auto threadData : allThreadData)
{
if (threadData->size() > index)
{
threadData->at(index) = nullptr;
}
}
return true;
#elif ANGLE_PLATFORM_WINDOWS
#else
return (TlsFree(index) == TRUE);
#endif
#elif defined(ANGLE_PLATFORM_POSIX)
return (pthread_key_delete(index) == 0);
#endif
......@@ -73,11 +104,25 @@ bool SetTLSValue(TLSIndex index, void *value)
return false;
}
#if defined(ANGLE_PLATFORM_WINRT)
tls->at(index) = value;
#ifdef ANGLE_PLATFORM_WINDOWS
#ifdef ANGLE_ENABLE_WINDOWS_STORE
ThreadLocalData* threadData = currentThreadData;
if (!threadData)
{
threadData = new ThreadLocalData(index + 1, nullptr);
allThreadData.insert(threadData);
currentThreadData = threadData;
}
else if (threadData->size() <= index)
{
threadData->resize(index + 1, nullptr);
}
threadData->at(index) = value;
return true;
#elif defined(ANGLE_PLATFORM_WINDOWS)
#else
return (TlsSetValue(index, value) == TRUE);
#endif
#elif defined(ANGLE_PLATFORM_POSIX)
return (pthread_setspecific(index, value) == 0);
#endif
......@@ -85,18 +130,26 @@ bool SetTLSValue(TLSIndex index, void *value)
void *GetTLSValue(TLSIndex index)
{
#if !defined(ANGLE_PLATFORM_WINRT) // Valid on WinRT, as Alloc handles the index creation
assert(index != TLS_INVALID_INDEX && "GetTLSValue(): Invalid TLS Index");
#endif
if (index == TLS_INVALID_INDEX)
{
return NULL;
}
#if defined(ANGLE_PLATFORM_WINRT)
return tls->at(index);
#elif defined(ANGLE_PLATFORM_WINDOWS)
#ifdef ANGLE_PLATFORM_WINDOWS
#ifdef ANGLE_ENABLE_WINDOWS_STORE
ThreadLocalData* threadData = currentThreadData;
if (threadData && threadData->size() > index)
{
return threadData->at(index);
}
else
{
return nullptr;
}
#else
return TlsGetValue(index);
#endif
#elif defined(ANGLE_PLATFORM_POSIX)
return pthread_getspecific(index);
#endif
......
......@@ -11,11 +11,15 @@
#include "common/platform.h"
#if defined(ANGLE_PLATFORM_WINRT)
typedef size_t TLSIndex;
# define TLS_OUT_OF_INDEXES (static_cast<TLSIndex>(-1))
# define TLS_INVALID_INDEX TLS_OUT_OF_INDEXES
#elif defined(ANGLE_PLATFORM_WINDOWS)
#ifdef ANGLE_PLATFORM_WINDOWS
// TLS does not exist for Windows Store and needs to be emulated
# ifdef ANGLE_ENABLE_WINDOWS_STORE
# define TLS_OUT_OF_INDEXES -1
# ifndef CREATE_SUSPENDED
# define CREATE_SUSPENDED 0x00000004
# endif
# endif
typedef DWORD TLSIndex;
# define TLS_INVALID_INDEX (TLS_OUT_OF_INDEXES)
#elif defined(ANGLE_PLATFORM_POSIX)
......@@ -28,6 +32,9 @@
# error Unsupported platform.
#endif
// TODO(kbr): for POSIX platforms this will have to be changed to take
// in a destructor function pointer, to allow the thread-local storage
// to be properly deallocated upon thread exit.
TLSIndex CreateTLSIndex();
bool DestroyTLSIndex(TLSIndex index);
......
......@@ -9,17 +9,16 @@
#include "common/utilities.h"
#include "common/mathutil.h"
#include "common/platform.h"
#if defined(ANGLE_PLATFORM_WINRT)
# include <locale>
# include <codecvt>
# include <wrl.h>
# include <windows.storage.h>
using namespace Microsoft::WRL;
using namespace ABI::Windows::Storage;
#endif
#include <set>
#if defined(ANGLE_ENABLE_WINDOWS_STORE)
# include <wrl.h>
# include <wrl/wrappers/corewrappers.h>
# include <windows.applicationmodel.core.h>
# include <windows.graphics.display.h>
#endif
namespace gl
{
......@@ -447,50 +446,10 @@ int VariableSortOrder(GLenum type)
}
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
std::string getTempPath()
{
#if defined(ANGLE_PLATFORM_WINRT)
static std::string path;
while (path.empty())
{
ComPtr<IApplicationDataStatics> factory;
Wrappers::HStringReference classId(RuntimeClass_Windows_Storage_ApplicationData);
HRESULT result = RoGetActivationFactory(classId.Get(), IID_PPV_ARGS(&factory));
if (FAILED(result))
break;
ComPtr<IApplicationData> applicationData;
result = factory->get_Current(&applicationData);
if (FAILED(result))
break;
ComPtr<IStorageFolder> storageFolder;
result = applicationData->get_LocalFolder(&storageFolder);
if (FAILED(result))
break;
ComPtr<IStorageItem> localFolder;
result = storageFolder.As(&localFolder);
if (FAILED(result))
break;
HSTRING localFolderPath;
result = localFolder->get_Path(&localFolderPath);
if (FAILED(result))
break;
std::wstring_convert< std::codecvt_utf8<wchar_t> > converter;
path = converter.to_bytes(WindowsGetStringRawBuffer(localFolderPath, NULL));
if (path.empty())
{
UNREACHABLE();
break;
}
}
return path;
#elif defined(ANGLE_PLATFORM_WINDOWS)
#ifdef ANGLE_PLATFORM_WINDOWS
char path[MAX_PATH];
DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path);
if (pathLen == 0)
......@@ -525,3 +484,33 @@ void writeFile(const char* path, const void* content, size_t size)
fwrite(content, sizeof(char), size, file);
fclose(file);
}
#endif // !ANGLE_ENABLE_WINDOWS_STORE
#if defined(ANGLE_ENABLE_WINDOWS_STORE)
void Sleep(unsigned long dwMilliseconds)
{
static HANDLE singletonEvent = nullptr;
HANDLE sleepEvent = singletonEvent;
if (!sleepEvent)
{
sleepEvent = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
if (!sleepEvent)
return;
HANDLE previousEvent = InterlockedCompareExchangePointerRelease(&singletonEvent, sleepEvent, nullptr);
if (previousEvent)
{
// Back out if multiple threads try to demand create at the same time.
CloseHandle(sleepEvent);
sleepEvent = previousEvent;
}
}
// Emulate sleep by waiting with timeout on an event that is never signalled.
WaitForSingleObjectEx(sleepEvent, dwMilliseconds, false);
}
#endif // ANGLE_ENABLE_WINDOWS_STORE
......@@ -46,7 +46,13 @@ template <typename outT> outT uiround(GLfloat value) { return static_cast<outT>(
}
#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
std::string getTempPath();
void writeFile(const char* path, const void* data, size_t size);
#endif
#if defined(ANGLE_ENABLE_WINDOWS_STORE)
void Sleep(_In_ unsigned long dwMilliseconds);
#endif
#endif // LIBGLESV2_UTILITIES_H
//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// NativeWindow.cpp: Handler for managing HWND native window types.
#include "common/NativeWindow.h"
#include "common/debug.h"
namespace rx
{
bool IsValidEGLNativeWindowType(EGLNativeWindowType window)
{
return (IsWindow(window) == TRUE);
}
NativeWindow::NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display) : mWindow(window), mDisplay(display)
{
}
bool NativeWindow::initialize()
{
return true;
}
bool NativeWindow::getClientRect(LPRECT rect)
{
return GetClientRect(mWindow, rect) == TRUE;
}
bool NativeWindow::isIconic()
{
return IsIconic(mWindow) == TRUE;
}
HRESULT NativeWindow::createSwapChain(NativeWindow::Device* device, DXGIFactory* factory,
DXGI_FORMAT format, unsigned int width, unsigned int height,
DXGISwapChain** swapChain)
{
if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0)
{
return E_INVALIDARG;
}
DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Format = format;
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.Flags = 0;
swapChainDesc.OutputWindow = mWindow;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Windowed = TRUE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
return factory->CreateSwapChain(device, &swapChainDesc, swapChain);
}
}
//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types.
#include <algorithm>
#include "common/winrt/CoreWindowNativeWindow.h"
using namespace ABI::Windows::Foundation::Collections;
namespace rx
{
typedef ITypedEventHandler<ABI::Windows::UI::Core::CoreWindow *, ABI::Windows::UI::Core::WindowSizeChangedEventArgs *> SizeChangedHandler;
CoreWindowNativeWindow::~CoreWindowNativeWindow()
{
unregisterForSizeChangeEvents();
}
bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet)
{
ComPtr<IPropertySet> props = propertySet;
ComPtr<IInspectable> win = window;
ComPtr<IInspectable> displayInformation = display;
SIZE swapChainSize = {};
bool swapChainSizeSpecified = false;
HRESULT result = S_OK;
// IPropertySet is an optional parameter and can be null.
// If one is specified, cache as an IMap and read the properties
// used for initial host initialization.
if (propertySet)
{
result = props.As(&mPropertyMap);
if (SUCCEEDED(result))
{
// The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
// was prevalidated to contain the EGLNativeWindowType before being passed to
// this host.
result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified);
}
}
if (SUCCEEDED(result))
{
result = win.As(&mCoreWindow);
}
if (SUCCEEDED(result))
{
result = displayInformation.As(&mDisplayInformation);
}
if (SUCCEEDED(result))
{
#if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP
ComPtr<ABI::Windows::Graphics::Display::IDisplayInformation2> displayInformation2;
result = mDisplayInformation.As(&displayInformation2);
ASSERT(SUCCEEDED(result));
result = displayInformation2->get_RawPixelsPerViewPixel(&mScaleFactor);
ASSERT(SUCCEEDED(result));
#else
ABI::Windows::Graphics::Display::ResolutionScale resolutionScale;
result = mDisplayInformation->get_ResolutionScale(&resolutionScale);
ASSERT(SUCCEEDED(result));
mScaleFactor = DOUBLE(resolutionScale) / 100.0;
#endif
}
if (SUCCEEDED(result))
{
// If a swapchain size is specfied, then the automatic resize
// behaviors implemented by the host should be disabled. The swapchain
// will be still be scaled when being rendered to fit the bounds
// of the host.
// Scaling of the swapchain output occurs automatically because if
// the scaling mode setting DXGI_SCALING_STRETCH on the swapchain.
if (swapChainSizeSpecified)
{
mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy };
mSupportsSwapChainResize = false;
}
else
{
ABI::Windows::Foundation::Rect rect;
HRESULT result = mCoreWindow->get_Bounds(&rect);
if (SUCCEEDED(result))
{
LONG width = std::floor(rect.Width * mScaleFactor + 0.5);
LONG height = std::floor(rect.Height * mScaleFactor + 0.5);
mClientRect = { 0, 0, width, height };
}
}
}
if (SUCCEEDED(result))
{
mNewClientRect = mClientRect;
mClientRectChanged = false;
return registerForSizeChangeEvents();
}
return false;
}
bool CoreWindowNativeWindow::registerForSizeChangeEvents()
{
HRESULT result = mCoreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &CoreWindowNativeWindow::onSizeChanged).Get(),
&mSizeChangedEventToken);
if (SUCCEEDED(result))
{
return true;
}
return false;
}
void CoreWindowNativeWindow::unregisterForSizeChangeEvents()
{
if (mCoreWindow)
{
(void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken);
}
mSizeChangedEventToken.value = 0;
}
HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain)
{
if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0)
{
return E_INVALIDARG;
}
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = format;
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.BufferCount = 2;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
*swapChain = nullptr;
ComPtr<IDXGISwapChain1> newSwapChain;
HRESULT result = factory->CreateSwapChainForCoreWindow(device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf());
if (SUCCEEDED(result))
{
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) // This block is disabled for Qt applications, as the resize events are expected
// Test if swapchain supports resize. On Windows Phone devices, this will return DXGI_ERROR_UNSUPPORTED. On
// other devices DXGI_ERROR_INVALID_CALL should be returned because the combination of flags passed
// (DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) are invalid flag combinations.
if (newSwapChain->ResizeBuffers(swapChainDesc.BufferCount, swapChainDesc.Width, swapChainDesc.Height, swapChainDesc.Format, DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) == DXGI_ERROR_UNSUPPORTED)
{
mSupportsSwapChainResize = false;
}
#endif // (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
result = newSwapChain.CopyTo(swapChain);
}
if (SUCCEEDED(result))
{
// If automatic swapchain resize behaviors have been disabled, then
// unregister for the resize change events.
if (mSupportsSwapChainResize == false)
{
unregisterForSizeChangeEvents();
}
}
return result;
}
// Basically, this shouldn't be used on Phone
HRESULT CoreWindowNativeWindow::onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *e)
{
ABI::Windows::Foundation::Size size;
if (SUCCEEDED(e->get_Size(&size)))
{
SIZE windowSizeInPixels = {
std::floor(size.Width * mScaleFactor + 0.5),
std::floor(size.Height * mScaleFactor + 0.5)
};
setNewClientSize(windowSizeInPixels);
}
return S_OK;
}
}
//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// CoreWindowNativeWindow.h: NativeWindow for managing ICoreWindow native window types.
#ifndef COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_
#define COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_
#include "common/winrt/InspectableNativeWindow.h"
#include <memory>
#include <windows.graphics.display.h>
namespace rx
{
class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this<CoreWindowNativeWindow>
{
public:
~CoreWindowNativeWindow();
bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet);
bool registerForSizeChangeEvents();
void unregisterForSizeChangeEvents();
HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain);
private:
HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *);
ComPtr<ABI::Windows::UI::Core::ICoreWindow> mCoreWindow;
ComPtr<ABI::Windows::Graphics::Display::IDisplayInformation> mDisplayInformation;
ComPtr<IMap<HSTRING, IInspectable*>> mPropertyMap;
};
}
#endif // COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_
//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// InspectableNativeWindow.cpp: NativeWindow base class for managing IInspectable native window types.
#include "common/winrt/CoreWindowNativeWindow.h"
#include "common/winrt/SwapChainPanelNativeWindow.h"
namespace rx
{
NativeWindow::NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display)
: mWindow(window), mDisplay(display)
{
}
bool NativeWindow::initialize()
{
// If the native window type is a IPropertySet, extract the
// EGLNativeWindowType (IInspectable) and initialize the
// proper host with this IPropertySet.
ComPtr<ABI::Windows::Foundation::Collections::IPropertySet> propertySet;
ComPtr<IInspectable> eglNativeWindow;
if (IsEGLConfiguredPropertySet(mWindow, &propertySet, &eglNativeWindow))
{
// A property set was found and the EGLNativeWindowType was
// retrieved. The mWindow member of the host to must be updated
// to use the EGLNativeWindowType specified in the property set.
// mWindow is treated as a raw pointer not an AddRef'd interface, so
// the old mWindow does not need a Release() before this assignment.
mWindow = eglNativeWindow.Get();
}
ComPtr<ABI::Windows::UI::Core::ICoreWindow> coreWindow;
ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> swapChainPanel;
if (IsCoreWindow(mWindow, &coreWindow))
{
mImpl = std::make_shared<CoreWindowNativeWindow>();
if (mImpl)
{
return mImpl->initialize(mWindow, mDisplay, propertySet.Get());
}
}
else if (IsSwapChainPanel(mWindow, &swapChainPanel))
{
mImpl = std::make_shared<SwapChainPanelNativeWindow>();
if (mImpl)
{
return mImpl->initialize(mWindow, mDisplay, propertySet.Get());
}
}
else
{
ERR("Invalid IInspectable EGLNativeWindowType detected. Valid IInspectables include ICoreWindow, ISwapChainPanel and IPropertySet");
}
return false;
}
bool NativeWindow::getClientRect(RECT *rect)
{
if (mImpl)
{
return mImpl->getClientRect(rect);
}
return false;
}
bool NativeWindow::isIconic()
{
return false;
}
HRESULT NativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain)
{
if (mImpl)
{
return mImpl->createSwapChain(device, factory, format, width, height, swapChain);
}
return E_UNEXPECTED;
}
bool IsCoreWindow(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Core::ICoreWindow> *coreWindow)
{
if (!window)
{
return false;
}
ComPtr<IInspectable> win = window;
ComPtr<ABI::Windows::UI::Core::ICoreWindow> coreWin;
if (SUCCEEDED(win.As(&coreWin)))
{
if (coreWindow != nullptr)
{
*coreWindow = coreWin.Detach();
}
return true;
}
return false;
}
bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> *swapChainPanel)
{
if (!window)
{
return false;
}
ComPtr<IInspectable> win = window;
ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> panel;
if (SUCCEEDED(win.As(&panel)))
{
if (swapChainPanel != nullptr)
{
*swapChainPanel = panel.Detach();
}
return true;
}
return false;
}
bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet, IInspectable **eglNativeWindow)
{
if (!window)
{
return false;
}
ComPtr<IInspectable> props = window;
ComPtr<IPropertySet> propSet;
ComPtr<IInspectable> nativeWindow;
ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>> propMap;
boolean hasEglNativeWindowPropertyKey = false;
HRESULT result = props.As(&propSet);
if (SUCCEEDED(result))
{
result = propSet.As(&propMap);
}
// Look for the presence of the EGLNativeWindowType in the property set
if (SUCCEEDED(result))
{
result = propMap->HasKey(HStringReference(EGLNativeWindowTypeProperty).Get(), &hasEglNativeWindowPropertyKey);
}
// If the IPropertySet does not contain the required EglNativeWindowType key, the property set is
// considered invalid.
if (SUCCEEDED(result) && !hasEglNativeWindowPropertyKey)
{
ERR("Could not find EGLNativeWindowTypeProperty in IPropertySet. Valid EGLNativeWindowTypeProperty values include ICoreWindow");
return false;
}
// The EglNativeWindowType property exists, so retreive the IInspectable that represents the EGLNativeWindowType
if (SUCCEEDED(result) && hasEglNativeWindowPropertyKey)
{
result = propMap->Lookup(HStringReference(EGLNativeWindowTypeProperty).Get(), &nativeWindow);
}
if (SUCCEEDED(result))
{
if (propertySet != nullptr)
{
result = propSet.CopyTo(propertySet);
}
}
if (SUCCEEDED(result))
{
if (eglNativeWindow != nullptr)
{
result = nativeWindow.CopyTo(eglNativeWindow);
}
}
if (SUCCEEDED(result))
{
return true;
}
return false;
}
// A Valid EGLNativeWindowType IInspectable can only be:
//
// ICoreWindow
// IPropertySet
//
// Anything else will be rejected as an invalid IInspectable.
bool IsValidEGLNativeWindowType(EGLNativeWindowType window)
{
return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(window);
}
// Attempts to read an optional SIZE property value that is assumed to be in the form of
// an ABI::Windows::Foundation::Size. This function validates the Size value before returning
// it to the caller.
//
// Possible return values are:
// S_OK, valueExists == true - optional SIZE value was successfully retrieved and validated
// S_OK, valueExists == false - optional SIZE value was not found
// E_INVALIDARG, valueExists = false - optional SIZE value was malformed in the property set.
// * Incorrect property type ( must be PropertyType_Size)
// * Invalid property value (width/height must be > 0)
// Additional errors may be returned from IMap or IPropertyValue
//
HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists)
{
if (!propertyMap || !propertyName || !value || !valueExists)
{
return false;
}
// Assume that the value does not exist
*valueExists = false;
*value = { 0, 0 };
ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue;
ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty;
Size sizeValue = { 0, 0 };
boolean hasKey = false;
HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), &hasKey);
if (SUCCEEDED(result) && !hasKey)
{
// Value does not exist, so return S_OK and set the exists parameter to false to indicate
// that a the optional property does not exist.
*valueExists = false;
return S_OK;
}
if (SUCCEEDED(result))
{
result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue);
}
if (SUCCEEDED(result))
{
result = propertyValue->get_Type(&propertyType);
}
// Check if the expected Size property is of PropertyType_Size type.
if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size)
{
if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0))
{
// A valid property value exists
*value = { static_cast<long>(sizeValue.Width), static_cast<long>(sizeValue.Height) };
*valueExists = true;
result = S_OK;
}
else
{
// An invalid Size property was detected. Width/Height values must > 0
result = E_INVALIDARG;
}
}
else
{
// An invalid property type was detected. Size property must be of PropertyType_Size
result = E_INVALIDARG;
}
return result;
}
}
//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// InspectableNativeWindow.h: Host specific implementation interface for
// managing IInspectable native window types.
#ifndef COMMON_WINRT_INSPECTABLENATIVEWINDOW_H_
#define COMMON_WINRT_INSPECTABLENATIVEWINDOW_H_
#include "common/platform.h"
#include "common/NativeWindow.h"
#include "angle_windowsstore.h"
#include <windows.ui.xaml.h>
#include <windows.ui.xaml.media.dxinterop.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
namespace rx
{
class InspectableNativeWindow
{
public:
InspectableNativeWindow() :
mSupportsSwapChainResize(true),
mRequiresSwapChainScaling(false),
mClientRectChanged(false),
mClientRect({0,0,0,0}),
mNewClientRect({0,0,0,0}),
mScaleFactor(1.0)
{
mSizeChangedEventToken.value = 0;
}
virtual ~InspectableNativeWindow(){}
virtual bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) = 0;
virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0;
virtual bool registerForSizeChangeEvents() = 0;
virtual void unregisterForSizeChangeEvents() = 0;
virtual HRESULT scaleSwapChain(const SIZE& newSize) { return S_OK; }
bool getClientRect(RECT *rect)
{
if (mClientRectChanged && mSupportsSwapChainResize)
{
mClientRect = mNewClientRect;
mClientRectChanged = false;
}
*rect = mClientRect;
return true;
}
void setNewClientSize(const SIZE &newSize)
{
if (mSupportsSwapChainResize && !mRequiresSwapChainScaling)
{
mNewClientRect = { 0, 0, newSize.cx, newSize.cy };
mClientRectChanged = true;
}
if (mRequiresSwapChainScaling)
{
scaleSwapChain(newSize);
}
}
protected:
bool mSupportsSwapChainResize;
bool mRequiresSwapChainScaling;
RECT mClientRect;
RECT mNewClientRect;
bool mClientRectChanged;
DOUBLE mScaleFactor;
EventRegistrationToken mSizeChangedEventToken;
};
bool IsCoreWindow(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Core::ICoreWindow> *coreWindow = nullptr);
bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> *swapChainPanel = nullptr);
bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet = nullptr, IInspectable **inspectable = nullptr);
HRESULT GetOptionalSizePropertyValue(const ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists);
}
#endif // COMMON_WINRT_INSPECTABLENATIVEWINDOW_H_
//
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// SwapChainPanelNativeWindow.cpp: NativeWindow for managing ISwapChainPanel native window types.
#include "common/winrt/SwapChainPanelNativeWindow.h"
#include <algorithm>
#include <math.h>
using namespace ABI::Windows::Foundation::Collections;
namespace rx
{
SwapChainPanelNativeWindow::~SwapChainPanelNativeWindow()
{
unregisterForSizeChangeEvents();
}
bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet)
{
ComPtr<IPropertySet> props = propertySet;
ComPtr<IInspectable> win = window;
SIZE swapChainSize = {};
bool swapChainSizeSpecified = false;
HRESULT result = S_OK;
// IPropertySet is an optional parameter and can be null.
// If one is specified, cache as an IMap and read the properties
// used for initial host initialization.
if (propertySet)
{
result = props.As(&mPropertyMap);
if (SUCCEEDED(result))
{
// The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet
// was prevalidated to contain the EGLNativeWindowType before being passed to
// this host.
result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified);
}
}
if (SUCCEEDED(result))
{
result = win.As(&mSwapChainPanel);
}
if (SUCCEEDED(result))
{
// If a swapchain size is specfied, then the automatic resize
// behaviors implemented by the host should be disabled. The swapchain
// will be still be scaled when being rendered to fit the bounds
// of the host.
// Scaling of the swapchain output needs to be handled by the
// host for swapchain panels even though the scaling mode setting
// DXGI_SCALING_STRETCH is configured on the swapchain.
if (swapChainSizeSpecified)
{
mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy };
// Enable host swapchain scaling
mRequiresSwapChainScaling = true;
}
else
{
result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect);
}
}
if (SUCCEEDED(result))
{
mNewClientRect = mClientRect;
mClientRectChanged = false;
return registerForSizeChangeEvents();
}
return false;
}
bool SwapChainPanelNativeWindow::registerForSizeChangeEvents()
{
ComPtr<ABI::Windows::UI::Xaml::ISizeChangedEventHandler> sizeChangedHandler;
ComPtr<ABI::Windows::UI::Xaml::IFrameworkElement> frameworkElement;
HRESULT result = Microsoft::WRL::MakeAndInitialize<SwapChainPanelSizeChangedHandler>(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this());
if (SUCCEEDED(result))
{
result = mSwapChainPanel.As(&frameworkElement);
}
if (SUCCEEDED(result))
{
result = frameworkElement->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken);
}
if (SUCCEEDED(result))
{
return true;
}
return false;
}
void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents()
{
ComPtr<ABI::Windows::UI::Xaml::IFrameworkElement> frameworkElement;
if (SUCCEEDED(mSwapChainPanel.As(&frameworkElement)))
{
(void)frameworkElement->remove_SizeChanged(mSizeChangedEventToken);
}
mSizeChangedEventToken.value = 0;
}
HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain)
{
if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0)
{
return E_INVALIDARG;
}
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = format;
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER;
swapChainDesc.BufferCount = 2;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
*swapChain = nullptr;
ComPtr<IDXGISwapChain1> newSwapChain;
ComPtr<ISwapChainPanelNative> swapChainPanelNative;
RECT currentPanelSize = {};
HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf());
if (SUCCEEDED(result))
{
result = mSwapChainPanel.As(&swapChainPanelNative);
}
if (SUCCEEDED(result))
{
result = swapChainPanelNative->SetSwapChain(newSwapChain.Get());
}
if (SUCCEEDED(result))
{
// The swapchain panel host requires an instance of the swapchain set on the SwapChainPanel
// to perform the runtime-scale behavior. This swapchain is cached here because there are
// no methods for retreiving the currently configured on from ISwapChainPanelNative.
mSwapChain = newSwapChain;
result = newSwapChain.CopyTo(swapChain);
}
// If the host is responsible for scaling the output of the swapchain, then
// scale it now before returning an instance to the caller. This is done by
// first reading the current size of the swapchain panel, then scaling
if (SUCCEEDED(result) && mRequiresSwapChainScaling)
{
result = GetSwapChainPanelSize(mSwapChainPanel, &currentPanelSize);
}
// Scale the swapchain to fit inside the contents of the panel.
if (SUCCEEDED(result) && mRequiresSwapChainScaling)
{
SIZE currentSize = { currentPanelSize.right, currentPanelSize.bottom };
result = scaleSwapChain(currentSize);
}
if (SUCCEEDED(result))
{
// If automatic swapchain resize behaviors have been disabled, then
// unregister for the resize change events.
if (mSupportsSwapChainResize == false)
{
unregisterForSizeChangeEvents();
}
}
return result;
}
HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize)
{
ABI::Windows::Foundation::Size renderScale = { (float)newSize.cx/(float)mClientRect.right, (float)newSize.cy/(float)mClientRect.bottom };
// Setup a scale matrix for the swap chain
DXGI_MATRIX_3X2_F scaleMatrix = {};
scaleMatrix._11 = renderScale.Width;
scaleMatrix._22 = renderScale.Height;
ComPtr<IDXGISwapChain2> swapChain2;
HRESULT result = mSwapChain.As(&swapChain2);
if (SUCCEEDED(result))
{
result = swapChain2->SetMatrixTransform(&scaleMatrix);
}
return result;
}
HRESULT GetSwapChainPanelSize(const ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> &swapChainPanel, RECT *windowSize)
{
ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement;
ABI::Windows::Foundation::Size renderSize = { 0, 0 };
HRESULT result = swapChainPanel.As(&uiElement);
if (SUCCEEDED(result))
{
result = uiElement->get_RenderSize(&renderSize);
}
if (SUCCEEDED(result))
{
*windowSize = { 0, 0, lround(renderSize.Width), lround(renderSize.Height) };
}
return result;
}
}