Merge remote-tracking branch 'upstream/master' into canary-old-1

This commit is contained in:
illusion98 2019-12-02 09:40:45 -05:00
commit c4c9f104d8
314 changed files with 2599 additions and 173826 deletions

View File

@ -5,12 +5,12 @@ os:
- linux
sudo: required
dist: xenial
dist: bionic
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-7
- llvm-toolchain-bionic-7
packages:
- clang-7
- llvm-7-dev
@ -18,7 +18,6 @@ addons:
- python3
- libc++-dev
- libc++abi-dev
- libglew-dev
- libgtk-3-dev
- libpthread-stubs0-dev
#- libvulkan1

View File

@ -105,7 +105,7 @@ sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes in
You will also need some development libraries. To get them on an Ubuntu system:
```
sudo apt-get install libgtk-3-dev libpthread-stubs0-dev liblz4-dev libglew-dev libx11-dev libvulkan-dev libc++-dev libc++abi-dev
sudo apt-get install libgtk-3-dev libpthread-stubs0-dev liblz4-dev libx11-dev libvulkan-dev libc++-dev libc++abi-dev
```
In addition, you will need the latest Vulkan libraries and drivers for your hardware.

View File

@ -22,9 +22,6 @@ includedirs({
defines({
"_UNICODE",
"UNICODE",
-- TODO(benvanik): find a better place for this stuff.
"GLEW_NO_GLU=1",
})
-- TODO(DrChat): Find a way to disable this on other architectures.
@ -73,7 +70,7 @@ filter({"configurations:Debug", "platforms:Windows"})
flags({
"NoMinimalRebuild", -- Required for /MP above.
})
filter({"configurations:Debug", "platforms:Linux"})
buildoptions({
"-g",
@ -97,9 +94,6 @@ filter({"configurations:Release", "platforms:Windows"})
linkoptions({
"/NODEFAULTLIB:MSVCRTD",
})
buildoptions({
"/MP /O2",
})
filter("platforms:Linux")
system("linux")
@ -227,7 +221,6 @@ solution("xenia")
include("third_party/discord-rpc.lua")
include("third_party/cxxopts.lua")
include("third_party/cpptoml.lua")
include("third_party/glew.lua")
include("third_party/glslang-spirv.lua")
include("third_party/imgui.lua")
include("third_party/libav.lua")

View File

@ -12,7 +12,6 @@ project("xenia-app")
"capstone",
"dxbc",
"discord-rpc",
"glew",
"glslang-spirv",
"imgui",
"libavcodec",
@ -71,7 +70,6 @@ project("xenia-app")
"X11",
"xcb",
"X11-xcb",
"GL",
"vulkan",
})

View File

@ -0,0 +1,315 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_APU_XAUDIO2_XAUDIO2_API_H_
#define XENIA_APU_XAUDIO2_XAUDIO2_API_H_
#include <Audioclient.h>
#include "xenia/base/platform_win.h"
namespace xe {
namespace apu {
namespace xaudio2 {
namespace api {
// Parts of XAudio2.h needed for Xenia. The header in the Windows SDK (for 2.8+)
// or the DirectX SDK (for 2.7 and below) is for a single version that is chosen
// for the target OS version at compile time, and cannot be useful for different
// DLL versions.
//
// XAudio 2.8 is also not available on Windows 7, but including the 2.7 header
// is complicated because it has the same name and include guard as the 2.8 one,
// and also 2.7 is outdated - support already dropped in Microsoft Store apps,
// for instance.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
class __declspec(uuid("5a508685-a254-4fba-9b82-9a24b00306af")) XAudio2_7;
interface __declspec(uuid("8bcf1f58-9fe7-4583-8ac6-e2adc465c8bb")) IXAudio2_7;
interface __declspec(uuid("60d8dac8-5aa1-4e8e-b597-2f5e2883d484")) IXAudio2_8;
#pragma pack(push, 1)
static constexpr UINT32 XE_XAUDIO2_MAX_QUEUED_BUFFERS = 64;
static constexpr float XE_XAUDIO2_MAX_FREQ_RATIO = 1024.0f;
static constexpr float XE_XAUDIO2_DEFAULT_FREQ_RATIO = 2.0f;
static constexpr UINT32 XE_XAUDIO2_COMMIT_NOW = 0;
static constexpr UINT32 XE_XAUDIO2_NO_LOOP_REGION = 0;
static constexpr UINT32 XE_XAUDIO2_DEFAULT_CHANNELS = 0;
static constexpr UINT32 XE_XAUDIO2_DEFAULT_SAMPLERATE = 0;
// 2.8+ only.
static constexpr UINT32 XE_XAUDIO2_VOICE_NOSAMPLESPLAYED = 0x0100;
interface IXAudio2_7;
interface IXAudio2_8;
interface IXAudio2Voice;
interface IXAudio2_7SourceVoice;
interface IXAudio2_8SourceVoice;
interface IXAudio2SubmixVoice;
interface IXAudio2_7MasteringVoice;
interface IXAudio2_8MasteringVoice;
interface IXAudio2EngineCallback;
interface IXAudio2VoiceCallback;
typedef UINT32 XAUDIO2_PROCESSOR;
static constexpr XAUDIO2_PROCESSOR XE_XAUDIO2_ANY_PROCESSOR = 0xFFFFFFFF;
static constexpr XAUDIO2_PROCESSOR XE_XAUDIO2_7_DEFAULT_PROCESSOR =
XE_XAUDIO2_ANY_PROCESSOR;
static constexpr XAUDIO2_PROCESSOR XE_XAUDIO2_8_DEFAULT_PROCESSOR = 0x00000001;
// 2.7 only.
struct XAUDIO2_DEVICE_DETAILS;
struct XAUDIO2_VOICE_DETAILS;
struct XAUDIO2_VOICE_SENDS;
struct XAUDIO2_EFFECT_CHAIN;
struct XAUDIO2_FILTER_PARAMETERS;
struct XAUDIO2_BUFFER {
UINT32 Flags;
UINT32 AudioBytes;
const BYTE* pAudioData;
UINT32 PlayBegin;
UINT32 PlayLength;
UINT32 LoopBegin;
UINT32 LoopLength;
UINT32 LoopCount;
void* pContext;
};
struct XAUDIO2_BUFFER_WMA;
struct XAUDIO2_VOICE_STATE {
void* pCurrentBufferContext;
UINT32 BuffersQueued;
UINT64 SamplesPlayed;
};
struct XAUDIO2_PERFORMANCE_DATA;
struct XAUDIO2_DEBUG_CONFIGURATION {
UINT32 TraceMask;
UINT32 BreakMask;
BOOL LogThreadID;
BOOL LogFileline;
BOOL LogFunctionName;
BOOL LogTiming;
};
static constexpr UINT32 XE_XAUDIO2_LOG_ERRORS = 0x0001;
static constexpr UINT32 XE_XAUDIO2_LOG_WARNINGS = 0x0002;
// clang-format off
// IXAudio2 2.7.
DECLARE_INTERFACE_(IXAudio2_7, IUnknown) {
STDMETHOD(QueryInterface)(REFIID riid, void** ppvInterface) = 0;
STDMETHOD_(ULONG, AddRef)() = 0;
STDMETHOD_(ULONG, Release)() = 0;
// 2.7 only.
STDMETHOD(GetDeviceCount)(UINT32* pCount) = 0;
// 2.7 only.
STDMETHOD(GetDeviceDetails)(UINT32 Index,
XAUDIO2_DEVICE_DETAILS* pDeviceDetails) = 0;
// 2.7 only.
STDMETHOD(Initialize)(
UINT32 Flags = 0,
XAUDIO2_PROCESSOR XAudio2Processor = XE_XAUDIO2_7_DEFAULT_PROCESSOR) = 0;
STDMETHOD(RegisterForCallbacks)(IXAudio2EngineCallback* pCallback) = 0;
STDMETHOD_(void, UnregisterForCallbacks)(
IXAudio2EngineCallback* pCallback) = 0;
STDMETHOD(CreateSourceVoice)(
IXAudio2_7SourceVoice** ppSourceVoice, const WAVEFORMATEX* pSourceFormat,
UINT32 Flags = 0, float MaxFrequencyRatio = XE_XAUDIO2_DEFAULT_FREQ_RATIO,
IXAudio2VoiceCallback* pCallback = nullptr,
const XAUDIO2_VOICE_SENDS* pSendList = nullptr,
const XAUDIO2_EFFECT_CHAIN* pEffectChain = nullptr) = 0;
STDMETHOD(CreateSubmixVoice)(
IXAudio2SubmixVoice** ppSubmixVoice, UINT32 InputChannels,
UINT32 InputSampleRate, UINT32 Flags = 0, UINT32 ProcessingStage = 0,
const XAUDIO2_VOICE_SENDS* pSendList = nullptr,
const XAUDIO2_EFFECT_CHAIN* pEffectChain = nullptr) = 0;
// 2.7: Device index instead of device ID, no stream category.
STDMETHOD(CreateMasteringVoice)(
IXAudio2_7MasteringVoice** ppMasteringVoice,
UINT32 InputChannels = XE_XAUDIO2_DEFAULT_CHANNELS,
UINT32 InputSampleRate = XE_XAUDIO2_DEFAULT_SAMPLERATE, UINT32 Flags = 0,
UINT32 DeviceIndex = 0,
const XAUDIO2_EFFECT_CHAIN* pEffectChain = nullptr) = 0;
STDMETHOD(StartEngine)() = 0;
STDMETHOD_(void, StopEngine)() = 0;
STDMETHOD(CommitChanges)(UINT32 OperationSet) = 0;
STDMETHOD_(void, GetPerformanceData)(XAUDIO2_PERFORMANCE_DATA* pPerfData) = 0;
STDMETHOD_(void, SetDebugConfiguration)(
const XAUDIO2_DEBUG_CONFIGURATION* pDebugConfiguration,
void* pReserved = nullptr) = 0;
};
// IXAudio2 2.8.
DECLARE_INTERFACE_(IXAudio2_8, IUnknown) {
STDMETHOD(QueryInterface)(REFIID riid, void** ppvInterface) = 0;
STDMETHOD_(ULONG, AddRef)() = 0;
STDMETHOD_(ULONG, Release)() = 0;
// 2.8: No GetDeviceCount, GetDeviceDetails and Initialize.
STDMETHOD(RegisterForCallbacks)(IXAudio2EngineCallback* pCallback) = 0;
STDMETHOD_(void, UnregisterForCallbacks)(
IXAudio2EngineCallback* pCallback) = 0;
STDMETHOD(CreateSourceVoice)(
IXAudio2_8SourceVoice** ppSourceVoice, const WAVEFORMATEX* pSourceFormat,
UINT32 Flags = 0, float MaxFrequencyRatio = XE_XAUDIO2_DEFAULT_FREQ_RATIO,
IXAudio2VoiceCallback* pCallback = nullptr,
const XAUDIO2_VOICE_SENDS* pSendList = nullptr,
const XAUDIO2_EFFECT_CHAIN* pEffectChain = nullptr) = 0;
STDMETHOD(CreateSubmixVoice)(
IXAudio2SubmixVoice** ppSubmixVoice, UINT32 InputChannels,
UINT32 InputSampleRate, UINT32 Flags = 0, UINT32 ProcessingStage = 0,
const XAUDIO2_VOICE_SENDS* pSendList = nullptr,
const XAUDIO2_EFFECT_CHAIN* pEffectChain = nullptr) = 0;
// 2.8: Device ID instead of device index, added stream category.
STDMETHOD(CreateMasteringVoice)(
IXAudio2_8MasteringVoice** ppMasteringVoice,
UINT32 InputChannels = XE_XAUDIO2_DEFAULT_CHANNELS,
UINT32 InputSampleRate = XE_XAUDIO2_DEFAULT_SAMPLERATE, UINT32 Flags = 0,
LPCWSTR szDeviceId = nullptr,
const XAUDIO2_EFFECT_CHAIN* pEffectChain = nullptr,
AUDIO_STREAM_CATEGORY StreamCategory = AudioCategory_GameEffects) = 0;
STDMETHOD(StartEngine)() = 0;
STDMETHOD_(void, StopEngine)() = 0;
STDMETHOD(CommitChanges)(UINT32 OperationSet) = 0;
STDMETHOD_(void, GetPerformanceData)(XAUDIO2_PERFORMANCE_DATA* pPerfData) = 0;
STDMETHOD_(void, SetDebugConfiguration)(
const XAUDIO2_DEBUG_CONFIGURATION* pDebugConfiguration,
void* pReserved = nullptr) = 0;
};
DECLARE_INTERFACE(IXAudio2Voice) {
#define XE_APU_XAUDIO2_API_DECLARE_IXAUDIO2VOICE_METHODS \
STDMETHOD_(void, GetVoiceDetails)(XAUDIO2_VOICE_DETAILS* pVoiceDetails) = 0; \
STDMETHOD(SetOutputVoices)(const XAUDIO2_VOICE_SENDS* pSendList) = 0; \
STDMETHOD(SetEffectChain)(const XAUDIO2_EFFECT_CHAIN* pEffectChain) = 0; \
STDMETHOD(EnableEffect)(UINT32 EffectIndex, \
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0; \
STDMETHOD(DisableEffect)(UINT32 EffectIndex, \
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0; \
STDMETHOD_(void, GetEffectState)(UINT32 EffectIndex, BOOL* pEnabled) = 0; \
STDMETHOD(SetEffectParameters)( \
UINT32 EffectIndex, const void* pParameters, UINT32 ParametersByteSize, \
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0; \
STDMETHOD(GetEffectParameters)(UINT32 EffectIndex, void* pParameters, \
UINT32 ParametersByteSize) = 0; \
STDMETHOD(SetFilterParameters)( \
const XAUDIO2_FILTER_PARAMETERS* pParameters, \
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0; \
STDMETHOD_(void, GetFilterParameters)( \
XAUDIO2_FILTER_PARAMETERS* pParameters) = 0; \
STDMETHOD(SetOutputFilterParameters)( \
IXAudio2Voice* pDestinationVoice, \
const XAUDIO2_FILTER_PARAMETERS* pParameters, \
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0; \
STDMETHOD_(void, GetOutputFilterParameters)( \
IXAudio2Voice* pDestinationVoice, \
XAUDIO2_FILTER_PARAMETERS* pParameters) = 0; \
STDMETHOD(SetVolume)(float Volume, \
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0; \
STDMETHOD_(void, GetVolume)(float* pVolume) = 0; \
STDMETHOD(SetChannelVolumes)( \
UINT32 Channels, const float* pVolumes, \
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0; \
STDMETHOD_(void, GetChannelVolumes)(UINT32 Channels, float* pVolumes) = 0; \
STDMETHOD(SetOutputMatrix)(IXAudio2Voice* pDestinationVoice, \
UINT32 SourceChannels, \
UINT32 DestinationChannels, \
const float* pLevelMatrix, \
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0; \
STDMETHOD_(void, GetOutputMatrix)(IXAudio2Voice* pDestinationVoice, \
UINT32 SourceChannels, \
UINT32 DestinationChannels, \
float* pLevelMatrix) = 0; \
STDMETHOD_(void, DestroyVoice)() = 0;
XE_APU_XAUDIO2_API_DECLARE_IXAUDIO2VOICE_METHODS
};
// IXAudio2SourceVoice 2.7.
DECLARE_INTERFACE_(IXAudio2_7SourceVoice, IXAudio2Voice) {
XE_APU_XAUDIO2_API_DECLARE_IXAUDIO2VOICE_METHODS
STDMETHOD(Start)(UINT32 Flags = 0,
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0;
STDMETHOD(Stop)(UINT32 Flags = 0,
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0;
STDMETHOD(SubmitSourceBuffer)(
const XAUDIO2_BUFFER* pBuffer,
const XAUDIO2_BUFFER_WMA* pBufferWMA = nullptr) = 0;
STDMETHOD(FlushSourceBuffers)() = 0;
STDMETHOD(Discontinuity)() = 0;
STDMETHOD(ExitLoop)(UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0;
// 2.7: No Flags.
STDMETHOD_(void, GetState)(XAUDIO2_VOICE_STATE* pVoiceState) = 0;
STDMETHOD(SetFrequencyRatio)(float Ratio,
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0;
STDMETHOD_(void, GetFrequencyRatio)(float* pRatio) = 0;
STDMETHOD(SetSourceSampleRate)(UINT32 NewSourceSampleRate) = 0;
};
// IXAudio2SourceVoice 2.8.
DECLARE_INTERFACE_(IXAudio2_8SourceVoice, IXAudio2Voice) {
XE_APU_XAUDIO2_API_DECLARE_IXAUDIO2VOICE_METHODS
STDMETHOD(Start)(UINT32 Flags = 0,
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0;
STDMETHOD(Stop)(UINT32 Flags = 0,
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0;
STDMETHOD(SubmitSourceBuffer)(
const XAUDIO2_BUFFER* pBuffer,
const XAUDIO2_BUFFER_WMA* pBufferWMA = nullptr) = 0;
STDMETHOD(FlushSourceBuffers)() = 0;
STDMETHOD(Discontinuity)() = 0;
STDMETHOD(ExitLoop)(UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0;
// 2.8: Flags added.
STDMETHOD_(void, GetState)(XAUDIO2_VOICE_STATE* pVoiceState,
UINT32 Flags = 0) = 0;
STDMETHOD(SetFrequencyRatio)(float Ratio,
UINT32 OperationSet = XE_XAUDIO2_COMMIT_NOW) = 0;
STDMETHOD_(void, GetFrequencyRatio)(float* pRatio) = 0;
STDMETHOD(SetSourceSampleRate)(UINT32 NewSourceSampleRate) = 0;
};
// IXAudio2MasteringVoice 2.7.
DECLARE_INTERFACE_(IXAudio2_7MasteringVoice, IXAudio2Voice) {
XE_APU_XAUDIO2_API_DECLARE_IXAUDIO2VOICE_METHODS
// 2.7: No GetChannelMask.
};
// IXAudio2MasteringVoice 2.8.
DECLARE_INTERFACE_(IXAudio2_8MasteringVoice, IXAudio2Voice) {
XE_APU_XAUDIO2_API_DECLARE_IXAUDIO2VOICE_METHODS
// 2.8: GetChannelMask added.
STDMETHOD(GetChannelMask)(DWORD* pChannelmask) = 0;
};
DECLARE_INTERFACE(IXAudio2VoiceCallback) {
// Called just before this voice's processing pass begins.
STDMETHOD_(void, OnVoiceProcessingPassStart)(UINT32 BytesRequired) = 0;
STDMETHOD_(void, OnVoiceProcessingPassEnd)() = 0;
STDMETHOD_(void, OnStreamEnd)() = 0;
STDMETHOD_(void, OnBufferStart)(void* pBufferContext) = 0;
STDMETHOD_(void, OnBufferEnd)(void* pBufferContext) = 0;
STDMETHOD_(void, OnLoopEnd)(void* pBufferContext) = 0;
STDMETHOD_(void, OnVoiceError)(void* pBufferContext, HRESULT Error) = 0;
};
#pragma pack(pop)
} // namespace api
} // namespace xaudio2
} // namespace apu
} // namespace xe
#endif // XENIA_APU_XAUDIO2_XAUDIO2_API_H_

View File

@ -12,8 +12,6 @@
// Must be included before xaudio2.h so we get the right windows.h include.
#include "xenia/base/platform_win.h"
#include <xaudio2.h> // NOLINT(build/include_order)
#include "xenia/apu/apu_flags.h"
#include "xenia/base/clock.h"
#include "xenia/base/logging.h"
@ -22,7 +20,7 @@ namespace xe {
namespace apu {
namespace xaudio2 {
class XAudio2AudioDriver::VoiceCallback : public IXAudio2VoiceCallback {
class XAudio2AudioDriver::VoiceCallback : public api::IXAudio2VoiceCallback {
public:
explicit VoiceCallback(xe::threading::Semaphore* semaphore)
: semaphore_(semaphore) {}
@ -45,74 +43,97 @@ class XAudio2AudioDriver::VoiceCallback : public IXAudio2VoiceCallback {
XAudio2AudioDriver::XAudio2AudioDriver(Memory* memory,
xe::threading::Semaphore* semaphore)
: AudioDriver(memory), semaphore_(semaphore) {
static_assert(frame_count_ == XAUDIO2_MAX_QUEUED_BUFFERS,
"xaudio header differs");
}
: AudioDriver(memory), semaphore_(semaphore) {}
XAudio2AudioDriver::~XAudio2AudioDriver() = default;
const DWORD ChannelMasks[] = {
0,
0,
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY,
0,
0,
0,
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT |
SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT,
0,
};
bool XAudio2AudioDriver::Initialize() {
HRESULT hr;
voice_callback_ = new VoiceCallback(semaphore_);
// Load XAudio2_8.dll dynamically - Windows 8.1 SDK references XAudio2_8.dll
// in xaudio2.lib, which is available on Windows 8.1, however, Windows 10 SDK
// references XAudio2_9.dll in it, which is only available in Windows 10, and
// XAudio2_8.dll is linked through a different .lib - xaudio2_8.lib, so easier
// not to link the .lib at all.
// Load the XAudio2 DLL dynamically. Needed both for 2.7 and for
// differentiating between 2.8 and later versions. Windows 8.1 SDK references
// XAudio2_8.dll in xaudio2.lib, which is available on Windows 8.1, however,
// Windows 10 SDK references XAudio2_9.dll in it, which is only available in
// Windows 10, and XAudio2_8.dll is linked through a different .lib -
// xaudio2_8.lib, so easier not to link the .lib at all.
xaudio2_module_ = reinterpret_cast<void*>(LoadLibrary(L"XAudio2_8.dll"));
if (!xaudio2_module_) {
XELOGE("LoadLibrary(XAudio2_8.dll) failed");
assert_always();
return false;
if (xaudio2_module_) {
api_minor_version_ = 8;
} else {
xaudio2_module_ = reinterpret_cast<void*>(LoadLibrary(L"XAudio2_7.dll"));
if (xaudio2_module_) {
api_minor_version_ = 7;
} else {
XELOGE("Failed to load XAudio 2.8 or 2.7 library DLL");
assert_always();
return false;
}
}
union {
HRESULT(__stdcall* xaudio2_create)
(IXAudio2** xaudio2_out, UINT32 flags, XAUDIO2_PROCESSOR xaudio2_processor);
FARPROC xaudio2_create_ptr;
};
xaudio2_create_ptr = GetProcAddress(
reinterpret_cast<HMODULE>(xaudio2_module_), "XAudio2Create");
if (!xaudio2_create_ptr) {
XELOGE("GetProcAddress(XAudio2_8.dll, XAudio2Create) failed");
assert_always();
return false;
// First CPU (2.8 default). XAUDIO2_ANY_PROCESSOR (2.7 default) steals too
// much time from other things. Ideally should process audio on what roughly
// represents thread 4 (5th) on the Xbox 360 (2.7 default on the console), or
// even beyond the 6 guest cores.
api::XAUDIO2_PROCESSOR processor = 0x00000001;
if (api_minor_version_ >= 8) {
union {
// clang-format off
HRESULT (__stdcall* xaudio2_create)(
api::IXAudio2_8** xaudio2_out, UINT32 flags,
api::XAUDIO2_PROCESSOR xaudio2_processor);
// clang-format on
FARPROC xaudio2_create_ptr;
};
xaudio2_create_ptr = GetProcAddress(
reinterpret_cast<HMODULE>(xaudio2_module_), "XAudio2Create");
if (!xaudio2_create_ptr) {
XELOGE("XAudio2Create not found in XAudio2_8.dll");
assert_always();
return false;
}
hr = xaudio2_create(&objects_.api_2_8.audio, 0, processor);
if (FAILED(hr)) {
XELOGE("XAudio2Create failed with %.8X", hr);
assert_always();
return false;
}
return InitializeObjects(objects_.api_2_8);
} else {
hr = CoCreateInstance(__uuidof(api::XAudio2_7), NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&objects_.api_2_7.audio));
if (FAILED(hr)) {
XELOGE("CoCreateInstance for XAudio2 failed with %.8X", hr);
assert_always();
return false;
}
hr = objects_.api_2_7.audio->Initialize(0, processor);
if (FAILED(hr)) {
XELOGE("IXAudio2::Initialize failed with %.8X", hr);
assert_always();
return false;
}
return InitializeObjects(objects_.api_2_7);
}
}
hr = xaudio2_create(&audio_, 0, XAUDIO2_DEFAULT_PROCESSOR);
if (FAILED(hr)) {
XELOGE("XAudio2Create failed with %.8X", hr);
assert_always();
return false;
}
template <typename Objects>
bool XAudio2AudioDriver::InitializeObjects(Objects& objects) {
HRESULT hr;
XAUDIO2_DEBUG_CONFIGURATION config;
config.TraceMask = XAUDIO2_LOG_ERRORS | XAUDIO2_LOG_WARNINGS;
api::XAUDIO2_DEBUG_CONFIGURATION config;
config.TraceMask = api::XE_XAUDIO2_LOG_ERRORS | api::XE_XAUDIO2_LOG_WARNINGS;
config.BreakMask = 0;
config.LogThreadID = FALSE;
config.LogTiming = TRUE;
config.LogFunctionName = TRUE;
config.LogFileline = TRUE;
audio_->SetDebugConfiguration(&config);
objects.audio->SetDebugConfiguration(&config);
hr = audio_->CreateMasteringVoice(&mastering_voice_);
hr = objects.audio->CreateMasteringVoice(&objects.mastering_voice);
if (FAILED(hr)) {
XELOGE("CreateMasteringVoice failed with %.8X", hr);
XELOGE("IXAudio2::CreateMasteringVoice failed with %.8X", hr);
assert_always();
return false;
}
@ -132,27 +153,38 @@ bool XAudio2AudioDriver::Initialize() {
waveformat.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
waveformat.Samples.wValidBitsPerSample = waveformat.Format.wBitsPerSample;
waveformat.dwChannelMask = ChannelMasks[waveformat.Format.nChannels];
static const DWORD kChannelMasks[] = {
0,
0,
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT,
0,
0,
0,
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT |
SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT,
0,
};
waveformat.dwChannelMask = kChannelMasks[waveformat.Format.nChannels];
hr = audio_->CreateSourceVoice(
&pcm_voice_, &waveformat.Format,
0, // XAUDIO2_VOICE_NOSRC | XAUDIO2_VOICE_NOPITCH,
XAUDIO2_MAX_FREQ_RATIO, voice_callback_);
hr = objects.audio->CreateSourceVoice(
&objects.pcm_voice, &waveformat.Format,
0, // api::XE_XAUDIO2_VOICE_NOSRC | api::XE_XAUDIO2_VOICE_NOPITCH,
api::XE_XAUDIO2_MAX_FREQ_RATIO, voice_callback_);
if (FAILED(hr)) {
XELOGE("CreateSourceVoice failed with %.8X", hr);
XELOGE("IXAudio2::CreateSourceVoice failed with %.8X", hr);
assert_always();
return false;
}
hr = pcm_voice_->Start();
hr = objects.pcm_voice->Start();
if (FAILED(hr)) {
XELOGE("Start failed with %.8X", hr);
XELOGE("IXAudio2SourceVoice::Start failed with %.8X", hr);
assert_always();
return false;
}
if (cvars::mute) {
pcm_voice_->SetVolume(0.0f);
objects.pcm_voice->SetVolume(0.0f);
}
return true;
@ -162,8 +194,13 @@ void XAudio2AudioDriver::SubmitFrame(uint32_t frame_ptr) {
// Process samples! They are big-endian floats.
HRESULT hr;
XAUDIO2_VOICE_STATE state;
pcm_voice_->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
api::XAUDIO2_VOICE_STATE state;
if (api_minor_version_ >= 8) {
objects_.api_2_8.pcm_voice->GetState(&state,
api::XE_XAUDIO2_VOICE_NOSAMPLESPLAYED);
} else {
objects_.api_2_7.pcm_voice->GetState(&state);
}
assert_true(state.BuffersQueued < frame_count_);
auto input_frame = memory_->TranslateVirtual<float*>(frame_ptr);
@ -178,17 +215,21 @@ void XAudio2AudioDriver::SubmitFrame(uint32_t frame_ptr) {
}
}
XAUDIO2_BUFFER buffer;
api::XAUDIO2_BUFFER buffer;
buffer.Flags = 0;
buffer.pAudioData = reinterpret_cast<BYTE*>(output_frame);
buffer.AudioBytes = frame_size_;
buffer.PlayBegin = 0;
buffer.PlayLength = channel_samples_;
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
buffer.LoopBegin = api::XE_XAUDIO2_NO_LOOP_REGION;
buffer.LoopLength = 0;
buffer.LoopCount = 0;
buffer.pContext = 0;
hr = pcm_voice_->SubmitSourceBuffer(&buffer);
if (api_minor_version_ >= 8) {
hr = objects_.api_2_8.pcm_voice->SubmitSourceBuffer(&buffer);
} else {
hr = objects_.api_2_7.pcm_voice->SubmitSourceBuffer(&buffer);
}
if (FAILED(hr)) {
XELOGE("SubmitSourceBuffer failed with %.8X", hr);
assert_always();
@ -199,26 +240,19 @@ void XAudio2AudioDriver::SubmitFrame(uint32_t frame_ptr) {
// Update playback ratio to our time scalar.
// This will keep audio in sync with the game clock.
pcm_voice_->SetFrequencyRatio(
static_cast<float>(xe::Clock::guest_time_scalar()));
float frequency_ratio = static_cast<float>(xe::Clock::guest_time_scalar());
if (api_minor_version_ >= 8) {
objects_.api_2_8.pcm_voice->SetFrequencyRatio(frequency_ratio);
} else {
objects_.api_2_7.pcm_voice->SetFrequencyRatio(frequency_ratio);
}
}
void XAudio2AudioDriver::Shutdown() {
if (pcm_voice_) {
pcm_voice_->Stop();
pcm_voice_->DestroyVoice();
pcm_voice_ = NULL;
}
if (mastering_voice_) {
mastering_voice_->DestroyVoice();
mastering_voice_ = NULL;
}
if (audio_) {
audio_->StopEngine();
audio_->Release();
audio_ = nullptr;
if (api_minor_version_ >= 8) {
ShutdownObjects(objects_.api_2_8);
} else {
ShutdownObjects(objects_.api_2_7);
}
if (xaudio2_module_) {
@ -232,6 +266,26 @@ void XAudio2AudioDriver::Shutdown() {
}
}
template <typename Objects>
void XAudio2AudioDriver::ShutdownObjects(Objects& objects) {
if (objects.pcm_voice) {
objects.pcm_voice->Stop();
objects.pcm_voice->DestroyVoice();
objects.pcm_voice = nullptr;
}
if (objects.mastering_voice) {
objects.mastering_voice->DestroyVoice();
objects.mastering_voice = nullptr;
}
if (objects.audio) {
objects.audio->StopEngine();
objects.audio->Release();
objects.audio = nullptr;
}
}
} // namespace xaudio2
} // namespace apu
} // namespace xe

View File

@ -11,6 +11,7 @@
#define XENIA_APU_XAUDIO2_XAUDIO2_AUDIO_DRIVER_H_
#include "xenia/apu/audio_driver.h"
#include "xenia/apu/xaudio2/xaudio2_api.h"
#include "xenia/base/threading.h"
struct IXAudio2;
@ -31,16 +32,31 @@ class XAudio2AudioDriver : public AudioDriver {
void Shutdown();
private:
template <typename Objects>
bool InitializeObjects(Objects& objects);
template <typename Objects>
void ShutdownObjects(Objects& objects);
void* xaudio2_module_ = nullptr;
IXAudio2* audio_ = nullptr;
IXAudio2MasteringVoice* mastering_voice_ = nullptr;
IXAudio2SourceVoice* pcm_voice_ = nullptr;
uint32_t api_minor_version_ = 7;
union {
struct {
api::IXAudio2_7* audio;
api::IXAudio2_7MasteringVoice* mastering_voice;
api::IXAudio2_7SourceVoice* pcm_voice;
} api_2_7;
struct {
api::IXAudio2_8* audio;
api::IXAudio2_8MasteringVoice* mastering_voice;
api::IXAudio2_8SourceVoice* pcm_voice;
} api_2_8;
} objects_ = {};
xe::threading::Semaphore* semaphore_ = nullptr;
class VoiceCallback;
VoiceCallback* voice_callback_ = nullptr;
static const uint32_t frame_count_ = 64;
static const uint32_t frame_count_ = api::XE_XAUDIO2_MAX_QUEUED_BUFFERS;
static const uint32_t frame_channels_ = 6;
static const uint32_t channel_samples_ = 256;
static const uint32_t frame_samples_ = frame_channels_ * channel_samples_;

View File

@ -9,8 +9,6 @@
#include "xenia/apu/xaudio2/xaudio2_audio_system.h"
#include <xaudio2.h>
#include "xenia/apu/apu_flags.h"
#include "xenia/apu/xaudio2/xaudio2_audio_driver.h"

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -10,50 +10,135 @@
#include "xenia/base/clock.h"
#include <algorithm>
#include <climits>
#include <limits>
#include <mutex>
#include "xenia/base/assert.h"
#include "xenia/base/math.h"
DEFINE_bool(clock_no_scaling, false,
"Disable scaling code. Time management and locking is bypassed. "
"Guest system time is directly pulled from host.",
"CPU");
DEFINE_bool(clock_source_raw, false,
"Use the RDTSC instruction as the time source. "
"Host CPU must support invariant TSC. ",
"CPU");
namespace xe {
// Time scalar applied to all time operations.
double guest_time_scalar_ = 1.0;
// Tick frequency of guest.
uint64_t guest_tick_frequency_ = Clock::host_tick_frequency();
uint64_t guest_tick_frequency_ = Clock::host_tick_frequency_platform();
// Base FILETIME of the guest system from app start.
uint64_t guest_system_time_base_ = Clock::QueryHostSystemTime();
// Combined time and frequency scalar (computed by RecomputeGuestTickScalar).
double guest_tick_scalar_ = 1.0;
// Combined time and frequency ratio between host and guest.
// Split in numerator (first) and denominator (second).
// Computed by RecomputeGuestTickScalar.
std::pair<uint64_t, uint64_t> guest_tick_ratio_ = std::make_pair(1, 1);
// Native guest ticks.
thread_local uint64_t guest_tick_count_ = 0;
// 100ns ticks, relative to guest_system_time_base_.
thread_local uint64_t guest_time_filetime_ = 0;
uint64_t last_guest_tick_count_ = 0;
// Last sampled host tick count.
thread_local uint64_t last_host_tick_count_ = Clock::QueryHostTickCount();
uint64_t last_host_tick_count_ = Clock::QueryHostTickCount();
// Mutex to ensure last_host_tick_count_ and last_guest_tick_count_ are in sync
std::mutex tick_mutex_;
void RecomputeGuestTickScalar() {
guest_tick_scalar_ = (guest_tick_frequency_ * guest_time_scalar_) /
static_cast<double>(Clock::host_tick_frequency());
// Create a rational number with numerator (first) and denominator (second)
auto frac =
std::make_pair(guest_tick_frequency_, Clock::QueryHostTickFrequency());
// Doing it this way ensures we don't mess up our frequency scaling and
// precisely controls the precision the guest_time_scalar_ can have.
if (guest_time_scalar_ > 1.0) {
frac.first *= static_cast<uint64_t>(guest_time_scalar_ * 10.0);
frac.second *= 10;
} else {
frac.first *= 10;
frac.second *= static_cast<uint64_t>(10.0 / guest_time_scalar_);
}
// Keep this a rational calculation and reduce the fraction
reduce_fraction(frac);
std::lock_guard<std::mutex> lock(tick_mutex_);
guest_tick_ratio_ = frac;
}
void UpdateGuestClock() {
// Update the guest timer for all threads.
// Return a copy of the value so locking is reduced.
uint64_t UpdateGuestClock() {
uint64_t host_tick_count = Clock::QueryHostTickCount();
uint64_t host_tick_delta = host_tick_count > last_host_tick_count_
? host_tick_count - last_host_tick_count_
: 0;
last_host_tick_count_ = host_tick_count;
uint64_t guest_tick_delta = uint64_t(host_tick_delta * guest_tick_scalar_);
guest_tick_count_ += guest_tick_delta;
guest_time_filetime_ += (guest_tick_delta * 10000000) / guest_tick_frequency_;
if (cvars::clock_no_scaling) {
// Nothing to update, calculate on the fly
return host_tick_count * guest_tick_ratio_.first / guest_tick_ratio_.second;
}
std::unique_lock<std::mutex> lock(tick_mutex_, std::defer_lock);
if (lock.try_lock()) {
// Translate host tick count to guest tick count.
uint64_t host_tick_delta = host_tick_count > last_host_tick_count_
? host_tick_count - last_host_tick_count_
: 0;
last_host_tick_count_ = host_tick_count;
uint64_t guest_tick_delta =
host_tick_delta * guest_tick_ratio_.first / guest_tick_ratio_.second;
last_guest_tick_count_ += guest_tick_delta;
return last_guest_tick_count_;
} else {
// Wait until another thread has finished updating the clock.
lock.lock();
return last_guest_tick_count_;
}
}
// Offset of the current guest system file time relative to the guest base time.
inline uint64_t QueryGuestSystemTimeOffset() {
if (cvars::clock_no_scaling) {
return Clock::QueryHostSystemTime() - guest_system_time_base_;
}
auto guest_tick_count = UpdateGuestClock();
uint64_t numerator = 10000000; // 100ns/10MHz resolution
uint64_t denominator = guest_tick_frequency_;
reduce_fraction(numerator, denominator);
return guest_tick_count * numerator / denominator;
}
uint64_t Clock::QueryHostTickFrequency() {
if (cvars::clock_source_raw) {
return host_tick_frequency_raw();
} else {
return host_tick_frequency_platform();
}
}
uint64_t Clock::QueryHostTickCount() {
if (cvars::clock_source_raw) {
return host_tick_count_raw();
} else {
return host_tick_count_platform();
}
}
double Clock::guest_time_scalar() { return guest_time_scalar_; }
void Clock::set_guest_time_scalar(double scalar) {
if (cvars::clock_no_scaling) {
return;
}
guest_time_scalar_ = scalar;
RecomputeGuestTickScalar();
}
std::pair<uint64_t, uint64_t> Clock::guest_tick_ratio() {
std::lock_guard<std::mutex> lock(tick_mutex_);
return guest_tick_ratio_;
}
uint64_t Clock::guest_tick_frequency() { return guest_tick_frequency_; }
void Clock::set_guest_tick_frequency(uint64_t frequency) {
@ -68,43 +153,58 @@ void Clock::set_guest_system_time_base(uint64_t time_base) {
}
uint64_t Clock::QueryGuestTickCount() {
UpdateGuestClock();
return guest_tick_count_;
auto guest_tick_count = UpdateGuestClock();
return guest_tick_count;
}
uint64_t Clock::QueryGuestSystemTime() {
UpdateGuestClock();
return guest_system_time_base_ + guest_time_filetime_;
if (cvars::clock_no_scaling) {
return Clock::QueryHostSystemTime();
}
auto guest_system_time_offset = QueryGuestSystemTimeOffset();
return guest_system_time_base_ + guest_system_time_offset;
}
uint32_t Clock::QueryGuestUptimeMillis() {
UpdateGuestClock();
uint64_t uptime_millis = guest_tick_count_ / (guest_tick_frequency_ / 1000);
uint32_t result = uint32_t(std::min(uptime_millis, uint64_t(UINT_MAX)));
return result;
}
void Clock::SetGuestTickCount(uint64_t tick_count) {
last_host_tick_count_ = Clock::QueryHostTickCount();
guest_tick_count_ = tick_count;
return static_cast<uint32_t>(
std::min<uint64_t>(QueryGuestSystemTimeOffset() / 10000,
std::numeric_limits<uint32_t>::max()));
}
void Clock::SetGuestSystemTime(uint64_t system_time) {
last_host_tick_count_ = Clock::QueryHostTickCount();
guest_time_filetime_ = system_time - guest_system_time_base_;
if (cvars::clock_no_scaling) {
// Time is fixed to host time.
return;
}
// Query the filetime offset to calculate a new base time.
auto guest_system_time_offset = QueryGuestSystemTimeOffset();
guest_system_time_base_ = system_time - guest_system_time_offset;
}
uint32_t Clock::ScaleGuestDurationMillis(uint32_t guest_ms) {
if (guest_ms == UINT_MAX) {
return UINT_MAX;
if (cvars::clock_no_scaling) {
return guest_ms;
}
constexpr uint64_t max = std::numeric_limits<uint32_t>::max();
if (guest_ms >= max) {
return max;
} else if (!guest_ms) {
return 0;
}
uint64_t scaled_ms = uint64_t(uint64_t(guest_ms) * guest_time_scalar_);
return uint32_t(std::min(scaled_ms, uint64_t(UINT_MAX)));
uint64_t scaled_ms = static_cast<uint64_t>(
(static_cast<uint64_t>(guest_ms) * guest_time_scalar_));
return static_cast<uint32_t>(std::min(scaled_ms, max));
}
int64_t Clock::ScaleGuestDurationFileTime(int64_t guest_file_time) {
if (cvars::clock_no_scaling) {
return static_cast<uint64_t>(guest_file_time);
}
if (!guest_file_time) {
return 0;
} else if (guest_file_time > 0) {
@ -116,17 +216,23 @@ int64_t Clock::ScaleGuestDurationFileTime(int64_t guest_file_time) {
return static_cast<int64_t>(guest_time) + scaled_time;
} else {
// Relative time.
uint64_t scaled_file_time =
uint64_t(uint64_t(guest_file_time) * guest_time_scalar_);
uint64_t scaled_file_time = static_cast<uint64_t>(
(static_cast<uint64_t>(guest_file_time) * guest_time_scalar_));
// TODO(benvanik): check for overflow?
return scaled_file_time;
}
}
void Clock::ScaleGuestDurationTimeval(int32_t* tv_sec, int32_t* tv_usec) {
uint64_t scaled_sec = uint64_t(uint64_t(*tv_sec) * guest_tick_scalar_);
uint64_t scaled_usec = uint64_t(uint64_t(*tv_usec) * guest_time_scalar_);
if (scaled_usec > UINT_MAX) {
if (cvars::clock_no_scaling) {
return;
}
uint64_t scaled_sec = static_cast<uint64_t>(static_cast<uint64_t>(*tv_sec) *
guest_time_scalar_);
uint64_t scaled_usec = static_cast<uint64_t>(static_cast<uint64_t>(*tv_usec) *
guest_time_scalar_);
if (scaled_usec > std::numeric_limits<uint32_t>::max()) {
uint64_t overflow_sec = scaled_usec / 1000000;
scaled_usec -= overflow_sec * 1000000;
scaled_sec += overflow_sec;

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -12,12 +12,25 @@
#include <cstdint>
#include "xenia/base/cvar.h"
DECLARE_bool(clock_no_scaling);
DECLARE_bool(clock_source_raw);
namespace xe {
class Clock {
public:
// Host ticks-per-second.
static uint64_t host_tick_frequency();
// Host ticks-per-second. Generally QueryHostTickFrequency should be used.
// Either from platform suplied time source or from hardware directly.
static uint64_t host_tick_frequency_platform();
static uint64_t host_tick_frequency_raw();
// Host tick count. Generally QueryHostTickCount() should be used.
static uint64_t host_tick_count_platform();
static uint64_t host_tick_count_raw();
// Queries the host tick frequency.
static uint64_t QueryHostTickFrequency();
// Queries the current host tick count.
static uint64_t QueryHostTickCount();
// Host time, in FILETIME format.
@ -30,6 +43,8 @@ class Clock {
// Sets the guest time scalar, adjusting tick and wall clock speed.
// Ex: 1x=normal, 2x=double speed, 1/2x=half speed.
static void set_guest_time_scalar(double scalar);
// Get the tick ration between host and guest including time scaling if set.
static std::pair<uint64_t, uint64_t> guest_tick_ratio();
// Guest ticks-per-second.
static uint64_t guest_tick_frequency();
// Sets the guest ticks-per-second.
@ -39,6 +54,7 @@ class Clock {
// Sets the guest time base, used for computing the system time.
// By default this is the current system time.
static void set_guest_system_time_base(uint64_t time_base);
// Queries the current guest tick count, accounting for frequency adjustment
// and scaling.
static uint64_t QueryGuestTickCount();
@ -47,9 +63,7 @@ class Clock {
// Queries the milliseconds since the guest began, accounting for scaling.
static uint32_t QueryGuestUptimeMillis();
// Sets the guest tick count for the current thread.
static void SetGuestTickCount(uint64_t tick_count);
// Sets the system time for the current thread.
// Sets the system time of the guest.
static void SetGuestSystemTime(uint64_t system_time);
// Scales a time duration in milliseconds, from guest time.

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2017 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -14,14 +14,14 @@
namespace xe {
uint64_t Clock::host_tick_frequency() {
uint64_t Clock::host_tick_frequency_platform() {
timespec res;
clock_getres(CLOCK_MONOTONIC_RAW, &res);
return uint64_t(res.tv_sec) + uint64_t(res.tv_nsec) * 1000000000ull;
}
uint64_t Clock::QueryHostTickCount() {
uint64_t Clock::host_tick_count_platform() {
timespec res;
clock_gettime(CLOCK_MONOTONIC_RAW, &res);
@ -40,7 +40,7 @@ uint64_t Clock::QueryHostSystemTime() {
}
uint64_t Clock::QueryHostUptimeMillis() {
return QueryHostTickCount() / (host_tick_frequency() / 1000);
return host_tick_count_platform() * 1000 / host_tick_frequency_platform();
}
} // namespace xe

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -13,15 +13,13 @@
namespace xe {
uint64_t Clock::host_tick_frequency() {
static LARGE_INTEGER frequency = {{0}};
if (!frequency.QuadPart) {
QueryPerformanceFrequency(&frequency);
}
uint64_t Clock::host_tick_frequency_platform() {
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
return frequency.QuadPart;
}
uint64_t Clock::QueryHostTickCount() {
uint64_t Clock::host_tick_count_platform() {
LARGE_INTEGER counter;
uint64_t time = 0;
if (QueryPerformanceCounter(&counter)) {
@ -37,7 +35,7 @@ uint64_t Clock::QueryHostSystemTime() {
}
uint64_t Clock::QueryHostUptimeMillis() {
return QueryHostTickCount() / (host_tick_frequency() / 1000);
return host_tick_count_platform() * 1000 / host_tick_frequency_platform();
}
} // namespace xe

105
src/xenia/base/clock_x64.cc Normal file
View File

@ -0,0 +1,105 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/platform.h"
#if XE_ARCH_AMD64
#include "xenia/base/clock.h"
#include "xenia/base/logging.h"
// Wrap all these different cpu compiler intrinsics.
// So no inline assembler here and the compiler will remove the clutter.
#if XE_COMPILER_MSVC
#define xe_cpu_cpuid(level, eax, ebx, ecx, edx) \
{ \
int __xe_cpuid_registers_[4]; \
__cpuid(__xe_cpuid_registers_, (level)); \
(eax) = static_cast<uint32_t>(__xe_cpuid_registers_[0]); \
(ebx) = static_cast<uint32_t>(__xe_cpuid_registers_[1]); \
(ecx) = static_cast<uint32_t>(__xe_cpuid_registers_[2]); \
(edx) = static_cast<uint32_t>(__xe_cpuid_registers_[3]); \
}
#define xe_cpu_rdtsc() __rdtsc()
#elif XE_COMPILER_CLANG || XE_COMPILER_GNUC
#include <cpuid.h>
#define xe_cpu_cpuid(level, eax, ebx, ecx, edx) \
__cpuid((level), (eax), (ebx), (ecx), (edx));
#define xe_cpu_rdtsc() __rdtsc()
#else
#error "No cpu instruction wrappers for current compiler implemented."
#endif
#define CLOCK_FATAL(msg) \
xe::FatalError( \
"The raw clock source is not supported on your CPU. \n" \
"%s \n" \
"Set the cvar 'clock_source_raw' to 'false'.", \
(msg));
namespace xe {
// Getting the TSC frequency can be a bit tricky. This method here only works on
// Intel as it seems. There is no easy way to get the frequency outside of ring0
// on AMD, so we fail gracefully if not possible.
uint64_t Clock::host_tick_frequency_raw() {
uint32_t eax, ebx, ecx, edx;
// 00H Get max supported cpuid level.
xe_cpu_cpuid(0x0, eax, ebx, ecx, edx);
auto max_cpuid = eax;
// 80000000H Get max extended cpuid level
xe_cpu_cpuid(0x80000000, eax, ebx, ecx, edx);
auto max_cpuid_ex = eax;
// 80000007H Get extended power feature info
if (max_cpuid_ex >= 0x80000007) {
xe_cpu_cpuid(0x80000007, eax, ebx, ecx, edx);
// Invariant TSC bit at position 8
auto tsc_invariant = edx & (1 << 8);
// If the TSC is not invariant it will change its frequency with power
// states and across cores.
if (!tsc_invariant) {
CLOCK_FATAL("The CPU has no invariant TSC.");
return 0;
}
} else {
CLOCK_FATAL("Unclear if the CPU has an invariant TSC.")
return 0;
}
if (max_cpuid >= 0x15) {
// 15H Get TSC/Crystal ratio and Crystal Hz.
xe_cpu_cpuid(0x15, eax, ebx, ecx, edx);
uint64_t ratio_num = ebx;
uint64_t ratio_den = eax;
uint64_t cryst_freq = ecx;
// For some CPUs, Crystal frequency is not reported.
if (ratio_num && ratio_den && cryst_freq) {
// If it is, calculate the TSC frequency
auto tsc_freq = cryst_freq * ratio_num / ratio_den;
}
}
if (max_cpuid >= 0x16) {
// 16H Get CPU base frequency MHz in EAX.
xe_cpu_cpuid(0x16, eax, ebx, ecx, edx);
uint64_t cpu_base_freq = static_cast<uint64_t>(eax) * 1000000;
assert(cpu_base_freq);
return cpu_base_freq;
}
CLOCK_FATAL("The clock frequency could not be determined.");
return 0;
}
uint64_t Clock::host_tick_count_raw() { return xe_cpu_rdtsc(); }
} // namespace xe
#endif

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -15,6 +15,7 @@
#include <cstdint>
#include <cstring>
#include <limits>
#include <numeric>
#include <type_traits>
#include "xenia/base/platform.h"
@ -59,6 +60,34 @@ T next_pow2(T value) {
return value;
}
#if __cpp_lib_gcd_lcm
template <typename T>
inline constexpr T greatest_common_divisor(T a, T b) {
return std::gcd(a, b);
}
#else
template <typename T>
constexpr T greatest_common_divisor(T a, T b) {
// Use the Euclid algorithm to calculate the greatest common divisor
while (b) {
a = std::exchange(b, a % b);
}
return a;
}
#endif
template <typename T>
inline constexpr void reduce_fraction(T& numerator, T& denominator) {
auto gcd = greatest_common_divisor(numerator, denominator);
numerator /= gcd;
denominator /= gcd;
}
template <typename T>
inline constexpr void reduce_fraction(std::pair<T, T>& fraction) {
reduce_fraction<T>(fraction.first, fraction.second);
}
constexpr uint32_t make_bitmask(uint32_t a, uint32_t b) {
return (static_cast<uint32_t>(-1) >> (31 - b)) & ~((1u << a) - 1);
}

View File

@ -784,6 +784,7 @@ Xbyak::Address X64Emitter::GetXmmConstPtr(XmmConst id) {
sizeof(vec128_t) * id)];
}
// Implies possible StashXmm(0, ...)!
void X64Emitter::LoadConstantXmm(Xbyak::Xmm dest, const vec128_t& v) {
// https://www.agner.org/optimize/optimizing_assembly.pdf
// 13.4 Generating constants
@ -846,6 +847,35 @@ Xbyak::Address X64Emitter::StashXmm(int index, const Xbyak::Xmm& r) {
return addr;
}
Xbyak::Address X64Emitter::StashConstantXmm(int index, float v) {
union {
float f;
uint32_t i;
} x = {v};
auto addr = rsp + kStashOffset + (index * 16);
MovMem64(addr, x.i);
MovMem64(addr + 8, 0);
return ptr[addr];
}
Xbyak::Address X64Emitter::StashConstantXmm(int index, double v) {
union {
double d;
uint64_t i;
} x = {v};
auto addr = rsp + kStashOffset + (index * 16);
MovMem64(addr, x.i);
MovMem64(addr + 8, 0);
return ptr[addr];
}
Xbyak::Address X64Emitter::StashConstantXmm(int index, const vec128_t& v) {
auto addr = rsp + kStashOffset + (index * 16);
MovMem64(addr, v.low);
MovMem64(addr + 8, v.high);
return ptr[addr];
}
} // namespace x64
} // namespace backend
} // namespace cpu

View File

@ -214,6 +214,9 @@ class X64Emitter : public Xbyak::CodeGenerator {
void LoadConstantXmm(Xbyak::Xmm dest, double v);
void LoadConstantXmm(Xbyak::Xmm dest, const vec128_t& v);
Xbyak::Address StashXmm(int index, const Xbyak::Xmm& r);
Xbyak::Address StashConstantXmm(int index, float v);
Xbyak::Address StashConstantXmm(int index, double v);
Xbyak::Address StashConstantXmm(int index, const vec128_t& v);
bool IsFeatureEnabled(uint32_t feature_flag) const {
return (feature_flags_ & feature_flag) != 0;

View File

@ -709,8 +709,7 @@ struct VECTOR_SHL_V128
static void EmitInt8(X64Emitter& e, const EmitArgType& i) {
// TODO(benvanik): native version (with shift magic).
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -767,8 +766,7 @@ struct VECTOR_SHL_V128
// TODO(benvanik): native version (with shift magic).
e.L(emu);
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -844,8 +842,7 @@ struct VECTOR_SHL_V128
// TODO(benvanik): native version (with shift magic).
e.L(emu);
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -901,8 +898,7 @@ struct VECTOR_SHR_V128
static void EmitInt8(X64Emitter& e, const EmitArgType& i) {
// TODO(benvanik): native version (with shift magic).
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -951,8 +947,7 @@ struct VECTOR_SHR_V128
// TODO(benvanik): native version (with shift magic).
e.L(emu);
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -1028,8 +1023,7 @@ struct VECTOR_SHR_V128
// TODO(benvanik): native version.
e.L(emu);
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -1068,8 +1062,7 @@ struct VECTOR_SHA_V128
static void EmitInt8(X64Emitter& e, const EmitArgType& i) {
// TODO(benvanik): native version (with shift magic).
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -1118,8 +1111,7 @@ struct VECTOR_SHA_V128
// TODO(benvanik): native version (with shift magic).
e.L(emu);
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -1180,8 +1172,7 @@ struct VECTOR_SHA_V128
// TODO(benvanik): native version.
e.L(emu);
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -1223,26 +1214,24 @@ struct VECTOR_ROTATE_LEFT_V128
switch (i.instr->flags) {
case INT8_TYPE:
// TODO(benvanik): native version (with shift magic).
e.lea(e.GetNativeParam(0), e.StashXmm(0, i.src1));
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
e.lea(e.GetNativeParam(0), e.StashXmm(0, i.src1));
e.CallNativeSafe(
reinterpret_cast<void*>(EmulateVectorRotateLeft<uint8_t>));
e.vmovaps(i.dest, e.xmm0);
break;
case INT16_TYPE:
// TODO(benvanik): native version (with shift magic).
e.lea(e.GetNativeParam(0), e.StashXmm(0, i.src1));
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1), e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
e.lea(e.GetNativeParam(0), e.StashXmm(0, i.src1));
e.CallNativeSafe(
reinterpret_cast<void*>(EmulateVectorRotateLeft<uint16_t>));
e.vmovaps(i.dest, e.xmm0);
@ -1254,7 +1243,12 @@ struct VECTOR_ROTATE_LEFT_V128
temp = e.xmm2;
}
// Shift left (to get high bits):
e.vpand(e.xmm0, i.src2, e.GetXmmConstPtr(XMMShiftMaskPS));
if (i.src2.is_constant) {
e.LoadConstantXmm(temp, i.src2.constant());
e.vpand(e.xmm0, temp, e.GetXmmConstPtr(XMMShiftMaskPS));
} else {
e.vpand(e.xmm0, i.src2, e.GetXmmConstPtr(XMMShiftMaskPS));
}
e.vpsllvd(e.xmm1, i.src1, e.xmm0);
// Shift right (to get low bits):
e.vmovaps(temp, e.GetXmmConstPtr(XMMPI32));
@ -1264,13 +1258,13 @@ struct VECTOR_ROTATE_LEFT_V128
e.vpor(i.dest, e.xmm1);
} else {
// TODO(benvanik): non-AVX2 native version.
e.lea(e.GetNativeParam(0), e.StashXmm(0, i.src1));
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1),
e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
e.lea(e.GetNativeParam(0), e.StashXmm(0, i.src1));
e.CallNativeSafe(
reinterpret_cast<void*>(EmulateVectorRotateLeft<uint32_t>));
e.vmovaps(i.dest, e.xmm0);
@ -1337,8 +1331,8 @@ struct VECTOR_AVERAGE
// No 32bit averages in AVX.
if (is_unsigned) {
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1),
e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -1348,8 +1342,8 @@ struct VECTOR_AVERAGE
e.vmovaps(i.dest, e.xmm0);
} else {
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1),
e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -1874,8 +1868,8 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
// http://blogs.msdn.com/b/chuckw/archive/2012/09/11/directxmath-f16c-and-fma.aspx
// dest = [(src1.x | src1.y), 0, 0, 0]
Xmm src;
if (e.IsFeatureEnabled(kX64EmitF16C)) {
Xmm src;
if (i.src1.is_constant) {
src = i.dest;
e.LoadConstantXmm(src, i.src1.constant());
@ -1888,12 +1882,10 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
e.vpshufb(i.dest, i.dest, e.GetXmmConstPtr(XMMPackFLOAT16_2));
} else {
if (i.src1.is_constant) {
src = e.xmm0;
e.LoadConstantXmm(src, i.src1.constant());
e.lea(e.GetNativeParam(0), e.StashConstantXmm(0, i.src1.constant()));
} else {
src = i.src1;
e.lea(e.GetNativeParam(0), e.StashXmm(0, i.src1));
}
e.lea(e.GetNativeParam(0), e.StashXmm(0, src));
e.CallNativeSafe(reinterpret_cast<void*>(EmulateFLOAT16_2));
e.vmovaps(i.dest, e.xmm0);
}
@ -1915,8 +1907,8 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
assert_true(i.src2.value->IsConstantZero());
// dest = [(src1.z | src1.w), (src1.x | src1.y), 0, 0]
Xmm src;
if (e.IsFeatureEnabled(kX64EmitF16C)) {
Xmm src;
if (i.src1.is_constant) {
src = i.dest;
e.LoadConstantXmm(src, i.src1.constant());
@ -1929,12 +1921,10 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
e.vpshufb(i.dest, i.dest, e.GetXmmConstPtr(XMMPackFLOAT16_4));
} else {
if (i.src1.is_constant) {
src = e.xmm0;
e.LoadConstantXmm(src, i.src1.constant());
e.lea(e.GetNativeParam(0), e.StashConstantXmm(0, i.src1.constant()));
} else {
src = i.src1;
e.lea(e.GetNativeParam(0), e.StashXmm(0, i.src1));
}
e.lea(e.GetNativeParam(0), e.StashXmm(0, src));
e.CallNativeSafe(reinterpret_cast<void*>(EmulateFLOAT16_4));
e.vmovaps(i.dest, e.xmm0);
}
@ -2063,8 +2053,8 @@ struct PACK : Sequence<PACK, I<OPCODE_PACK, V128Op, V128Op, V128Op>> {
if (IsPackOutSaturate(flags)) {
// unsigned -> unsigned + saturate
if (i.src2.is_constant) {
e.LoadConstantXmm(e.xmm0, i.src2.constant());
e.lea(e.GetNativeParam(1), e.StashXmm(1, e.xmm0));
e.lea(e.GetNativeParam(1),
e.StashConstantXmm(1, i.src2.constant()));
} else {
e.lea(e.GetNativeParam(1), e.StashXmm(1, i.src2));
}
@ -2305,8 +2295,8 @@ struct UNPACK : Sequence<UNPACK, I<OPCODE_UNPACK, V128Op, V128Op>> {
// Also zero out the high end.
// TODO(benvanik): special case constant unpacks that just get 0/1/etc.
Xmm src;
if (e.IsFeatureEnabled(kX64EmitF16C)) {
Xmm src;
if (i.src1.is_constant) {
src = i.dest;
e.LoadConstantXmm(src, i.src1.constant());
@ -2326,12 +2316,10 @@ struct UNPACK : Sequence<UNPACK, I<OPCODE_UNPACK, V128Op, V128Op>> {
e.vpor(i.dest, e.GetXmmConstPtr(XMM0001));
} else {
if (i.src1.is_constant) {
src = e.xmm0;
e.LoadConstantXmm(src, i.src1.constant());
e.lea(e.GetNativeParam(0), e.StashConstantXmm(0, i.src1.constant()));
} else {
src = i.src1;
e.lea(e.GetNativeParam(0), e.StashXmm(0, i.src1));
}
e.lea(e.GetNativeParam(0), e.StashXmm(0, src));
e.CallNativeSafe(reinterpret_cast<void*>(EmulateFLOAT16_2));
e.vmovaps(i.dest, e.xmm0);
}
@ -2349,8 +2337,8 @@ struct UNPACK : Sequence<UNPACK, I<OPCODE_UNPACK, V128Op, V128Op>> {
}
static void EmitFLOAT16_4(X64Emitter& e, const EmitArgType& i) {
// src = [(dest.x | dest.y), (dest.z | dest.w), 0, 0]
Xmm src;
if (e.IsFeatureEnabled(kX64EmitF16C)) {
Xmm src;
if (i.src1.is_constant) {
src = i.dest;
e.LoadConstantXmm(src, i.src1.constant());
@ -2362,12 +2350,10 @@ struct UNPACK : Sequence<UNPACK, I<OPCODE_UNPACK, V128Op, V128Op>> {
e.vcvtph2ps(i.dest, i.dest);
} else {
if (i.src1.is_constant) {
src = e.xmm0;
e.LoadConstantXmm(src, i.src1.constant());
e.lea(e.GetNativeParam(0), e.StashConstantXmm(0, i.src1.constant()));
} else {
src = i.src1;
e.lea(e.GetNativeParam(0), e.StashXmm(0, i.src1));
}
e.lea(e.GetNativeParam(0), e.StashXmm(0, src));
e.CallNativeSafe(reinterpret_cast<void*>(EmulateFLOAT16_4));
e.vmovaps(i.dest, e.xmm0);
}

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -440,9 +440,34 @@ EMITTER_OPCODE_TABLE(OPCODE_ROUND, ROUND_F32, ROUND_F64, ROUND_V128);
// ============================================================================
struct LOAD_CLOCK : Sequence<LOAD_CLOCK, I<OPCODE_LOAD_CLOCK, I64Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
// It'd be cool to call QueryPerformanceCounter directly, but w/e.
e.CallNative(LoadClock);
e.mov(i.dest, e.rax);
// When scaling is disabled and the raw clock source is selected, the code
// in the Clock class is actually just forwarding tick counts after one
// simple multiply and division. In that case we rather bake the scaling in
// here to cut extra function calls with CPU cache misses and stack frame
// overhead.
if (cvars::clock_no_scaling && cvars::clock_source_raw) {
auto ratio = Clock::guest_tick_ratio();
// The 360 CPU is an in-order CPU, AMD64 usually isn't. Without
// mfence/lfence magic the rdtsc instruction can be executed sooner or
// later in the cache window. Since it's resolution however is much higher
// than the 360's mftb instruction this can safely be ignored.
// Read time stamp in edx (high part) and eax (low part).
e.rdtsc();
// Make it a 64 bit number in rax.
e.shl(e.rdx, 32);
e.or_(e.rax, e.rdx);
// Apply tick frequency scaling.
e.mov(e.rcx, ratio.first);
e.mul(e.rcx);
// We actually now have a 128 bit number in rdx:rax.
e.mov(e.rcx, ratio.second);
e.div(e.rcx);
e.mov(i.dest, e.rax);
} else {
e.CallNative(LoadClock);
e.mov(i.dest, e.rax);
}
}
static uint64_t LoadClock(void* raw_context) {
return Clock::QueryGuestTickCount();

View File

@ -103,10 +103,9 @@ bool XexModule::GetOptHeader(xex2_header_keys key, void** out_ptr) const {
return XexModule::GetOptHeader(xex_header(), key, out_ptr);
}
const xex2_security_info* XexModule::GetSecurityInfo(
const xex2_header* header) {
return reinterpret_cast<const xex2_security_info*>(uintptr_t(header) +
header->security_offset);
const void* XexModule::GetSecurityInfo(const xex2_header* header) {
return reinterpret_cast<const void*>(uintptr_t(header) +
header->security_offset);
}
const PESection* XexModule::GetPESection(const char* name) {
@ -870,7 +869,11 @@ bool XexModule::Load(const std::string& name, const std::string& path,
const void* xex_addr, size_t xex_length) {
auto src_header = reinterpret_cast<const xex2_header*>(xex_addr);
if (src_header->magic != 'XEX2') {
if (src_header->magic == 'XEX1') {
xex_format_ = kFormatXex1;
} else if (src_header->magic == 'XEX2') {
xex_format_ = kFormatXex2;
} else {
return false;
}
@ -881,6 +884,34 @@ bool XexModule::Load(const std::string& name, const std::string& path,
xex_header_mem_.resize(src_header->header_size);
std::memcpy(xex_header_mem_.data(), src_header, src_header->header_size);
if (xex_format_ == kFormatXex1) {
const xex1_security_info* xex1_sec_info =
reinterpret_cast<const xex1_security_info*>(
GetSecurityInfo(xex_header()));
security_info_.rsa_signature = xex1_sec_info->rsa_signature;
security_info_.aes_key = xex1_sec_info->aes_key;
security_info_.image_size = xex1_sec_info->image_size;
security_info_.image_flags = xex1_sec_info->image_flags;
security_info_.export_table = xex1_sec_info->export_table;
security_info_.load_address = xex1_sec_info->load_address;
security_info_.page_descriptor_count = xex1_sec_info->page_descriptor_count;
security_info_.page_descriptors = xex1_sec_info->page_descriptors;
} else if (xex_format_ == kFormatXex2) {
const xex2_security_info* xex2_sec_info =
reinterpret_cast<const xex2_security_info*>(
GetSecurityInfo(xex_header()));
security_info_.rsa_signature = xex2_sec_info->rsa_signature;
security_info_.aes_key = xex2_sec_info->aes_key;
security_info_.image_size = xex2_sec_info->image_size;
security_info_.image_flags = xex2_sec_info->image_flags;
security_info_.export_table = xex2_sec_info->export_table;
security_info_.load_address = xex2_sec_info->load_address;
security_info_.page_descriptor_count = xex2_sec_info->page_descriptor_count;
security_info_.page_descriptors = xex2_sec_info->page_descriptors;
}
auto sec_header = xex_security_info();
// Try setting our base_address based on XEX_HEADER_IMAGE_BASE_ADDRESS, fall

View File

@ -43,6 +43,21 @@ class XexModule : public xe::cpu::Module {
xe_xex2_version_t min_version;
std::vector<ImportLibraryFn> imports;
};
struct SecurityInfoContext {
const char* rsa_signature;
const char* aes_key;
uint32_t image_size;
uint32_t image_flags;
uint32_t export_table;
uint32_t load_address;
uint32_t page_descriptor_count;
const xex2_page_descriptor* page_descriptors;
};
enum XexFormat {
kFormatUnknown,
kFormatXex1,
kFormatXex2,
};
XexModule(Processor* processor, kernel::KernelState* kernel_state);
virtual ~XexModule();
@ -51,8 +66,8 @@ class XexModule : public xe::cpu::Module {
const xex2_header* xex_header() const {
return reinterpret_cast<const xex2_header*>(xex_header_mem_.data());
}
const xex2_security_info* xex_security_info() const {
return GetSecurityInfo(xex_header());
const SecurityInfoContext* xex_security_info() const {
return &security_info_;
}
uint32_t image_size() const {
@ -112,7 +127,7 @@ class XexModule : public xe::cpu::Module {
return GetOptHeader(key, reinterpret_cast<void**>(out_ptr));
}
static const xex2_security_info* GetSecurityInfo(const xex2_header* header);
static const void* GetSecurityInfo(const xex2_header* header);
const PESection* GetPESection(const char* name);
@ -186,6 +201,9 @@ class XexModule : public xe::cpu::Module {
uint32_t base_address_ = 0;
uint32_t low_address_ = 0;
uint32_t high_address_ = 0;
XexFormat xex_format_ = kFormatUnknown;
SecurityInfoContext security_info_ = {};
};
} // namespace cpu

View File

@ -140,7 +140,7 @@ void DebugWindow::DrawFrame() {
float top_panes_height =
ImGui::GetContentRegionAvail().y - bottom_panes_height;
float log_pane_width =
ImGui::GetContentRegionAvailWidth() - breakpoints_pane_width;
ImGui::GetContentRegionAvail().x - breakpoints_pane_width;
ImGui::BeginChild("##toolbar", ImVec2(0, 25), true);
DrawToolbar();
@ -237,12 +237,10 @@ void DebugWindow::DrawFrame() {
ImGui::PopStyleVar();
if (cvars::imgui_debug) {
ImGui::ShowTestWindow();
ImGui::ShowDemoWindow();
ImGui::ShowMetricsWindow();
}
ImGui::Render();
// Continuous paint.
window_->Invalidate();
}
@ -321,7 +319,7 @@ void DebugWindow::DrawSourcePane() {
// address start - end
// name text box (editable)
// combo for interleaved + [ppc, hir, opt hir, x64 + byte with sizes]
ImGui::AlignFirstTextHeightToWidgets();
ImGui::AlignTextToFramePadding();
ImGui::Text("%s", function->module()->name().c_str());
ImGui::SameLine();
ImGui::Dummy(ImVec2(4, 0));
@ -340,7 +338,7 @@ void DebugWindow::DrawSourcePane() {
ImGui::SameLine();
char name[256];
std::strcpy(name, function->name().c_str());
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() - 10);
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - 10);
if (ImGui::InputText("##name", name, sizeof(name),
ImGuiInputTextFlags_AutoSelectAll)) {
function->set_name(name);
@ -623,7 +621,7 @@ void DebugWindow::DrawBreakpointGutterButton(
void DebugWindow::ScrollToSourceIfPcChanged() {
if (state_.has_changed_pc) {
// TODO(benvanik): not so annoying scroll.
ImGui::SetScrollHere();
ImGui::SetScrollHereY(0.5f);
state_.has_changed_pc = false;
}
}
@ -868,7 +866,7 @@ void DebugWindow::DrawRegistersPane() {
}
ImGui::BeginChild("##guest_general");
ImGui::BeginGroup();
ImGui::AlignFirstTextHeightToWidgets();
ImGui::AlignTextToFramePadding();
ImGui::Text(" lr");
ImGui::SameLine();
ImGui::Dummy(ImVec2(4, 0));
@ -877,7 +875,7 @@ void DebugWindow::DrawRegistersPane() {
DrawRegisterTextBox(100, &thread_info->guest_context.lr);
ImGui::EndGroup();
ImGui::BeginGroup();
ImGui::AlignFirstTextHeightToWidgets();
ImGui::AlignTextToFramePadding();
ImGui::Text("ctr");
ImGui::SameLine();
ImGui::Dummy(ImVec2(4, 0));
@ -891,7 +889,7 @@ void DebugWindow::DrawRegistersPane() {
// VSCR
for (int i = 0; i < 32; ++i) {
ImGui::BeginGroup();
ImGui::AlignFirstTextHeightToWidgets();
ImGui::AlignTextToFramePadding();
ImGui::Text(i < 10 ? " r%d" : "r%d", i);
ImGui::SameLine();
ImGui::Dummy(ImVec2(4, 0));
@ -909,7 +907,7 @@ void DebugWindow::DrawRegistersPane() {
ImGui::BeginChild("##guest_float");
for (int i = 0; i < 32; ++i) {
ImGui::BeginGroup();
ImGui::AlignFirstTextHeightToWidgets();
ImGui::AlignTextToFramePadding();
ImGui::Text(i < 10 ? " f%d" : "f%d", i);
ImGui::SameLine();
ImGui::Dummy(ImVec2(4, 0));
@ -927,7 +925,7 @@ void DebugWindow::DrawRegistersPane() {
ImGui::BeginChild("##guest_vector");
for (int i = 0; i < 128; ++i) {
ImGui::BeginGroup();
ImGui::AlignFirstTextHeightToWidgets();
ImGui::AlignTextToFramePadding();
ImGui::Text(i < 10 ? " v%d" : (i < 100 ? " v%d" : "v%d"), i);
ImGui::SameLine();
ImGui::Dummy(ImVec2(4, 0));
@ -943,7 +941,7 @@ void DebugWindow::DrawRegistersPane() {
for (int i = 0; i < 18; ++i) {
auto reg = static_cast<X64Register>(i);
ImGui::BeginGroup();
ImGui::AlignFirstTextHeightToWidgets();
ImGui::AlignTextToFramePadding();
ImGui::Text("%3s", X64Context::GetRegisterName(reg));
ImGui::SameLine();
ImGui::Dummy(ImVec2(4, 0));
@ -968,7 +966,7 @@ void DebugWindow::DrawRegistersPane() {
auto reg =
static_cast<X64Register>(static_cast<int>(X64Register::kXmm0) + i);
ImGui::BeginGroup();
ImGui::AlignFirstTextHeightToWidgets();
ImGui::AlignTextToFramePadding();
ImGui::Text("%5s", X64Context::GetRegisterName(reg));
ImGui::SameLine();
ImGui::Dummy(ImVec2(4, 0));
@ -1006,7 +1004,7 @@ void DebugWindow::DrawThreadsPane() {
continue;
}
if (is_current_thread && state_.has_changed_thread) {
ImGui::SetScrollHere();
ImGui::SetScrollHereY(0.5f);
state_.has_changed_thread = false;
}
if (!is_current_thread) {
@ -1017,7 +1015,7 @@ void DebugWindow::DrawThreadsPane() {
}
ImGui::PushID(thread_info);
if (is_current_thread) {
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Always);
ImGui::SetNextItemOpen(true, ImGuiCond_Always);
}
const char* state_label = "?";
if (thread->can_debugger_suspend()) {
@ -1037,8 +1035,9 @@ void DebugWindow::DrawThreadsPane() {
thread->is_guest_thread() ? "guest" : "host", state_label,
thread->thread_id(), thread->handle(),
thread->name().c_str());
if (ImGui::CollapsingHeader(thread_label, nullptr, true,
is_current_thread)) {
if (ImGui::CollapsingHeader(
thread_label,
is_current_thread ? ImGuiTreeNodeFlags_DefaultOpen : 0)) {
// | (log button) detail of kernel call categories
// log button toggles only logging that thread
ImGui::BulletText("Call Stack");
@ -1133,7 +1132,7 @@ void DebugWindow::DrawBreakpointsPane() {
if (ImGui::BeginPopup("##add_code_breakpoint")) {
++add_code_popup_render_count;
ImGui::AlignFirstTextHeightToWidgets();
ImGui::AlignTextToFramePadding();
ImGui::Text("PPC");
ImGui::SameLine();
ImGui::Dummy(ImVec2(2, 0));
@ -1158,7 +1157,7 @@ void DebugWindow::DrawBreakpointsPane() {
ImGui::PopItemWidth();
ImGui::Dummy(ImVec2(0, 2));
ImGui::AlignFirstTextHeightToWidgets();
ImGui::AlignTextToFramePadding();
ImGui::Text("x64");
ImGui::SameLine();
ImGui::Dummy(ImVec2(2, 0));

View File

@ -136,6 +136,8 @@ class CommandProcessor {
virtual void TracePlaybackWroteMemory(uint32_t base_ptr, uint32_t length) = 0;
virtual void RestoreEDRAMSnapshot(const void* snapshot) = 0;
void InitializeRingBuffer(uint32_t ptr, uint32_t page_count);
void EnableReadPointerWriteBack(uint32_t ptr, uint32_t block_size);

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,6 @@
#include "xenia/gpu/dxbc_shader_translator.h"
#include "xenia/gpu/xenos.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/ui/d3d12/command_list.h"
#include "xenia/ui/d3d12/d3d12_context.h"
#include "xenia/ui/d3d12/pools.h"
@ -48,12 +47,15 @@ class D3D12CommandProcessor : public CommandProcessor {
void TracePlaybackWroteMemory(uint32_t base_ptr, uint32_t length) override;
void RestoreEDRAMSnapshot(const void* snapshot) override;
// Needed by everything that owns transient objects.
xe::ui::d3d12::D3D12Context* GetD3D12Context() const {
return static_cast<xe::ui::d3d12::D3D12Context*>(context_.get());
}
// Returns the deferred drawing command list for the currently open frame.
// Returns the deferred drawing command list for the currently open
// submission.
DeferredCommandList* GetDeferredCommandList() {
return deferred_command_list_.get();
}
@ -63,6 +65,12 @@ class D3D12CommandProcessor : public CommandProcessor {
// targets.
bool IsROVUsedForEDRAM() const;
uint64_t GetCurrentSubmission() const { return submission_current_; }
uint64_t GetCompletedSubmission() const { return submission_completed_; }
uint64_t GetCurrentFrame() const { return frame_current_; }
uint64_t GetCompletedFrame() const { return frame_completed_; }
// Gets the current color write mask, taking the pixel shader's write mask
// into account. If a shader doesn't write to a render target, it shouldn't be
// written to and it shouldn't be even bound - otherwise, in Halo 3, one
@ -92,19 +100,19 @@ class D3D12CommandProcessor : public CommandProcessor {
}
// Request and automatically rebind descriptors on the draw command list.
// Refer to DescriptorHeapPool::Request for partial/full update explanation.
uint64_t RequestViewDescriptors(uint64_t previous_full_update,
uint64_t RequestViewDescriptors(uint64_t previous_heap_index,
uint32_t count_for_partial_update,
uint32_t count_for_full_update,
D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out,
D3D12_GPU_DESCRIPTOR_HANDLE& gpu_handle_out);
uint64_t RequestSamplerDescriptors(
uint64_t previous_full_update, uint32_t count_for_partial_update,
uint64_t previous_heap_index, uint32_t count_for_partial_update,
uint32_t count_for_full_update,
D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out,
D3D12_GPU_DESCRIPTOR_HANDLE& gpu_handle_out);
// Returns a single temporary GPU-side buffer within a frame for tasks like
// texture untiling and resolving.
// Returns a single temporary GPU-side buffer within a submission for tasks
// like texture untiling and resolving.
ID3D12Resource* RequestScratchGPUBuffer(uint32_t size,
D3D12_RESOURCE_STATES state);
// This must be called when done with the scratch buffer, to notify the
@ -124,22 +132,23 @@ class D3D12CommandProcessor : public CommandProcessor {
}
// Sets the current pipeline state to a compute pipeline. This is for cache
// invalidation primarily. A frame must be open.
// invalidation primarily. A submission must be open.
void SetComputePipeline(ID3D12PipelineState* pipeline);
// Stores and unbinds render targets before binding changing render targets
// externally. This is separate from SetExternalGraphicsPipeline because it
// causes computations to be dispatched, and the scratch buffer may also be
// used.
void UnbindRenderTargets();
void FlushAndUnbindRenderTargets();
// Sets the current pipeline state to a special drawing pipeline, invalidating
// various cached state variables. UnbindRenderTargets may be needed before
// calling this. A frame must be open.
void SetExternalGraphicsPipeline(ID3D12PipelineState* pipeline,
bool reset_viewport = true,
bool reset_blend_factor = false,
bool reset_stencil_ref = false);
// various cached state variables. FlushAndUnbindRenderTargets may be needed
// before calling this. A submission must be open.
void SetExternalGraphicsPipeline(
ID3D12PipelineState* pipeline,
bool changing_rts_and_sample_positions = true,
bool changing_viewport = true, bool changing_blend_factor = false,
bool changing_stencil_ref = false);
// Returns the text to display in the GPU backend name in the window title.
std::wstring GetWindowTitleText() const;
@ -167,6 +176,8 @@ class D3D12CommandProcessor : public CommandProcessor {
void FinalizeTrace() override;
private:
static constexpr uint32_t kQueueFrames = 3;
enum RootParameter : UINT {
// These are always present.
@ -211,10 +222,22 @@ class D3D12CommandProcessor : public CommandProcessor {
const D3D12Shader* vertex_shader, const D3D12Shader* pixel_shader,
RootExtraParameterIndices& indices_out);
// Returns true if a new frame was started.
bool BeginFrame();
// Returns true if an open frame was ended.
bool EndFrame();
// BeginSubmission and EndSubmission may be called at any time. If there's an
// open non-frame submission, BeginSubmission(true) will promote it to a
// frame. EndSubmission(true) will close the frame no matter whether the
// submission has already been closed.
// If is_guest_command is true, a new full frame - with full cleanup of
// resources and, if needed, starting capturing - is opened if pending (as
// opposed to simply resuming after mid-frame synchronization).
void BeginSubmission(bool is_guest_command);
// If is_swap is true, a full frame is closed - with, if needed, cache
// clearing and stopping capturing. Returns whether the submission was done
// successfully, if it has failed, leaves it open.
bool EndSubmission(bool is_swap);
void AwaitAllSubmissionsCompletion();
// Need to await submission completion before calling.
void ClearCommandAllocatorCache();
void UpdateFixedFunctionState(bool primitive_two_faced);
void UpdateSystemConstantValues(
@ -239,8 +262,32 @@ class D3D12CommandProcessor : public CommandProcessor {
bool cache_clear_requested_ = false;
std::unique_ptr<ui::d3d12::CommandList>
command_lists_[ui::d3d12::D3D12Context::kQueuedFrames] = {};
bool submission_open_ = false;
// Values of submission_fence_.
uint64_t submission_current_ = 1;
uint64_t submission_completed_ = 0;
HANDLE submission_fence_completion_event_ = nullptr;
ID3D12Fence* submission_fence_ = nullptr;
bool frame_open_ = false;
// Guest frame index, since some transient resources can be reused across
// submissions. Values updated in the beginning of a frame.
uint64_t frame_current_ = 1;
uint64_t frame_completed_ = 0;
// Submission indices of frames that have already been submitted.
uint64_t closed_frame_submissions_[kQueueFrames] = {};
struct CommandAllocator {
ID3D12CommandAllocator* command_allocator;
uint64_t last_usage_submission;
CommandAllocator* next;
};
CommandAllocator* command_allocator_writable_first_ = nullptr;
CommandAllocator* command_allocator_writable_last_ = nullptr;
CommandAllocator* command_allocator_submitted_first_ = nullptr;
CommandAllocator* command_allocator_submitted_last_ = nullptr;
ID3D12GraphicsCommandList* command_list_ = nullptr;
ID3D12GraphicsCommandList1* command_list_1_ = nullptr;
std::unique_ptr<DeferredCommandList> deferred_command_list_ = nullptr;
std::unique_ptr<SharedMemory> shared_memory_ = nullptr;
@ -265,11 +312,10 @@ class D3D12CommandProcessor : public CommandProcessor {
ID3D12Resource* gamma_ramp_texture_ = nullptr;
D3D12_RESOURCE_STATES gamma_ramp_texture_state_;
// Upload buffer for an image that is the same as gamma_ramp_, but with
// ui::d3d12::D3D12Context::kQueuedFrames array layers.
// kQueueFrames array layers.
ID3D12Resource* gamma_ramp_upload_ = nullptr;
uint8_t* gamma_ramp_upload_mapping_ = nullptr;
D3D12_PLACED_SUBRESOURCE_FOOTPRINT
gamma_ramp_footprints_[ui::d3d12::D3D12Context::kQueuedFrames * 2];
D3D12_PLACED_SUBRESOURCE_FOOTPRINT gamma_ramp_footprints_[kQueueFrames * 2];
static constexpr uint32_t kSwapTextureWidth = 1280;
static constexpr uint32_t kSwapTextureHeight = 720;
@ -291,7 +337,7 @@ class D3D12CommandProcessor : public CommandProcessor {
struct BufferForDeletion {
ID3D12Resource* buffer;
uint64_t last_usage_frame;
uint64_t last_usage_submission;
};
std::deque<BufferForDeletion> buffers_for_deletion_;
@ -305,8 +351,6 @@ class D3D12CommandProcessor : public CommandProcessor {
ID3D12Resource* readback_buffer_ = nullptr;
uint32_t readback_buffer_size_ = 0;
uint32_t current_queue_frame_ = UINT32_MAX;
std::atomic<bool> pix_capture_requested_ = false;
bool pix_capturing_;
@ -362,8 +406,8 @@ class D3D12CommandProcessor : public CommandProcessor {
ConstantBufferBinding cbuffer_bindings_fetch_;
// Pages with the descriptors currently used for handling Xenos draw calls.
uint64_t draw_view_full_update_;
uint64_t draw_sampler_full_update_;
uint64_t draw_view_heap_index_;
uint64_t draw_sampler_heap_index_;
// Whether the last used texture bindings have been written to the current
// view descriptor heap.

View File

@ -199,12 +199,6 @@ std::unique_ptr<xe::ui::RawImage> D3D12GraphicsSystem::Capture() {
return d3d12_command_processor->Capture();
}
void D3D12GraphicsSystem::AwaitFrontBufferUnused() {
if (display_context_ != nullptr) {
display_context_->AwaitAllFramesCompletion();
}
}
void D3D12GraphicsSystem::StretchTextureToFrontBuffer(
D3D12_GPU_DESCRIPTOR_HANDLE handle,
D3D12_GPU_DESCRIPTOR_HANDLE* gamma_ramp_handle, float gamma_ramp_inv_size,

View File

@ -36,8 +36,6 @@ class D3D12GraphicsSystem : public GraphicsSystem {
std::unique_ptr<xe::ui::RawImage> Capture() override;
void AwaitFrontBufferUnused();
// Draws a texture covering the entire viewport to the render target currently
// bound on the specified command list (in D3D12Context::kSwapChainFormat).
// This changes the current pipeline, graphics root signature and primitive

View File

@ -0,0 +1,61 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/logging.h"
#include "xenia/base/main.h"
#include "xenia/gpu/d3d12/d3d12_command_processor.h"
#include "xenia/gpu/d3d12/d3d12_graphics_system.h"
#include "xenia/gpu/trace_viewer.h"
namespace xe {
namespace gpu {
namespace d3d12 {
using namespace xe::gpu::xenos;
class D3D12TraceViewer : public TraceViewer {
public:
std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() override {
return std::unique_ptr<gpu::GraphicsSystem>(new D3D12GraphicsSystem());
}
uintptr_t GetColorRenderTarget(uint32_t pitch, MsaaSamples samples,
uint32_t base,
ColorRenderTargetFormat format) override {
// TODO(Triang3l): EDRAM viewer.
return 0;
}
uintptr_t GetDepthRenderTarget(uint32_t pitch, MsaaSamples samples,
uint32_t base,
DepthRenderTargetFormat format) override {
// TODO(Triang3l): EDRAM viewer.
return 0;
}
uintptr_t GetTextureEntry(const TextureInfo& texture_info,
const SamplerInfo& sampler_info) override {
// TODO(Triang3l): Textures, but from a fetch constant rather than
// TextureInfo/SamplerInfo which are going away.
return 0;
}
};
int trace_viewer_main(const std::vector<std::wstring>& args) {
D3D12TraceViewer trace_viewer;
return trace_viewer.Main(args);
}
} // namespace d3d12
} // namespace gpu
} // namespace xe
DEFINE_ENTRY_POINT(L"xenia-gpu-d3d12-trace-viewer",
xe::gpu::d3d12::trace_viewer_main, "some.trace",
"target_trace_file");

View File

@ -38,6 +38,15 @@ void DeferredCommandList::Execute(ID3D12GraphicsCommandList* command_list,
stream += header_size;
stream_remaining -= header_size;
switch (Command(header[0])) {
case Command::kD3DClearUnorderedAccessViewUint: {
auto& args =
*reinterpret_cast<const ClearUnorderedAccessViewHeader*>(stream);
command_list->ClearUnorderedAccessViewUint(
args.view_gpu_handle_in_current_heap, args.view_cpu_handle,
args.resource, args.values_uint, args.num_rects,
args.num_rects ? reinterpret_cast<const D3D12_RECT*>(&args + 1)
: nullptr);
} break;
case Command::kD3DCopyBufferRegion: {
auto& args =
*reinterpret_cast<const D3DCopyBufferRegionArguments*>(stream);

View File

@ -15,7 +15,7 @@
#include <vector>
#include "xenia/base/math.h"
#include "xenia/ui/d3d12/command_list.h"
#include "xenia/ui/d3d12/d3d12_api.h"
namespace xe {
namespace gpu {
@ -32,6 +32,24 @@ class DeferredCommandList {
void Execute(ID3D12GraphicsCommandList* command_list,
ID3D12GraphicsCommandList1* command_list_1);
inline void D3DClearUnorderedAccessViewUint(
D3D12_GPU_DESCRIPTOR_HANDLE view_gpu_handle_in_current_heap,
D3D12_CPU_DESCRIPTOR_HANDLE view_cpu_handle, ID3D12Resource* resource,
const UINT values[4], UINT num_rects, const D3D12_RECT* rects) {
auto args = reinterpret_cast<ClearUnorderedAccessViewHeader*>(
WriteCommand(Command::kD3DClearUnorderedAccessViewUint,
sizeof(ClearUnorderedAccessViewHeader) +
num_rects * sizeof(D3D12_RECT)));
args->view_gpu_handle_in_current_heap = view_gpu_handle_in_current_heap;
args->view_cpu_handle = view_cpu_handle;
args->resource = resource;
std::memcpy(args->values_uint, values, 4 * sizeof(UINT));
args->num_rects = num_rects;
if (num_rects != 0) {
std::memcpy(args + 1, rects, num_rects * sizeof(D3D12_RECT));
}
}
inline void D3DCopyBufferRegion(ID3D12Resource* dst_buffer, UINT64 dst_offset,
ID3D12Resource* src_buffer, UINT64 src_offset,
UINT64 num_bytes) {
@ -303,6 +321,7 @@ class DeferredCommandList {
static constexpr size_t kAlignment = std::max(sizeof(void*), sizeof(UINT64));
enum class Command : uint32_t {
kD3DClearUnorderedAccessViewUint,
kD3DCopyBufferRegion,
kD3DCopyResource,
kCopyTexture,
@ -331,6 +350,17 @@ class DeferredCommandList {
kD3DSetSamplePositions,
};
struct ClearUnorderedAccessViewHeader {
D3D12_GPU_DESCRIPTOR_HANDLE view_gpu_handle_in_current_heap;
D3D12_CPU_DESCRIPTOR_HANDLE view_cpu_handle;
ID3D12Resource* resource;
union {
float values_float[4];
UINT values_uint[4];
};
UINT num_rects;
};
struct D3DCopyBufferRegionArguments {
ID3D12Resource* dst_buffer;
UINT64 dst_offset;

View File

@ -154,7 +154,7 @@ void PipelineCache::ClearCache() {
shader_map_.clear();
}
void PipelineCache::EndFrame() {
void PipelineCache::EndSubmission() {
if (!creation_threads_.empty()) {
// Await creation of all queued pipelines.
bool await_event = false;

View File

@ -42,7 +42,7 @@ class PipelineCache {
void Shutdown();
void ClearCache();
void EndFrame();
void EndSubmission();
D3D12Shader* LoadShader(ShaderType shader_type, uint32_t guest_address,
const uint32_t* host_address, uint32_t dword_count);

View File

@ -18,6 +18,50 @@ project("xenia-gpu-d3d12")
"shaders/bin/*.h",
})
group("src")
project("xenia-gpu-d3d12-trace-viewer")
uuid("7b5b9fcb-7bf1-43ff-a774-d4c41c8706be")
kind("WindowedApp")
language("C++")
links({
"aes_128",
"capstone",
"dxbc",
"imgui",
"libavcodec",
"libavutil",
"mspack",
"snappy",
"xenia-apu",
"xenia-apu-nop",
"xenia-base",
"xenia-core",
"xenia-cpu",
"xenia-cpu-backend-x64",
"xenia-gpu",
"xenia-gpu-d3d12",
"xenia-hid",
"xenia-hid-nop",
"xenia-kernel",
"xenia-ui",
"xenia-ui-d3d12",
"xenia-vfs",
"xxhash",
})
files({
"d3d12_trace_viewer_main.cc",
"../../base/main_"..platform_suffix..".cc",
})
-- Only create the .user file if it doesn't already exist.
local user_file = project_root.."/build/xenia-gpu-d3d12-trace-viewer.vcxproj.user"
if not os.isfile(user_file) then
debugdir(project_root)
debugargs({
"2>&1",
"1>scratch/stdout-trace-viewer.txt",
})
end
group("src")
project("xenia-gpu-d3d12-trace-dump")
uuid("686b859c-0046-44c4-a02c-41fc3fb75698")

View File

@ -53,14 +53,14 @@ PrimitiveConverter::PrimitiveConverter(D3D12CommandProcessor* command_processor,
PrimitiveConverter::~PrimitiveConverter() { Shutdown(); }
bool PrimitiveConverter::Initialize() {
auto context = command_processor_->GetD3D12Context();
auto device = context->GetD3D12Provider()->GetDevice();
auto device =
command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice();
// There can be at most 65535 indices in a Xenos draw call, but they can be up
// to 4 bytes large, and conversion can add more indices (almost triple the
// count for triangle strips, for instance).
buffer_pool_ =
std::make_unique<ui::d3d12::UploadBufferPool>(context, 4 * 1024 * 1024);
std::make_unique<ui::d3d12::UploadBufferPool>(device, 4 * 1024 * 1024);
// Create the static index buffer for non-indexed drawing.
D3D12_RESOURCE_DESC static_ib_desc;
@ -112,7 +112,7 @@ bool PrimitiveConverter::Initialize() {
}
static_ib_upload_->Unmap(0, nullptr);
// Not uploaded yet.
static_ib_upload_frame_ = UINT64_MAX;
static_ib_upload_submission_ = UINT64_MAX;
if (FAILED(device->CreateCommittedResource(
&ui::d3d12::util::kHeapPropertiesDefault, D3D12_HEAP_FLAG_NONE,
&static_ib_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
@ -142,34 +142,33 @@ void PrimitiveConverter::Shutdown() {
void PrimitiveConverter::ClearCache() { buffer_pool_->ClearCache(); }
void PrimitiveConverter::BeginFrame() {
void PrimitiveConverter::BeginSubmission() {
// Got a command list now - upload and transition the static index buffer if
// needed.
if (static_ib_upload_ != nullptr) {
auto context = command_processor_->GetD3D12Context();
if (static_ib_upload_frame_ == UINT64_MAX) {
if (static_ib_upload_) {
if (static_ib_upload_submission_ == UINT64_MAX) {
// Not uploaded yet - upload.
command_processor_->GetDeferredCommandList()->D3DCopyResource(
static_ib_, static_ib_upload_);
command_processor_->PushTransitionBarrier(
static_ib_, D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_INDEX_BUFFER);
static_ib_upload_frame_ = context->GetCurrentFrame();
} else if (context->GetLastCompletedFrame() >= static_ib_upload_frame_) {
static_ib_upload_submission_ = command_processor_->GetCurrentSubmission();
} else if (command_processor_->GetCompletedSubmission() >=
static_ib_upload_submission_) {
// Completely uploaded - release the upload buffer.
static_ib_upload_->Release();
static_ib_upload_ = nullptr;
}
}
}
buffer_pool_->BeginFrame();
void PrimitiveConverter::BeginFrame() {
buffer_pool_->Reclaim(command_processor_->GetCompletedFrame());
converted_indices_cache_.clear();
memory_regions_used_ = 0;
}
void PrimitiveConverter::EndFrame() { buffer_pool_->EndFrame(); }
PrimitiveType PrimitiveConverter::GetReplacementPrimitiveType(
PrimitiveType type) {
switch (type) {
@ -696,7 +695,8 @@ void* PrimitiveConverter::AllocateIndices(
}
D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
uint8_t* mapping =
buffer_pool_->RequestFull(size, nullptr, nullptr, &gpu_address);
buffer_pool_->Request(command_processor_->GetCurrentFrame(), size,
nullptr, nullptr, &gpu_address);
if (mapping == nullptr) {
XELOGE("Failed to allocate space for %u converted %u-bit vertex indices",
count, format == IndexFormat::kInt32 ? 32 : 16);

View File

@ -46,8 +46,8 @@ class PrimitiveConverter {
void Shutdown();
void ClearCache();
void BeginSubmission();
void BeginFrame();
void EndFrame();
// Returns the primitive type that the original type will be converted to.
static PrimitiveType GetReplacementPrimitiveType(PrimitiveType type);
@ -112,7 +112,7 @@ class PrimitiveConverter {
// CPU-side, used only for uploading - destroyed once the copy commands have
// been completed.
ID3D12Resource* static_ib_upload_ = nullptr;
uint64_t static_ib_upload_frame_;
uint64_t static_ib_upload_submission_;
// GPU-side - used for drawing.
ID3D12Resource* static_ib_ = nullptr;
D3D12_GPU_VIRTUAL_ADDRESS static_ib_gpu_address_;

View File

@ -23,6 +23,7 @@
#include "xenia/gpu/texture_info.h"
#include "xenia/gpu/texture_util.h"
#include "xenia/ui/d3d12/d3d12_util.h"
#include "xenia/ui/d3d12/pools.h"
DEFINE_bool(d3d12_16bit_rtv_full_range, true,
"Use full -32...32 range for RG16 and RGBA16 render targets "
@ -390,6 +391,8 @@ bool RenderTargetCache::Initialize(const TextureCache* texture_cache) {
void RenderTargetCache::Shutdown() {
ClearCache();
edram_snapshot_restore_pool_.reset();
ui::d3d12::util::ReleaseAndNull(edram_snapshot_download_buffer_);
for (auto& resolve_pipeline : resolve_pipelines_) {
resolve_pipeline.pipeline->Release();
}
@ -448,15 +451,31 @@ void RenderTargetCache::ClearCache() {
}
}
#endif
edram_snapshot_restore_pool_.reset();
}
void RenderTargetCache::BeginFrame() {
// A frame does not always end in a resolve (for example, when memexport
// readback happens) or something else that would surely submit the UAV
// barrier, so we need to preserve the `current_` variables.
if (!command_processor_->IsROVUsedForEDRAM()) {
ClearBindings();
void RenderTargetCache::BeginSubmission() {
if (edram_snapshot_restore_pool_) {
edram_snapshot_restore_pool_->Reclaim(
command_processor_->GetCompletedSubmission());
}
// With the ROV, a submission does not always end in a resolve (for example,
// when memexport readback happens) or something else that would surely submit
// the UAV barrier, so we need to preserve the `current_` variables.
//
// With RTVs, simply going to a different command list doesn't have to cause
// storing the render targets to the EDRAM buffer, however, the new command
// list doesn't have the needed RTVs/DSV bound yet.
//
// Just make sure they are bound to the new command list.
ForceApplyOnNextUpdate();
}
void RenderTargetCache::EndFrame() {
// May be clearing the cache after this.
FlushAndUnbindRenderTargets();
}
bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
@ -751,6 +770,8 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
}
}
bool sample_positions_set = false;
// Need to change the bindings.
if (full_update || render_targets_to_attach) {
#if 0
@ -892,7 +913,8 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
if (!rov_used) {
// Sample positions when loading depth must match sample positions when
// drawing.
command_processor_->SetSamplePositions(rb_surface_info.msaa_samples);
command_processor_->SetSamplePositions(current_msaa_samples_);
sample_positions_set = true;
// Load the contents of the new render targets from the EDRAM buffer (will
// change the state of the render targets to copy destination).
@ -918,13 +940,16 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
// Transition the render targets to the appropriate state if needed,
// compress the list of the render target because null RTV descriptors are
// broken in Direct3D 12 and bind the render targets to the command list.
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handles[4];
// broken in Direct3D 12 and update the list of the render targets to bind
// to the command list.
uint32_t rtv_count = 0;
for (uint32_t i = 0; i < 4; ++i) {
const RenderTargetBinding& binding = current_bindings_[i];
if (!binding.is_bound) {
continue;
}
RenderTarget* render_target = binding.render_target;
if (!binding.is_bound || render_target == nullptr) {
if (render_target == nullptr) {
continue;
}
XELOGGPU("RT Color %u: base %u, format %u", i, edram_bases[i],
@ -933,7 +958,6 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
render_target->resource, render_target->state,
D3D12_RESOURCE_STATE_RENDER_TARGET);
render_target->state = D3D12_RESOURCE_STATE_RENDER_TARGET;
rtv_handles[rtv_count] = render_target->handle;
current_pipeline_render_targets_[rtv_count].guest_render_target = i;
current_pipeline_render_targets_[rtv_count].format =
GetColorDXGIFormat(ColorRenderTargetFormat(formats[i]));
@ -943,7 +967,6 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
current_pipeline_render_targets_[i].guest_render_target = i;
current_pipeline_render_targets_[i].format = DXGI_FORMAT_UNKNOWN;
}
const D3D12_CPU_DESCRIPTOR_HANDLE* dsv_handle;
const RenderTargetBinding& depth_binding = current_bindings_[4];
RenderTarget* depth_render_target = depth_binding.render_target;
current_pipeline_render_targets_[4].guest_render_target = 4;
@ -953,19 +976,44 @@ bool RenderTargetCache::UpdateRenderTargets(const D3D12Shader* pixel_shader) {
depth_render_target->resource, depth_render_target->state,
D3D12_RESOURCE_STATE_DEPTH_WRITE);
depth_render_target->state = D3D12_RESOURCE_STATE_DEPTH_WRITE;
dsv_handle = &depth_binding.render_target->handle;
current_pipeline_render_targets_[4].format =
GetDepthDXGIFormat(DepthRenderTargetFormat(formats[4]));
} else {
dsv_handle = nullptr;
current_pipeline_render_targets_[4].format = DXGI_FORMAT_UNKNOWN;
}
command_processor_->SubmitBarriers();
command_processor_->GetDeferredCommandList()->D3DOMSetRenderTargets(
rtv_count, rtv_handles, FALSE, dsv_handle);
apply_to_command_list_ = true;
}
}
// Bind the render targets to the command list, either in case of an update or
// if asked to externally.
if (!rov_used && apply_to_command_list_) {
apply_to_command_list_ = false;
if (!sample_positions_set) {
command_processor_->SetSamplePositions(current_msaa_samples_);
}
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handles[4];
uint32_t rtv_count;
for (rtv_count = 0; rtv_count < 4; ++rtv_count) {
const PipelineRenderTarget& pipeline_render_target =
current_pipeline_render_targets_[rtv_count];
if (pipeline_render_target.format == DXGI_FORMAT_UNKNOWN) {
break;
}
const RenderTargetBinding& binding =
current_bindings_[pipeline_render_target.guest_render_target];
rtv_handles[rtv_count] = binding.render_target->handle;
}
const RenderTargetBinding& depth_binding = current_bindings_[4];
const D3D12_CPU_DESCRIPTOR_HANDLE* dsv_handle =
current_pipeline_render_targets_[4].format != DXGI_FORMAT_UNKNOWN
? &depth_binding.render_target->handle
: nullptr;
command_processor_->GetDeferredCommandList()->D3DOMSetRenderTargets(
rtv_count, rtv_handles, FALSE, dsv_handle);
}
// Update the dirty regions.
for (uint32_t i = 0; i < 5; ++i) {
if (!enabled[i] || (i == 4 && depth_readonly)) {
@ -1379,7 +1427,9 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start;
if (command_processor_->RequestViewDescriptors(
0, 2, 2, descriptor_cpu_start, descriptor_gpu_start) == 0) {
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 2, 2,
descriptor_cpu_start, descriptor_gpu_start) ==
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
return false;
}
TransitionEDRAMBuffer(D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
@ -1527,7 +1577,9 @@ bool RenderTargetCache::ResolveCopy(SharedMemory* shared_memory,
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start;
if (command_processor_->RequestViewDescriptors(
0, 3, 3, descriptor_cpu_start, descriptor_gpu_start) == 0) {
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 3, 3,
descriptor_cpu_start, descriptor_gpu_start) ==
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
return false;
}
// Buffer for copying.
@ -1833,8 +1885,10 @@ bool RenderTargetCache::ResolveClear(uint32_t edram_base,
command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice();
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start;
if (command_processor_->RequestViewDescriptors(0, 1, 1, descriptor_cpu_start,
descriptor_gpu_start) == 0) {
if (command_processor_->RequestViewDescriptors(
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 1, 1,
descriptor_cpu_start, descriptor_gpu_start) ==
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
return false;
}
@ -2089,7 +2143,7 @@ RenderTargetCache::ResolveTarget* RenderTargetCache::FindOrCreateResolveTarget(
return resolve_target;
}
void RenderTargetCache::UnbindRenderTargets() {
void RenderTargetCache::FlushAndUnbindRenderTargets() {
if (command_processor_->IsROVUsedForEDRAM()) {
return;
}
@ -2109,8 +2163,6 @@ void RenderTargetCache::WriteEDRAMUint32UAVDescriptor(
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
void RenderTargetCache::EndFrame() { UnbindRenderTargets(); }
ColorRenderTargetFormat RenderTargetCache::GetBaseColorFormat(
ColorRenderTargetFormat format) {
switch (format) {
@ -2154,6 +2206,113 @@ DXGI_FORMAT RenderTargetCache::GetColorDXGIFormat(
return DXGI_FORMAT_UNKNOWN;
}
bool RenderTargetCache::InitializeTraceSubmitDownloads() {
if (resolution_scale_2x_) {
// No 1:1 mapping.
return false;
}
const uint32_t kEDRAMSize = 2048 * 5120;
if (!edram_snapshot_download_buffer_) {
D3D12_RESOURCE_DESC edram_snapshot_download_buffer_desc;
ui::d3d12::util::FillBufferResourceDesc(edram_snapshot_download_buffer_desc,
kEDRAMSize,
D3D12_RESOURCE_FLAG_NONE);
auto device =
command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice();
if (FAILED(device->CreateCommittedResource(
&ui::d3d12::util::kHeapPropertiesReadback, D3D12_HEAP_FLAG_NONE,
&edram_snapshot_download_buffer_desc,
D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
IID_PPV_ARGS(&edram_snapshot_download_buffer_)))) {
XELOGE("Failed to create a EDRAM snapshot download buffer");
return false;
}
}
auto command_list = command_processor_->GetDeferredCommandList();
TransitionEDRAMBuffer(D3D12_RESOURCE_STATE_COPY_SOURCE);
command_processor_->SubmitBarriers();
command_list->D3DCopyBufferRegion(edram_snapshot_download_buffer_, 0,
edram_buffer_, 0, kEDRAMSize);
return true;
}
void RenderTargetCache::InitializeTraceCompleteDownloads() {
if (!edram_snapshot_download_buffer_) {
return;
}
void* download_mapping;
if (SUCCEEDED(edram_snapshot_download_buffer_->Map(0, nullptr,
&download_mapping))) {
trace_writer_->WriteEDRAMSnapshot(download_mapping);
D3D12_RANGE download_write_range = {};
edram_snapshot_download_buffer_->Unmap(0, &download_write_range);
} else {
XELOGE("Failed to map the EDRAM snapshot download buffer");
}
edram_snapshot_download_buffer_->Release();
edram_snapshot_download_buffer_ = nullptr;
}
void RenderTargetCache::RestoreEDRAMSnapshot(const void* snapshot) {
if (resolution_scale_2x_) {
// No 1:1 mapping.
return;
}
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
auto device = provider->GetDevice();
const uint32_t kEDRAMSize = 2048 * 5120;
if (!edram_snapshot_restore_pool_) {
edram_snapshot_restore_pool_ =
std::make_unique<ui::d3d12::UploadBufferPool>(device, kEDRAMSize);
}
ID3D12Resource* upload_buffer;
uint32_t upload_buffer_offset;
void* upload_buffer_mapping = edram_snapshot_restore_pool_->Request(
command_processor_->GetCurrentSubmission(), kEDRAMSize, &upload_buffer,
&upload_buffer_offset, nullptr);
if (!upload_buffer_mapping) {
XELOGE("Failed to get a buffer for restoring a EDRAM snapshot");
return;
}
std::memcpy(upload_buffer_mapping, snapshot, kEDRAMSize);
auto command_list = command_processor_->GetDeferredCommandList();
TransitionEDRAMBuffer(D3D12_RESOURCE_STATE_COPY_DEST);
command_processor_->SubmitBarriers();
command_list->D3DCopyBufferRegion(edram_buffer_, 0, upload_buffer,
upload_buffer_offset, kEDRAMSize);
if (!command_processor_->IsROVUsedForEDRAM()) {
// Clear and ignore the old 32-bit float depth - the non-ROV path is
// inaccurate anyway, and this is backend-specific, not a part of a guest
// trace.
D3D12_CPU_DESCRIPTOR_HANDLE shader_visbile_descriptor_cpu;
D3D12_GPU_DESCRIPTOR_HANDLE shader_visbile_descriptor_gpu;
if (command_processor_->RequestViewDescriptors(
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 1, 1,
shader_visbile_descriptor_cpu, shader_visbile_descriptor_gpu) !=
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
WriteEDRAMUint32UAVDescriptor(shader_visbile_descriptor_cpu);
UINT clear_value[4] = {0, 0, 0, 0};
D3D12_RECT clear_rect;
clear_rect.left = kEDRAMSize >> 2;
clear_rect.top = 0;
clear_rect.right = (kEDRAMSize >> 2) << 1;
clear_rect.bottom = 1;
TransitionEDRAMBuffer(D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
command_processor_->SubmitBarriers();
// ClearUnorderedAccessView takes a shader-visible GPU descriptor and a
// non-shader-visible CPU descriptor.
command_list->D3DClearUnorderedAccessViewUint(
shader_visbile_descriptor_gpu,
provider->OffsetViewDescriptor(
edram_buffer_descriptor_heap_start_,
uint32_t(EDRAMBufferDescriptorIndex::kUint32UAV)),
edram_buffer_, clear_value, 1, &clear_rect);
} else {
XELOGE("Failed to get a UAV descriptor for invalidating 32-bit depth");
}
}
}
uint32_t RenderTargetCache::GetEDRAMBufferSize() const {
uint32_t size = 2048 * 5120;
if (!command_processor_->IsROVUsedForEDRAM()) {
@ -2172,10 +2331,14 @@ void RenderTargetCache::TransitionEDRAMBuffer(D3D12_RESOURCE_STATES new_state) {
command_processor_->PushTransitionBarrier(edram_buffer_, edram_buffer_state_,
new_state);
edram_buffer_state_ = new_state;
if (new_state != D3D12_RESOURCE_STATE_UNORDERED_ACCESS) {
edram_buffer_modified_ = false;
}
}
void RenderTargetCache::CommitEDRAMBufferUAVWrites(bool force) {
if (edram_buffer_modified_ || force) {
if ((edram_buffer_modified_ || force) &&
edram_buffer_state_ == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) {
command_processor_->PushUAVBarrier(edram_buffer_);
}
edram_buffer_modified_ = false;
@ -2210,6 +2373,7 @@ void RenderTargetCache::ClearBindings() {
current_msaa_samples_ = MsaaSamples::k1X;
current_edram_max_rows_ = 0;
std::memset(current_bindings_, 0, sizeof(current_bindings_));
apply_to_command_list_ = true;
}
#if 0
@ -2549,8 +2713,10 @@ void RenderTargetCache::StoreRenderTargetsToEDRAM() {
// Allocate descriptors for the buffers.
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start;
if (command_processor_->RequestViewDescriptors(0, 2, 2, descriptor_cpu_start,
descriptor_gpu_start) == 0) {
if (command_processor_->RequestViewDescriptors(
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 2, 2,
descriptor_cpu_start, descriptor_gpu_start) ==
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
return;
}
@ -2694,8 +2860,10 @@ void RenderTargetCache::LoadRenderTargetsFromEDRAM(
// Allocate descriptors for the buffers.
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start;
if (command_processor_->RequestViewDescriptors(0, 2, 2, descriptor_cpu_start,
descriptor_gpu_start) == 0) {
if (command_processor_->RequestViewDescriptors(
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 2, 2,
descriptor_cpu_start, descriptor_gpu_start) ==
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
return;
}

View File

@ -10,6 +10,7 @@
#ifndef XENIA_GPU_D3D12_RENDER_TARGET_CACHE_H_
#define XENIA_GPU_D3D12_RENDER_TARGET_CACHE_H_
#include <memory>
#include <unordered_map>
#include "xenia/base/cvar.h"
@ -21,6 +22,7 @@
#include "xenia/gpu/xenos.h"
#include "xenia/memory.h"
#include "xenia/ui/d3d12/d3d12_api.h"
#include "xenia/ui/d3d12/pools.h"
DECLARE_bool(d3d12_16bit_rtv_full_range);
@ -255,7 +257,8 @@ class RenderTargetCache {
void Shutdown();
void ClearCache();
void BeginFrame();
void BeginSubmission();
void EndFrame();
// Called in the beginning of a draw call - may bind pipelines.
bool UpdateRenderTargets(const D3D12Shader* pixel_shader);
// Returns the host-to-guest mappings and host formats of currently bound
@ -271,12 +274,14 @@ class RenderTargetCache {
bool Resolve(SharedMemory* shared_memory, TextureCache* texture_cache,
Memory* memory, uint32_t& written_address_out,
uint32_t& written_length_out);
// Makes sure the render targets are re-attached to the command list for which
// the next update will take place.
void ForceApplyOnNextUpdate() { apply_to_command_list_ = true; }
// Flushes the render targets to EDRAM and unbinds them, for instance, when
// the command processor takes over framebuffer bindings to draw something
// special.
void UnbindRenderTargets();
void FlushAndUnbindRenderTargets();
void WriteEDRAMUint32UAVDescriptor(D3D12_CPU_DESCRIPTOR_HANDLE handle);
void EndFrame();
// Totally necessary to rely on the base format - Too Human switches between
// 2_10_10_10_FLOAT and 2_10_10_10_FLOAT_AS_16_16_16_16 every draw.
@ -298,6 +303,11 @@ class RenderTargetCache {
: DXGI_FORMAT_D24_UNORM_S8_UINT;
}
// Returns true if any downloads were submitted to the command processor.
bool InitializeTraceSubmitDownloads();
void InitializeTraceCompleteDownloads();
void RestoreEDRAMSnapshot(const void* snapshot);
private:
enum class EDRAMLoadStoreMode {
kColor32bpp,
@ -636,6 +646,7 @@ class RenderTargetCache {
// current_edram_max_rows_ is for RTV/DSV only (render target texture size).
uint32_t current_edram_max_rows_ = 0;
RenderTargetBinding current_bindings_[5] = {};
bool apply_to_command_list_ = true;
PipelineRenderTarget current_pipeline_render_targets_[5];
@ -669,6 +680,11 @@ class RenderTargetCache {
#else
std::unordered_map<uint32_t, ResolveTarget*> resolve_targets_;
#endif
// For traces only.
ID3D12Resource* edram_snapshot_download_buffer_ = nullptr;
std::unique_ptr<ui::d3d12::UploadBufferPool> edram_snapshot_restore_pool_ =
nullptr;
};
} // namespace d3d12

View File

@ -59,8 +59,7 @@ SharedMemory::SharedMemory(D3D12CommandProcessor* command_processor,
SharedMemory::~SharedMemory() { Shutdown(); }
bool SharedMemory::Initialize() {
auto context = command_processor_->GetD3D12Context();
auto provider = context->GetD3D12Provider();
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
auto device = provider->GetDevice();
D3D12_RESOURCE_DESC buffer_desc;
@ -98,7 +97,6 @@ bool SharedMemory::Initialize() {
std::memset(heaps_, 0, sizeof(heaps_));
heap_count_ = 0;
heap_creation_failed_ = false;
D3D12_DESCRIPTOR_HEAP_DESC buffer_descriptor_heap_desc;
buffer_descriptor_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
@ -131,7 +129,7 @@ bool SharedMemory::Initialize() {
valid_and_gpu_written_pages_.size() * sizeof(uint64_t));
upload_buffer_pool_ =
std::make_unique<ui::d3d12::UploadBufferPool>(context, 4 * 1024 * 1024);
std::make_unique<ui::d3d12::UploadBufferPool>(device, 4 * 1024 * 1024);
physical_write_watch_handle_ =
memory_->RegisterPhysicalWriteWatch(MemoryWriteCallbackThunk, this);
@ -167,13 +165,10 @@ void SharedMemory::Shutdown() {
}
}
void SharedMemory::BeginFrame() {
upload_buffer_pool_->BeginFrame();
heap_creation_failed_ = false;
void SharedMemory::BeginSubmission() {
upload_buffer_pool_->Reclaim(command_processor_->GetCompletedSubmission());
}
void SharedMemory::EndFrame() { upload_buffer_pool_->EndFrame(); }
SharedMemory::GlobalWatchHandle SharedMemory::RegisterGlobalWatch(
GlobalWatchCallback callback, void* callback_context) {
GlobalWatch* watch = new GlobalWatch;
@ -297,11 +292,6 @@ bool SharedMemory::MakeTilesResident(uint32_t start, uint32_t length) {
if (heaps_[i] != nullptr) {
continue;
}
if (heap_creation_failed_) {
// Don't try to create a heap for every vertex buffer or texture in the
// current frame anymore if have failed at least once.
return false;
}
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
auto device = provider->GetDevice();
auto direct_queue = provider->GetDirectQueue();
@ -311,7 +301,6 @@ bool SharedMemory::MakeTilesResident(uint32_t start, uint32_t length) {
heap_desc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
if (FAILED(device->CreateHeap(&heap_desc, IID_PPV_ARGS(&heaps_[i])))) {
XELOGE("Shared memory: Failed to create a tile heap");
heap_creation_failed_ = true;
return false;
}
++heap_count_;
@ -331,8 +320,8 @@ bool SharedMemory::MakeTilesResident(uint32_t start, uint32_t length) {
UINT range_tile_count = kHeapSize / D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES;
// FIXME(Triang3l): This may cause issues if the emulator is shut down
// mid-frame and the heaps are destroyed before tile mappings are updated
// (AwaitAllFramesCompletion won't catch this then). Defer this until the
// actual command list submission at the end of the frame.
// (awaiting the fence won't catch this then). Defer this until the actual
// command list submission at the end of the frame.
direct_queue->UpdateTileMappings(
buffer_, 1, &region_start_coordinates, &region_size, heaps_[i], 1,
&range_flags, &heap_range_start_offset, &range_tile_count,
@ -378,6 +367,7 @@ bool SharedMemory::RequestRange(uint32_t start, uint32_t length) {
ID3D12Resource* upload_buffer;
uint32_t upload_buffer_offset, upload_buffer_size;
uint8_t* upload_buffer_mapping = upload_buffer_pool_->RequestPartial(
command_processor_->GetCurrentSubmission(),
upload_range_length << page_size_log2_, &upload_buffer,
&upload_buffer_offset, &upload_buffer_size, nullptr);
if (upload_buffer_mapping == nullptr) {

View File

@ -44,8 +44,7 @@ class SharedMemory {
return buffer_gpu_address_;
}
void BeginFrame();
void EndFrame();
void BeginSubmission();
typedef void (*GlobalWatchCallback)(void* context, uint32_t address_first,
uint32_t address_last,
@ -166,8 +165,6 @@ class SharedMemory {
ID3D12Heap* heaps_[kBufferSize >> kHeapSizeLog2] = {};
// Number of the heaps currently resident, for profiling.
uint32_t heap_count_ = 0;
// Whether creation of a heap has failed in the current frame.
bool heap_creation_failed_ = false;
// Log2 of system page size.
uint32_t page_size_log2_;

View File

@ -24,6 +24,7 @@
#include "xenia/gpu/texture_info.h"
#include "xenia/gpu/texture_util.h"
#include "xenia/ui/d3d12/d3d12_util.h"
#include "xenia/ui/d3d12/pools.h"
DEFINE_int32(d3d12_resolution_scale, 1,
"Scale of rendering width and height (currently only 1 and 2 "
@ -90,6 +91,7 @@ namespace d3d12 {
#include "xenia/gpu/d3d12/shaders/dxbc/texture_tile_r10g11b11_rgba16_cs.h"
#include "xenia/gpu/d3d12/shaders/dxbc/texture_tile_r11g11b10_rgba16_cs.h"
constexpr uint32_t TextureCache::Texture::kCachedSRVDescriptorSwizzleMissing;
constexpr uint32_t TextureCache::SRVDescriptorCachePage::kHeapSize;
constexpr uint32_t TextureCache::LoadConstants::kGuestPitchTiled;
constexpr uint32_t TextureCache::kScaledResolveBufferSizeLog2;
@ -1168,8 +1170,7 @@ void TextureCache::BeginFrame() {
texture_current_usage_time_ = xe::Clock::QueryHostUptimeMillis();
// If memory usage is too high, destroy unused textures.
uint64_t last_completed_frame =
command_processor_->GetD3D12Context()->GetLastCompletedFrame();
uint64_t completed_frame = command_processor_->GetCompletedFrame();
uint32_t limit_soft_mb = cvars::d3d12_texture_cache_limit_soft;
uint32_t limit_hard_mb = cvars::d3d12_texture_cache_limit_hard;
if (IsResolutionScale2X()) {
@ -1186,7 +1187,7 @@ void TextureCache::BeginFrame() {
break;
}
Texture* texture = texture_used_first_;
if (texture->last_usage_frame > last_completed_frame) {
if (texture->last_usage_frame > completed_frame) {
break;
}
if (!limit_hard_exceeded &&
@ -1213,7 +1214,8 @@ void TextureCache::BeginFrame() {
// Exclude the texture from the memory usage counter.
textures_total_size_ -= texture->resource_size;
// Destroy the texture.
if (texture->cached_srv_descriptor.ptr) {
if (texture->cached_srv_descriptor_swizzle !=
Texture::kCachedSRVDescriptorSwizzleMissing) {
srv_descriptor_cache_free_.push_back(texture->cached_srv_descriptor);
}
shared_memory_->UnwatchMemoryRange(texture->base_watch_handle);
@ -1515,16 +1517,20 @@ void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
// swizzle. Profiling results say that CreateShaderResourceView takes the
// longest time of draw call processing, and it's very noticeable in many
// games.
bool cached_handle_available = false;
D3D12_CPU_DESCRIPTOR_HANDLE cached_handle = {};
assert_not_null(texture);
if (texture->cached_srv_descriptor.ptr) {
if (texture->cached_srv_descriptor_swizzle !=
Texture::kCachedSRVDescriptorSwizzleMissing) {
// Use an existing cached descriptor if it has the needed swizzle.
if (binding.swizzle == texture->cached_srv_descriptor_swizzle) {
cached_handle_available = true;
cached_handle = texture->cached_srv_descriptor;
}
} else {
// Try to create a new cached descriptor if it doesn't exist yet.
if (!srv_descriptor_cache_free_.empty()) {
cached_handle_available = true;
cached_handle = srv_descriptor_cache_free_.back();
srv_descriptor_cache_free_.pop_back();
} else if (srv_descriptor_cache_.empty() ||
@ -1542,22 +1548,24 @@ void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
new_page.heap = new_heap;
new_page.heap_start = new_heap->GetCPUDescriptorHandleForHeapStart();
new_page.current_usage = 1;
cached_handle_available = true;
cached_handle = new_page.heap_start;
srv_descriptor_cache_.push_back(new_page);
}
} else {
SRVDescriptorCachePage& page = srv_descriptor_cache_.back();
cached_handle_available = true;
cached_handle =
provider->OffsetViewDescriptor(page.heap_start, page.current_usage);
++page.current_usage;
}
if (cached_handle.ptr) {
if (cached_handle_available) {
device->CreateShaderResourceView(resource, &desc, cached_handle);
texture->cached_srv_descriptor = cached_handle;
texture->cached_srv_descriptor_swizzle = binding.swizzle;
}
}
if (cached_handle.ptr) {
if (cached_handle_available) {
device->CopyDescriptorsSimple(1, handle, cached_handle,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
} else {
@ -1813,8 +1821,10 @@ bool TextureCache::TileResolvedTexture(
// Tile the texture.
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start;
if (command_processor_->RequestViewDescriptors(0, 2, 2, descriptor_cpu_start,
descriptor_gpu_start) == 0) {
if (command_processor_->RequestViewDescriptors(
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 2, 2,
descriptor_cpu_start, descriptor_gpu_start) ==
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
return false;
}
if (resolution_scale_log2) {
@ -1953,8 +1963,8 @@ bool TextureCache::EnsureScaledResolveBufferResident(uint32_t start_unscaled,
kScaledResolveHeapSize / D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES;
// FIXME(Triang3l): This may cause issues if the emulator is shut down
// mid-frame and the heaps are destroyed before tile mappings are updated
// (AwaitAllFramesCompletion won't catch this then). Defer this until the
// actual command list submission at the end of the frame.
// (awaiting the fence won't catch this then). Defer this until the actual
// command list submission.
direct_queue->UpdateTileMappings(
scaled_resolve_buffer_, 1, &region_start_coordinates, &region_size,
scaled_resolve_heaps_[i], 1, &range_flags, &heap_range_start_offset,
@ -2290,8 +2300,8 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
// Untiling through a buffer instead of using unordered access because copying
// is not done that often.
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
auto context = command_processor_->GetD3D12Context();
auto device = context->GetD3D12Provider()->GetDevice();
auto device =
command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice();
// Assuming untiling will be the next operation.
D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COPY_DEST;
ID3D12Resource* resource;
@ -2309,7 +2319,7 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
texture->resource_size =
device->GetResourceAllocationInfo(0, 1, &desc).SizeInBytes;
texture->state = state;
texture->last_usage_frame = context->GetCurrentFrame();
texture->last_usage_frame = command_processor_->GetCurrentFrame();
texture->last_usage_time = texture_current_usage_time_;
texture->used_previous = texture_used_last_;
texture->used_next = nullptr;
@ -2378,8 +2388,8 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
}
texture->base_watch_handle = nullptr;
texture->mip_watch_handle = nullptr;
texture->cached_srv_descriptor.ptr = 0;
texture->cached_srv_descriptor_swizzle = 0b100100100100;
texture->cached_srv_descriptor_swizzle =
Texture::kCachedSRVDescriptorSwizzleMissing;
textures_.insert(std::make_pair(map_key, texture));
COUNT_profile_set("gpu/texture_cache/textures", textures_.size());
textures_total_size_ += texture->resource_size;
@ -2496,8 +2506,9 @@ bool TextureCache::LoadTextureData(Texture* texture) {
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start;
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start;
if (command_processor_->RequestViewDescriptors(
0, descriptor_count, descriptor_count, descriptor_cpu_start,
descriptor_gpu_start) == 0) {
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, descriptor_count,
descriptor_count, descriptor_cpu_start, descriptor_gpu_start) ==
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
command_processor_->ReleaseScratchGPUBuffer(copy_buffer, copy_buffer_state);
return false;
}
@ -2602,7 +2613,8 @@ bool TextureCache::LoadTextureData(Texture* texture) {
load_constants.guest_mip_offset[2]);
}
D3D12_GPU_VIRTUAL_ADDRESS cbuffer_gpu_address;
uint8_t* cbuffer_mapping = cbuffer_pool->RequestFull(
uint8_t* cbuffer_mapping = cbuffer_pool->Request(
command_processor_->GetCurrentFrame(),
xe::align(uint32_t(sizeof(load_constants)), 256u), nullptr, nullptr,
&cbuffer_gpu_address);
if (cbuffer_mapping == nullptr) {
@ -2680,8 +2692,7 @@ bool TextureCache::LoadTextureData(Texture* texture) {
}
void TextureCache::MarkTextureUsed(Texture* texture) {
uint64_t current_frame =
command_processor_->GetD3D12Context()->GetCurrentFrame();
uint64_t current_frame = command_processor_->GetCurrentFrame();
// This is called very frequently, don't relink unless needed for caching.
if (texture->last_usage_frame != current_frame) {
texture->last_usage_frame = current_frame;

View File

@ -363,7 +363,10 @@ class TextureCache {
// SRV descriptor from the cache, for the first swizzle the texture was used
// with (which is usually determined by the format, such as RGBA or BGRA).
// If swizzle is kCachedSRVDescriptorSwizzleMissing, the cached descriptor
// doesn't exist yet (there are no invalid D3D descriptor handle values).
D3D12_CPU_DESCRIPTOR_HANDLE cached_srv_descriptor;
static constexpr uint32_t kCachedSRVDescriptorSwizzleMissing = UINT32_MAX;
uint32_t cached_srv_descriptor_swizzle;
// Watch handles for the memory ranges (protected by the shared memory watch

File diff suppressed because it is too large Load Diff

View File

@ -1,87 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_GLSL_SHADER_TRANSLATOR_H_
#define XENIA_GPU_GLSL_SHADER_TRANSLATOR_H_
#include <memory>
#include <string>
#include <vector>
#include "xenia/base/string_buffer.h"
#include "xenia/gpu/shader_translator.h"
namespace xe {
namespace gpu {
class GlslShaderTranslator : public ShaderTranslator {
public:
enum class Dialect {
kGL45,
kVulkan,
};
GlslShaderTranslator(Dialect dialect);
~GlslShaderTranslator() override;
protected:
void Reset() override;
void EmitTranslationError(const char* message) override;
void EmitUnimplementedTranslationError() override;
void StartTranslation() override;
std::vector<uint8_t> CompleteTranslation() override;
void ProcessLabel(uint32_t cf_index) override;
void ProcessControlFlowNopInstruction(uint32_t cf_index) override;
void ProcessControlFlowInstructionBegin(uint32_t cf_index) override;
void ProcessControlFlowInstructionEnd(uint32_t cf_index) override;
void ProcessExecInstructionBegin(const ParsedExecInstruction& instr) override;
void ProcessExecInstructionEnd(const ParsedExecInstruction& instr) override;
void ProcessLoopStartInstruction(
const ParsedLoopStartInstruction& instr) override;
void ProcessLoopEndInstruction(
const ParsedLoopEndInstruction& instr) override;
void ProcessCallInstruction(const ParsedCallInstruction& instr) override;
void ProcessReturnInstruction(const ParsedReturnInstruction& instr) override;
void ProcessJumpInstruction(const ParsedJumpInstruction& instr) override;
void ProcessAllocInstruction(const ParsedAllocInstruction& instr) override;
void ProcessVertexFetchInstruction(
const ParsedVertexFetchInstruction& instr) override;
void ProcessTextureFetchInstruction(
const ParsedTextureFetchInstruction& instr) override;
void ProcessAluInstruction(const ParsedAluInstruction& instr) override;
private:
void Indent();
void Unindent();
void EmitLoadOperand(size_t i, const InstructionOperand& op);
void EmitStoreVectorResult(const InstructionResult& result);
void EmitStoreScalarResult(const InstructionResult& result);
void EmitStoreResult(const InstructionResult& result, const char* temp);
Dialect dialect_;
StringBuffer source_;
int depth_ = 0;
char depth_prefix_[16] = {0};
bool cf_wrote_pc_ = false;
bool cf_exec_pred_ = false;
bool cf_exec_pred_cond_ = false;
bool ProcessVectorAluOperation(const ParsedAluInstruction& instr);
bool ProcessScalarAluOperation(const ParsedAluInstruction& instr);
};
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_GLSL_SHADER_TRANSLATOR_H_

View File

@ -21,6 +21,8 @@ NullCommandProcessor::~NullCommandProcessor() = default;
void NullCommandProcessor::TracePlaybackWroteMemory(uint32_t base_ptr,
uint32_t length) {}
void NullCommandProcessor::RestoreEDRAMSnapshot(const void* snapshot) {}
bool NullCommandProcessor::SetupContext() {
return CommandProcessor::SetupContext();
}

View File

@ -27,6 +27,8 @@ class NullCommandProcessor : public CommandProcessor {
void TracePlaybackWroteMemory(uint32_t base_ptr, uint32_t length) override;
void RestoreEDRAMSnapshot(const void* snapshot) override;
private:
bool SetupContext() override;
void ShutdownContext() override;

View File

@ -18,7 +18,6 @@
#include "xenia/base/platform.h"
#include "xenia/base/string.h"
#include "xenia/gpu/dxbc_shader_translator.h"
#include "xenia/gpu/glsl_shader_translator.h"
#include "xenia/gpu/shader_translator.h"
#include "xenia/gpu/spirv_shader_translator.h"
#include "xenia/ui/spirv/spirv_disassembler.h"
@ -34,7 +33,7 @@ DEFINE_string(shader_input_type, "",
"GPU");
DEFINE_string(shader_output, "", "Output shader file path.", "GPU");
DEFINE_string(shader_output_type, "ucode",
"Translator to use: [ucode, glsl45, spirv, spirvtext, dxbc].",
"Translator to use: [ucode, spirv, spirvtext, dxbc, dxbctext].",
"GPU");
DEFINE_string(shader_output_patch, "",
"Tessellation patch type in the generated tessellation "
@ -105,10 +104,8 @@ int shader_compiler_main(const std::vector<std::wstring>& args) {
if (cvars::shader_output_type == "spirv" ||
cvars::shader_output_type == "spirvtext") {
translator = std::make_unique<SpirvShaderTranslator>();
} else if (cvars::shader_output_type == "glsl45") {
translator = std::make_unique<GlslShaderTranslator>(
GlslShaderTranslator::Dialect::kGL45);
} else if (cvars::shader_output_type == "dxbc") {
} else if (cvars::shader_output_type == "dxbc" ||
cvars::shader_output_type == "dxbctext") {
translator = std::make_unique<DxbcShaderTranslator>(
0, cvars::shader_output_dxbc_rov);
} else {
@ -141,7 +138,7 @@ int shader_compiler_main(const std::vector<std::wstring>& args) {
}
#if XE_PLATFORM_WIN32
ID3DBlob* dxbc_disasm_blob = nullptr;
if (cvars::shader_output_type == "dxbc") {
if (cvars::shader_output_type == "dxbctext") {
HMODULE d3d_compiler = LoadLibrary(L"D3DCompiler_47.dll");
if (d3d_compiler != nullptr) {
pD3DDisassemble d3d_disassemble =
@ -154,6 +151,13 @@ int shader_compiler_main(const std::vector<std::wstring>& args) {
nullptr, &dxbc_disasm_blob))) {
source_data = dxbc_disasm_blob->GetBufferPointer();
source_data_size = dxbc_disasm_blob->GetBufferSize();
// Stop at the null terminator.
for (size_t i = 0; i < source_data_size; ++i) {
if (reinterpret_cast<const char*>(source_data)[i] == '\0') {
source_data_size = i;
break;
}
}
}
}
FreeLibrary(d3d_compiler);

View File

@ -32,7 +32,7 @@ TracePlayer::TracePlayer(xe::ui::Loop* loop, GraphicsSystem* graphics_system)
playback_event_ = xe::threading::Event::CreateAutoResetEvent(false);
}
TracePlayer::~TracePlayer() = default;
TracePlayer::~TracePlayer() { delete[] edram_snapshot_; }
const TraceReader::Frame* TracePlayer::current_frame() const {
if (current_frame_index_ >= frame_count()) {
@ -186,6 +186,19 @@ void TracePlayer::PlayTraceOnThread(const uint8_t* trace_data,
trace_ptr += cmd->encoded_length;
break;
}
case TraceCommandType::kEDRAMSnapshot: {
auto cmd = reinterpret_cast<const EDRAMSnapshotCommand*>(trace_ptr);
trace_ptr += sizeof(*cmd);
const size_t kEDRAMSize = 10 * 1024 * 1024;
if (!edram_snapshot_) {
edram_snapshot_ = new uint8_t[kEDRAMSize];
}
DecompressMemory(cmd->encoding_format, trace_ptr, cmd->encoded_length,
edram_snapshot_, kEDRAMSize);
trace_ptr += cmd->encoded_length;
command_processor->RestoreEDRAMSnapshot(edram_snapshot_);
break;
}
case TraceCommandType::kEvent: {
auto cmd = reinterpret_cast<const EventCommand*>(trace_ptr);
trace_ptr += sizeof(*cmd);

View File

@ -61,6 +61,7 @@ class TracePlayer : public TraceReader {
bool playing_trace_ = false;
std::atomic<uint32_t> playback_percent_ = {0};
std::unique_ptr<xe::threading::Event> playback_event_;
uint8_t* edram_snapshot_ = nullptr;
};
} // namespace gpu

View File

@ -51,6 +51,7 @@ enum class TraceCommandType : uint32_t {
kPacketEnd,
kMemoryRead,
kMemoryWrite,
kEDRAMSnapshot,
kEvent,
};
@ -110,6 +111,18 @@ struct MemoryCommand {
uint32_t decoded_length;
};
// Represents a full 10 MB snapshot of EDRAM contents, for trace initialization
// (since replaying the trace will reconstruct its state at any point later) as
// a sequence of tiles with row-major samples (2x multisampling as 1x2 samples,
// 4x as 2x2 samples).
struct EDRAMSnapshotCommand {
TraceCommandType type;
// Encoding format of the data in the trace file.
MemoryEncodingFormat encoding_format;
// Number of bytes the data occupies in the trace file in its encoded form.
uint32_t encoded_length;
};
// Represents a GPU event of EventCommand::Type.
struct EventCommand {
TraceCommandType type;

View File

@ -190,6 +190,11 @@ void TraceReader::ParseTrace() {
trace_ptr += sizeof(*cmd) + cmd->encoded_length;
break;
}
case TraceCommandType::kEDRAMSnapshot: {
auto cmd = reinterpret_cast<const EDRAMSnapshotCommand*>(trace_ptr);
trace_ptr += sizeof(*cmd) + cmd->encoded_length;
break;
}
case TraceCommandType::kEvent: {
auto cmd = reinterpret_cast<const EventCommand*>(trace_ptr);
trace_ptr += sizeof(*cmd);

View File

@ -192,7 +192,7 @@ void TraceViewer::DrawMultilineString(const std::string& str) {
}
void TraceViewer::DrawUI() {
// ImGui::ShowTestWindow();
// ImGui::ShowDemoWindow();
DrawControllerUI();
DrawCommandListUI();
@ -201,8 +201,9 @@ void TraceViewer::DrawUI() {
}
void TraceViewer::DrawControllerUI() {
ImGui::SetNextWindowPos(ImVec2(5, 5), ImGuiSetCond_FirstUseEver);
if (!ImGui::Begin("Controller", nullptr, ImVec2(340, 60))) {
ImGui::SetNextWindowPos(ImVec2(5, 5), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(340, 60));
if (!ImGui::Begin("Controller", nullptr)) {
ImGui::End();
return;
}
@ -248,10 +249,11 @@ void TraceViewer::DrawControllerUI() {
}
void TraceViewer::DrawPacketDisassemblerUI() {
ImGui::SetNextWindowCollapsed(true, ImGuiSetCond_FirstUseEver);
ImGui::SetNextWindowCollapsed(true, ImGuiCond_FirstUseEver);
ImGui::SetNextWindowPos(ImVec2(float(window_->width()) - 500 - 5, 5),
ImGuiSetCond_FirstUseEver);
if (!ImGui::Begin("Packet Disassembler", nullptr, ImVec2(500, 300))) {
ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(500, 300));
if (!ImGui::Begin("Packet Disassembler", nullptr)) {
ImGui::End();
return;
}
@ -372,6 +374,12 @@ void TraceViewer::DrawPacketDisassemblerUI() {
// ImGui::BulletText("MemoryWrite");
break;
}
case TraceCommandType::kEDRAMSnapshot: {
auto cmd = reinterpret_cast<const EDRAMSnapshotCommand*>(trace_ptr);
trace_ptr += sizeof(*cmd) + cmd->encoded_length;
// ImGui::BulletText("EDRAMSnapshot");
break;
}
case TraceCommandType::kEvent: {
auto cmd = reinterpret_cast<const EventCommand*>(trace_ptr);
trace_ptr += sizeof(*cmd);
@ -450,8 +458,9 @@ int TraceViewer::RecursiveDrawCommandBufferUI(
}
void TraceViewer::DrawCommandListUI() {
ImGui::SetNextWindowPos(ImVec2(5, 70), ImGuiSetCond_FirstUseEver);
if (!ImGui::Begin("Command List", nullptr, ImVec2(200, 640))) {
ImGui::SetNextWindowPos(ImVec2(5, 70), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(200, 640));
if (!ImGui::Begin("Command List", nullptr)) {
ImGui::End();
return;
}
@ -529,7 +538,7 @@ void TraceViewer::DrawCommandListUI() {
}
ImGui::PopID();
if (did_seek && target_command == -1) {
ImGui::SetScrollPosHere();
ImGui::SetScrollHereY(0.5f);
}
auto id = RecursiveDrawCommandBufferUI(frame, frame->command_tree.get());
@ -1046,8 +1055,9 @@ void TraceViewer::DrawStateUI() {
auto& regs = *graphics_system_->register_file();
ImGui::SetNextWindowPos(ImVec2(float(window_->width()) - 500 - 5, 30),
ImGuiSetCond_FirstUseEver);
if (!ImGui::Begin("State", nullptr, ImVec2(500, 680))) {
ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(500, 680));
if (!ImGui::Begin("State", nullptr)) {
ImGui::End();
return;
}
@ -1324,7 +1334,8 @@ void TraceViewer::DrawStateUI() {
ImGui::BulletText("Blend Color: (%.2f,%.2f,%.2f,%.2f)", blend_color.x,
blend_color.y, blend_color.z, blend_color.w);
ImGui::SameLine();
ImGui::ColorButton(blend_color, true);
// TODO small_height (was true) parameter was removed
ImGui::ColorButton(nullptr, blend_color);
uint32_t rb_color_mask = regs[XE_GPU_REG_RB_COLOR_MASK].u32;
uint32_t color_info[4] = {

View File

@ -229,6 +229,37 @@ void TraceWriter::WriteMemoryCommand(TraceCommandType type, uint32_t base_ptr,
}
}
void TraceWriter::WriteEDRAMSnapshot(const void* snapshot) {
const uint32_t kEDRAMSize = 10 * 1024 * 1024;
EDRAMSnapshotCommand cmd;
cmd.type = TraceCommandType::kEDRAMSnapshot;
if (compress_output_) {
// Write the header now so we reserve space in the buffer.
long header_position = std::ftell(file_);
cmd.encoding_format = MemoryEncodingFormat::kSnappy;
fwrite(&cmd, 1, sizeof(cmd), file_);
// Stream the content right to the buffer.
snappy::ByteArraySource snappy_source(
reinterpret_cast<const char*>(snapshot), kEDRAMSize);
SnappySink snappy_sink(file_);
cmd.encoded_length =
static_cast<uint32_t>(snappy::Compress(&snappy_source, &snappy_sink));
// Seek back and overwrite the header with our final size.
std::fseek(file_, header_position, SEEK_SET);
fwrite(&cmd, 1, sizeof(cmd), file_);
std::fseek(file_, header_position + sizeof(cmd) + cmd.encoded_length,
SEEK_SET);
} else {
// Uncompressed - write buffer directly to the file.
cmd.encoding_format = MemoryEncodingFormat::kNone;
cmd.encoded_length = kEDRAMSize;
fwrite(&cmd, 1, sizeof(cmd), file_);
fwrite(snapshot, 1, kEDRAMSize, file_);
}
}
void TraceWriter::WriteEvent(EventCommand::Type event_type) {
if (!file_) {
return;

View File

@ -42,6 +42,7 @@ class TraceWriter {
void WriteMemoryReadCachedNop(uint32_t base_ptr, size_t length);
void WriteMemoryWrite(uint32_t base_ptr, size_t length,
const void* host_ptr = nullptr);
void WriteEDRAMSnapshot(const void* snapshot);
void WriteEvent(EventCommand::Type event_type);
private:

View File

@ -21,6 +21,8 @@ VulkanCommandProcessor::~VulkanCommandProcessor() = default;
void VulkanCommandProcessor::TracePlaybackWroteMemory(uint32_t base_ptr,
uint32_t length) {}
void VulkanCommandProcessor::RestoreEDRAMSnapshot(const void* snapshot) {}
bool VulkanCommandProcessor::SetupContext() { return true; }
void VulkanCommandProcessor::ShutdownContext() {}

View File

@ -26,6 +26,8 @@ class VulkanCommandProcessor : public CommandProcessor {
void TracePlaybackWroteMemory(uint32_t base_ptr, uint32_t length) override;
void RestoreEDRAMSnapshot(const void* snapshot) override;
protected:
bool SetupContext() override;
void ShutdownContext() override;

View File

@ -36,7 +36,6 @@ using xe::ui::vulkan::CheckResult;
PipelineCache::PipelineCache(RegisterFile* register_file,
ui::vulkan::VulkanDevice* device)
: register_file_(register_file), device_(device) {
// We can also use the GLSL translator with a Vulkan dialect.
shader_translator_.reset(new SpirvShaderTranslator());
}

View File

@ -14,7 +14,6 @@
#include "third_party/xxhash/xxhash.h"
#include "xenia/gpu/glsl_shader_translator.h"
#include "xenia/gpu/register_file.h"
#include "xenia/gpu/spirv_shader_translator.h"
#include "xenia/gpu/vulkan/render_cache.h"

View File

@ -51,6 +51,8 @@ void VulkanCommandProcessor::RequestFrameTrace(const std::wstring& root_path) {
void VulkanCommandProcessor::TracePlaybackWroteMemory(uint32_t base_ptr,
uint32_t length) {}
void VulkanCommandProcessor::RestoreEDRAMSnapshot(const void* snapshot) {}
void VulkanCommandProcessor::ClearCaches() {
CommandProcessor::ClearCaches();
cache_clear_requested_ = true;

View File

@ -52,6 +52,7 @@ class VulkanCommandProcessor : public CommandProcessor {
void RequestFrameTrace(const std::wstring& root_path) override;
void TracePlaybackWroteMemory(uint32_t base_ptr, uint32_t length) override;
void RestoreEDRAMSnapshot(const void* snapshot) override;
void ClearCaches() override;
RenderCache* render_cache() { return render_cache_.get(); }

View File

@ -20,7 +20,6 @@ project("xenia-hid-demo")
kind("WindowedApp")
language("C++")
links({
"glew",
"imgui",
"volk",
"xenia-base",
@ -29,10 +28,6 @@ project("xenia-hid-demo")
"xenia-ui",
"xenia-ui-vulkan",
})
defines({
"GLEW_STATIC=1",
"GLEW_MX=1",
})
files({
"hid_demo.cc",
"../base/main_"..platform_suffix..".cc",
@ -46,7 +41,6 @@ project("xenia-hid-demo")
"X11",
"xcb",
"X11-xcb",
"GL",
"vulkan",
})

View File

@ -178,7 +178,7 @@ X_STATUS UserModule::LoadFromMemory(const void* addr, const size_t length) {
auto processor = kernel_state()->processor();
auto magic = xe::load_and_swap<uint32_t>(addr);
if (magic == 'XEX2') {
if (magic == 'XEX2' || magic == 'XEX1') {
module_format_ = kModuleFormatXex;
} else if (magic == 0x7F454C46 /* 0x7F 'ELF' */) {
module_format_ = kModuleFormatElf;

View File

@ -194,6 +194,7 @@ X_STATUS ObjectTable::RemoveHandle(X_HANDLE handle) {
if (entry->object) {
auto object = entry->object;
entry->object = nullptr;
assert_zero(entry->handle_ref_count);
entry->handle_ref_count = 0;
// Walk the object's handles and remove this one.

View File

@ -544,6 +544,23 @@ struct xex2_security_info {
xex2_page_descriptor page_descriptors[1]; // 0x184
};
struct xex1_security_info {
xe::be<uint32_t> header_size;
xe::be<uint32_t> image_size;
char rsa_signature[0x100];
char image_digest[0x14];
char import_table_digest[0x14];
xe::be<uint32_t> load_address;
char aes_key[0x10];
char xgd2_media_id[0x10];
xe::be<uint32_t> region;
xe::be<uint32_t> image_flags;
xe::be<uint32_t> export_table;
xe::be<uint32_t> allowed_media_types;
xe::be<uint32_t> page_descriptor_count;
xex2_page_descriptor page_descriptors[1];
};
struct xex2_export_table {
xe::be<uint32_t> magic[3]; // 0x0
xe::be<uint32_t> modulenumber[2]; // 0xC

View File

@ -170,8 +170,8 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle,
if (XSUCCEEDED(result)) {
if (true || file->is_synchronous()) {
// some games NtReadFile() directly into texture memory
// TODO(rick): better checking of physical address
if (buffer.guest_address() >= 0xA0000000) {
auto heap = kernel_memory()->LookupHeap(buffer.guest_address());
if (heap && heap->IsGuestPhysicalHeap()) {
kernel_memory()->TriggerWatches(buffer.guest_address(), buffer_length,
true, true);
}

View File

@ -69,7 +69,7 @@ dword_result_t ObLookupThreadByThreadId(dword_t thread_id,
}
// Retain the object. Will be released in ObDereferenceObject.
thread->Retain();
thread->RetainHandle();
*out_object_ptr = thread->guest_object();
return X_STATUS_SUCCESS;
}
@ -133,7 +133,7 @@ dword_result_t ObReferenceObjectByHandle(dword_t handle,
// Caller takes the reference.
// It's released in ObDereferenceObject.
object->Retain();
object->RetainHandle();
if (out_object_ptr.guest_address()) {
*out_object_ptr = native_ptr;
}
@ -169,7 +169,7 @@ dword_result_t ObDereferenceObject(dword_t native_ptr) {
auto object = XObject::GetNativeObject<XObject>(
kernel_state(), kernel_memory()->TranslateVirtual(native_ptr));
if (object) {
object->Release();
object->ReleaseHandle();
}
return 0;

View File

@ -141,7 +141,6 @@ dword_result_t ExCreateThread(lpdword_t handle_ptr, dword_t stack_size,
// TODO(Gliniak): Temporary solution, requires more research // && !stack_size
*handle_ptr = thread->handle();
} else {
thread->RetainHandle();
*handle_ptr = thread->handle();
}
}

View File

@ -49,6 +49,7 @@ XObject::XObject(KernelState* kernel_state, Type type)
}
XObject::~XObject() {
assert_true(handles_.empty());
assert_zero(pointer_ref_count_);
if (allocated_guest_object_) {

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -366,7 +366,7 @@ X_STATUS XThread::Create() {
InitializeGuestObject();
// Always retain when starting - the thread owns itself until exited.
Retain();
RetainHandle();
xe::threading::Thread::CreationParameters params;
params.stack_size = 16 * 1024 * 1024; // Allocate a big host stack.
@ -407,7 +407,7 @@ X_STATUS XThread::Create() {
xe::Profiler::ThreadExit();
// Release the self-reference to the thread.
Release();
ReleaseHandle();
});
if (!thread_) {
@ -466,7 +466,7 @@ X_STATUS XThread::Exit(int exit_code) {
xe::Profiler::ThreadExit();
running_ = false;
Release();
ReleaseHandle();
// NOTE: this does not return!
xe::threading::Thread::Exit(exit_code);
@ -486,11 +486,11 @@ X_STATUS XThread::Terminate(int exit_code) {
running_ = false;
if (XThread::IsInThread(this)) {
Release();
ReleaseHandle();
xe::threading::Thread::Exit(exit_code);
} else {
thread_->Terminate(exit_code);
Release();
ReleaseHandle();
}
return X_STATUS_SUCCESS;
@ -823,10 +823,6 @@ struct ThreadSavedState {
bool is_main_thread; // Is this the main thread?
bool is_running;
// Clock settings (invalid if not running)
uint64_t tick_count_;
uint64_t system_time_;
uint32_t apc_head;
uint32_t tls_static_address;
uint32_t tls_dynamic_address;
@ -895,10 +891,6 @@ bool XThread::Save(ByteStream* stream) {
state.stack_alloc_size = stack_alloc_size_;
if (running_) {
state.tick_count_ = Clock::QueryGuestTickCount();
state.system_time_ =
Clock::QueryGuestSystemTime() - Clock::guest_system_time_base();
// Context information
auto context = thread_state_->context();
state.context.lr = context->lr;
@ -993,7 +985,7 @@ object_ref<XThread> XThread::Restore(KernelState* kernel_state,
context->vscr_sat = state.context.vscr_sat;
// Always retain when starting - the thread owns itself until exited.
thread->Retain();
thread->RetainHandle();
xe::threading::Thread::CreationParameters params;
params.create_suspended = true; // Not done restoring yet.
@ -1008,10 +1000,6 @@ object_ref<XThread> XThread::Restore(KernelState* kernel_state,
// Profiler needs to know about the thread.
xe::Profiler::ThreadEnter(thread->name().c_str());
// Setup the time now that we're in the thread.
Clock::SetGuestTickCount(state.tick_count_);
Clock::SetGuestSystemTime(state.system_time_);
current_xthread_tls_ = thread;
current_thread_ = thread;
@ -1035,7 +1023,7 @@ object_ref<XThread> XThread::Restore(KernelState* kernel_state,
xe::Profiler::ThreadExit();
// Release the self-reference to the thread.
thread->Release();
thread->ReleaseHandle();
});
// Notify processor we were recreated.

View File

@ -1355,6 +1355,11 @@ bool PhysicalHeap::Alloc(uint32_t size, uint32_t alignment,
// TODO(benvanik): don't leak parent memory.
return false;
}
if (protect & kMemoryProtectWrite) {
TriggerWatches(address, size, true, true, false);
}
*out_address = address;
return true;
}
@ -1392,6 +1397,10 @@ bool PhysicalHeap::AllocFixed(uint32_t base_address, uint32_t size,
return false;
}
if (protect & kMemoryProtectWrite) {
TriggerWatches(address, size, true, true, false);
}
return true;
}
@ -1432,6 +1441,11 @@ bool PhysicalHeap::AllocRange(uint32_t low_address, uint32_t high_address,
// TODO(benvanik): don't leak parent memory.
return false;
}
if (protect & kMemoryProtectWrite) {
TriggerWatches(address, size, true, true, false);
}
*out_address = address;
return true;
}
@ -1449,17 +1463,10 @@ bool PhysicalHeap::Decommit(uint32_t address, uint32_t size) {
bool PhysicalHeap::Release(uint32_t base_address, uint32_t* out_region_size) {
auto global_lock = global_critical_region_.Acquire();
uint32_t parent_base_address = GetPhysicalAddress(base_address);
uint32_t region_size = 0;
if (QuerySize(base_address, &region_size)) {
TriggerWatches(base_address, region_size, true, true,
!cvars::protect_on_release);
}
if (!parent_heap_->Release(parent_base_address, out_region_size)) {
XELOGE("PhysicalHeap::Release failed due to parent heap failure");
return false;
}
return BaseHeap::Release(base_address, out_region_size);
}
@ -1467,7 +1474,11 @@ bool PhysicalHeap::Protect(uint32_t address, uint32_t size, uint32_t protect,
uint32_t* old_protect) {
auto global_lock = global_critical_region_.Acquire();
TriggerWatches(address, size, true, true, false);
// Only invalidate if making writable again, for simplicity - not when simply
// marking some range as immutable, for instance.
if (protect & kMemoryProtectWrite) {
TriggerWatches(address, size, true, true, false);
}
if (!parent_heap_->Protect(GetPhysicalAddress(address), size, protect,
old_protect)) {

View File

@ -363,15 +363,15 @@ class Memory {
// triggered multiple times for a single range, and for any watched page every
// registered callbacks is triggered. This is a very simple one-shot method
// for use primarily for cache invalidation - there may be spurious firing,
// for example, if the game only changes the protection level without writing
// anything.
// for example, if the game only makes the pages writable without actually
// writing anything (done for simplicity).
//
// A range of pages can be watched at any time, but pages are only unwatched
// when watches are triggered (since multiple subscribers can depend on the
// same memory, and one subscriber shouldn't interfere with another).
//
// Callbacks can be triggered for one page (if the guest just stores words) or
// for multiple pages (for file reading, protection level changes).
// for multiple pages (for file reading, making pages writable).
//
// Only guest physical memory mappings are watched - the host-only mapping is
// not protected so it can be used to bypass the write protection (for file
@ -392,11 +392,12 @@ class Memory {
// Enables watching of the specified memory range, snapped to system page
// boundaries. When something is written to a watched range (or when the
// protection of it changes), the registered watch callbacks are triggered for
// the page (or pages, for file reads and protection changes) where something
// has been written to. This protects physical memory only under
// virtual_membase_, so writing to physical_membase_ can be done to bypass the
// protection placed by the watches.
// protection of it changes in a a way that it becomes writable), the
// registered watch callbacks are triggered for the page (or pages, for file
// reads and protection changes) where something has been written to. This
// protects physical memory only under virtual_membase_, so writing to
// physical_membase_ can be done to bypass the protection placed by the
// watches.
void WatchPhysicalMemoryWrite(uint32_t physical_address, uint32_t length);
// Forces triggering of watch callbacks for a virtual address range if pages

View File

@ -1,81 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2018 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/ui/d3d12/command_list.h"
#include "xenia/base/logging.h"
namespace xe {
namespace ui {
namespace d3d12 {
std::unique_ptr<CommandList> CommandList::Create(ID3D12Device* device,
ID3D12CommandQueue* queue,
D3D12_COMMAND_LIST_TYPE type) {
std::unique_ptr<CommandList> command_list(
new CommandList(device, queue, type));
if (!command_list->Initialize()) {
return nullptr;
}
return command_list;
}
CommandList::CommandList(ID3D12Device* device, ID3D12CommandQueue* queue,
D3D12_COMMAND_LIST_TYPE type)
: device_(device), queue_(queue), type_(type) {}
CommandList::~CommandList() {
if (command_list_1_ != nullptr) {
command_list_1_->Release();
}
if (command_list_ != nullptr) {
command_list_->Release();
}
if (command_allocator_ != nullptr) {
command_allocator_->Release();
}
}
bool CommandList::Initialize() {
if (FAILED(device_->CreateCommandAllocator(
type_, IID_PPV_ARGS(&command_allocator_)))) {
XELOGE("Failed to create a command allocator");
return false;
}
if (FAILED(device_->CreateCommandList(0, type_, command_allocator_, nullptr,
IID_PPV_ARGS(&command_list_)))) {
XELOGE("Failed to create a graphics command list");
command_allocator_->Release();
command_allocator_ = nullptr;
return false;
}
// Optional - added in Creators Update (SDK 10.0.15063.0).
command_list_->QueryInterface(IID_PPV_ARGS(&command_list_1_));
// A command list is initially open, need to close it before resetting.
command_list_->Close();
return true;
}
ID3D12GraphicsCommandList* CommandList::BeginRecording() {
command_allocator_->Reset();
command_list_->Reset(command_allocator_, nullptr);
return command_list_;
}
void CommandList::AbortRecording() { command_list_->Close(); }
void CommandList::Execute() {
command_list_->Close();
ID3D12CommandList* execute_lists[] = {command_list_};
queue_->ExecuteCommandLists(1, execute_lists);
}
} // namespace d3d12
} // namespace ui
} // namespace xe

View File

@ -1,56 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2018 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_D3D12_COMMAND_LIST_H_
#define XENIA_UI_D3D12_COMMAND_LIST_H_
#include <memory>
#include "xenia/ui/d3d12/d3d12_api.h"
namespace xe {
namespace ui {
namespace d3d12 {
class CommandList {
public:
~CommandList();
static std::unique_ptr<CommandList> Create(ID3D12Device* device,
ID3D12CommandQueue* queue,
D3D12_COMMAND_LIST_TYPE type);
ID3D12GraphicsCommandList* GetCommandList() const { return command_list_; }
ID3D12GraphicsCommandList1* GetCommandList1() const {
return command_list_1_;
}
ID3D12GraphicsCommandList* BeginRecording();
void AbortRecording();
void Execute();
protected:
CommandList(ID3D12Device* device, ID3D12CommandQueue* queue,
D3D12_COMMAND_LIST_TYPE type);
bool Initialize();
ID3D12Device* device_;
ID3D12CommandQueue* queue_;
D3D12_COMMAND_LIST_TYPE type_;
ID3D12CommandAllocator* command_allocator_ = nullptr;
ID3D12GraphicsCommandList* command_list_ = nullptr;
ID3D12GraphicsCommandList1* command_list_1_ = nullptr;
};
} // namespace d3d12
} // namespace ui
} // namespace xe
#endif // XENIA_UI_D3D12_CPU_FENCE_H_

View File

@ -1,75 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2018 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/ui/d3d12/cpu_fence.h"
#include "xenia/base/logging.h"
namespace xe {
namespace ui {
namespace d3d12 {
std::unique_ptr<CPUFence> CPUFence::Create(ID3D12Device* device,
ID3D12CommandQueue* queue) {
std::unique_ptr<CPUFence> fence(new CPUFence(device, queue));
if (!fence->Initialize()) {
return nullptr;
}
return fence;
}
CPUFence::CPUFence(ID3D12Device* device, ID3D12CommandQueue* queue)
: device_(device), queue_(queue) {}
CPUFence::~CPUFence() {
// First destroying the fence because it may reference the event.
if (fence_ != nullptr) {
fence_->Release();
}
if (completion_event_ != nullptr) {
CloseHandle(completion_event_);
}
}
bool CPUFence::Initialize() {
if (FAILED(device_->CreateFence(0, D3D12_FENCE_FLAG_NONE,
IID_PPV_ARGS(&fence_)))) {
XELOGE("Failed to create a fence");
return false;
}
completion_event_ = CreateEvent(nullptr, false, false, nullptr);
if (completion_event_ == nullptr) {
XELOGE("Failed to create a fence completion event");
fence_->Release();
fence_ = nullptr;
return false;
}
queued_value_ = 0;
return true;
}
void CPUFence::Enqueue() {
++queued_value_;
queue_->Signal(fence_, queued_value_);
}
bool CPUFence::IsCompleted() {
return fence_->GetCompletedValue() >= queued_value_;
}
void CPUFence::Await() {
if (fence_->GetCompletedValue() < queued_value_) {
fence_->SetEventOnCompletion(queued_value_, completion_event_);
WaitForSingleObject(completion_event_, INFINITE);
}
}
} // namespace d3d12
} // namespace ui
} // namespace xe

View File

@ -1,52 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2018 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_D3D12_CPU_FENCE_H_
#define XENIA_UI_D3D12_CPU_FENCE_H_
#include <memory>
#include "xenia/ui/d3d12/d3d12_api.h"
namespace xe {
namespace ui {
namespace d3d12 {
class CPUFence {
public:
~CPUFence();
static std::unique_ptr<CPUFence> Create(ID3D12Device* device,
ID3D12CommandQueue* queue);
// Submits the fence to the GPU command queue.
void Enqueue();
// Immediately returns whether the GPU has reached the fence.
bool IsCompleted();
// Blocks until the fence has been reached.
void Await();
private:
CPUFence(ID3D12Device* device, ID3D12CommandQueue* queue);
bool Initialize();
ID3D12Device* device_;
ID3D12CommandQueue* queue_;
ID3D12Fence* fence_ = nullptr;
HANDLE completion_event_ = nullptr;
uint64_t queued_value_ = 0;
};
} // namespace d3d12
} // namespace ui
} // namespace xe
#endif // XENIA_UI_D3D12_CPU_FENCE_H_

View File

@ -16,6 +16,7 @@
#include "xenia/base/math.h"
#include "xenia/ui/d3d12/d3d12_immediate_drawer.h"
#include "xenia/ui/d3d12/d3d12_provider.h"
#include "xenia/ui/d3d12/d3d12_util.h"
#include "xenia/ui/window.h"
DEFINE_bool(d3d12_random_clear_color, false,
@ -25,6 +26,9 @@ namespace xe {
namespace ui {
namespace d3d12 {
constexpr uint32_t D3D12Context::kSwapCommandAllocatorCount;
constexpr uint32_t D3D12Context::kSwapChainBufferCount;
D3D12Context::D3D12Context(D3D12Provider* provider, Window* target_window)
: GraphicsContext(provider, target_window) {}
@ -38,23 +42,24 @@ bool D3D12Context::Initialize() {
context_lost_ = false;
current_frame_ = 1;
// No frames have been completed yet.
last_completed_frame_ = 0;
// Keep in sync with the modulo because why not.
current_queue_frame_ = 1;
// Create fences for synchronization of reuse and destruction of transient
// objects (like command lists) and for global shutdown.
for (uint32_t i = 0; i < kQueuedFrames; ++i) {
fences_[i] = CPUFence::Create(device, direct_queue);
if (fences_[i] == nullptr) {
if (target_window_) {
swap_fence_current_value_ = 1;
swap_fence_completed_value_ = 0;
swap_fence_completion_event_ = CreateEvent(nullptr, false, false, nullptr);
if (swap_fence_completion_event_ == nullptr) {
XELOGE("Failed to create the composition fence completion event");
Shutdown();
return false;
}
// Create a fence for transient resources of compositing.
if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE,
IID_PPV_ARGS(&swap_fence_)))) {
XELOGE("Failed to create the composition fence");
Shutdown();
return false;
}
}
if (target_window_) {
// Create the swap chain.
swap_chain_width_ = target_window_->scaled_width();
swap_chain_height_ = target_window_->scaled_height();
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc;
@ -108,15 +113,25 @@ bool D3D12Context::Initialize() {
return false;
}
// Create command lists for compositing.
for (uint32_t i = 0; i < kQueuedFrames; ++i) {
swap_command_lists_[i] = CommandList::Create(
device, direct_queue, D3D12_COMMAND_LIST_TYPE_DIRECT);
if (swap_command_lists_[i] == nullptr) {
// Create the command list for compositing.
for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) {
if (FAILED(device->CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE_DIRECT,
IID_PPV_ARGS(&swap_command_allocators_[i])))) {
XELOGE("Failed to create a composition command allocator");
Shutdown();
return false;
}
}
if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
swap_command_allocators_[0], nullptr,
IID_PPV_ARGS(&swap_command_list_)))) {
XELOGE("Failed to create the composition graphics command list");
Shutdown();
return false;
}
// Initially in open state, wait until BeginSwap.
swap_command_list_->Close();
// Initialize the immediate mode drawer if not offscreen.
immediate_drawer_ = std::make_unique<D3D12ImmediateDrawer>(this);
@ -126,7 +141,6 @@ bool D3D12Context::Initialize() {
}
}
initialized_fully_ = true;
return true;
}
@ -159,39 +173,53 @@ bool D3D12Context::InitializeSwapChainBuffers() {
}
void D3D12Context::Shutdown() {
if (initialized_fully_ && !context_lost_) {
AwaitAllFramesCompletion();
if (!target_window_) {
return;
}
initialized_fully_ = false;
if (!context_lost_ && swap_fence_ &&
swap_fence_->GetCompletedValue() + 1 < swap_fence_current_value_) {
swap_fence_->SetEventOnCompletion(swap_fence_current_value_ - 1,
swap_fence_completion_event_);
WaitForSingleObject(swap_fence_completion_event_, INFINITE);
}
immediate_drawer_.reset();
if (swap_chain_ != nullptr) {
for (uint32_t i = 0; i < kQueuedFrames; ++i) {
swap_command_lists_[i].reset();
util::ReleaseAndNull(swap_command_list_);
for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) {
auto& swap_command_allocator = swap_command_allocators_[i];
if (!swap_command_allocator) {
break;
}
swap_command_allocator->Release();
swap_command_allocator = nullptr;
}
if (swap_chain_) {
for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) {
auto& buffer = swap_chain_buffers_[i];
if (buffer == nullptr) {
auto& swap_chain_buffer = swap_chain_buffers_[i];
if (!swap_chain_buffer) {
break;
}
buffer->Release();
buffer = nullptr;
swap_chain_buffer->Release();
swap_chain_buffer = nullptr;
}
if (swap_chain_rtv_heap_ != nullptr) {
swap_chain_rtv_heap_->Release();
swap_chain_rtv_heap_ = nullptr;
}
util::ReleaseAndNull(swap_chain_rtv_heap_);
swap_chain_->Release();
swap_chain_ = nullptr;
}
for (uint32_t i = 0; i < kQueuedFrames; ++i) {
fences_[i].reset();
// First release the fence since it may reference the event.
util::ReleaseAndNull(swap_fence_);
if (swap_fence_completion_event_) {
CloseHandle(swap_fence_completion_event_);
swap_fence_completion_event_ = nullptr;
}
swap_fence_current_value_ = 1;
swap_fence_completed_value_ = 0;
}
ImmediateDrawer* D3D12Context::immediate_drawer() {
@ -205,119 +233,127 @@ bool D3D12Context::MakeCurrent() { return true; }
void D3D12Context::ClearCurrent() {}
void D3D12Context::BeginSwap() {
if (context_lost_) {
if (!target_window_ || context_lost_) {
return;
}
// Await the availability of transient objects for the new frame.
// The frame number is incremented in EndSwap so it can be treated the same
// way both when inside a frame and when outside of it (it's tied to actual
// submissions).
fences_[current_queue_frame_]->Await();
// Update the completed frame if didn't explicitly await all queued frames.
if (last_completed_frame_ + kQueuedFrames < current_frame_) {
last_completed_frame_ = current_frame_ - kQueuedFrames;
}
if (target_window_ != nullptr) {
// Resize the swap chain if the window is resized.
uint32_t target_window_width = target_window_->scaled_width();
uint32_t target_window_height = target_window_->scaled_height();
if (swap_chain_width_ != target_window_width ||
swap_chain_height_ != target_window_height) {
// Await the completion of swap chain use.
// Context loss is also faked if resizing fails. In this case, before the
// context is shut down to be recreated, frame completion must be awaited
// (this isn't done if the context is truly lost).
AwaitAllFramesCompletion();
// All buffer references must be released before resizing.
for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) {
swap_chain_buffers_[i]->Release();
swap_chain_buffers_[i] = nullptr;
}
if (FAILED(swap_chain_->ResizeBuffers(
kSwapChainBufferCount, target_window_width, target_window_height,
kSwapChainFormat, 0))) {
context_lost_ = true;
return;
}
swap_chain_width_ = target_window_width;
swap_chain_height_ = target_window_height;
if (!InitializeSwapChainBuffers()) {
context_lost_ = true;
return;
}
// Resize the swap chain if the window is resized.
uint32_t target_window_width = target_window_->scaled_width();
uint32_t target_window_height = target_window_->scaled_height();
if (swap_chain_width_ != target_window_width ||
swap_chain_height_ != target_window_height) {
// Await the completion of swap chain use.
// Context loss is also faked if resizing fails. In this case, before the
// context is shut down to be recreated, frame completion must be awaited
// (this isn't done if the context is truly lost).
if (swap_fence_completed_value_ + 1 < swap_fence_current_value_) {
swap_fence_->SetEventOnCompletion(swap_fence_current_value_ - 1,
swap_fence_completion_event_);
WaitForSingleObject(swap_fence_completion_event_, INFINITE);
swap_fence_completed_value_ = swap_fence_current_value_ - 1;
}
// Bind the back buffer as a render target and clear it.
auto command_list = swap_command_lists_[current_queue_frame_].get();
auto graphics_command_list = command_list->BeginRecording();
D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource =
swap_chain_buffers_[swap_chain_back_buffer_index_];
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
graphics_command_list->ResourceBarrier(1, &barrier);
D3D12_CPU_DESCRIPTOR_HANDLE back_buffer_rtv = GetSwapChainBackBufferRTV();
graphics_command_list->OMSetRenderTargets(1, &back_buffer_rtv, TRUE,
nullptr);
float clear_color[4];
if (cvars::d3d12_random_clear_color) {
clear_color[0] =
rand() / float(RAND_MAX); // NOLINT(runtime/threadsafe_fn)
clear_color[1] = 1.0f;
clear_color[2] = 0.0f;
} else {
clear_color[0] = 238.0f / 255.0f;
clear_color[1] = 238.0f / 255.0f;
clear_color[2] = 238.0f / 255.0f;
// All buffer references must be released before resizing.
for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) {
swap_chain_buffers_[i]->Release();
swap_chain_buffers_[i] = nullptr;
}
clear_color[3] = 1.0f;
graphics_command_list->ClearRenderTargetView(back_buffer_rtv, clear_color,
0, nullptr);
}
}
void D3D12Context::EndSwap() {
if (context_lost_) {
return;
}
if (target_window_ != nullptr) {
// Switch the back buffer to presentation state.
auto command_list = swap_command_lists_[current_queue_frame_].get();
auto graphics_command_list = command_list->GetCommandList();
D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource =
swap_chain_buffers_[swap_chain_back_buffer_index_];
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
graphics_command_list->ResourceBarrier(1, &barrier);
command_list->Execute();
// Present and check if the context was lost.
HRESULT result = swap_chain_->Present(0, 0);
if (result == DXGI_ERROR_DEVICE_RESET ||
result == DXGI_ERROR_DEVICE_REMOVED) {
if (FAILED(swap_chain_->ResizeBuffers(
kSwapChainBufferCount, target_window_width, target_window_height,
kSwapChainFormat, 0))) {
context_lost_ = true;
return;
}
swap_chain_width_ = target_window_width;
swap_chain_height_ = target_window_height;
if (!InitializeSwapChainBuffers()) {
context_lost_ = true;
return;
}
// Get the back buffer index for the next frame.
swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex();
}
// Go to the next transient object frame.
fences_[current_queue_frame_]->Enqueue();
++current_queue_frame_;
if (current_queue_frame_ >= kQueuedFrames) {
current_queue_frame_ -= kQueuedFrames;
// Wait for a swap command allocator to become free.
// Command allocator 0 is used when swap_fence_current_value_ is 1, 4, 7...
swap_fence_completed_value_ = swap_fence_->GetCompletedValue();
if (swap_fence_completed_value_ + kSwapCommandAllocatorCount <
swap_fence_current_value_) {
swap_fence_->SetEventOnCompletion(
swap_fence_current_value_ - kSwapCommandAllocatorCount,
swap_fence_completion_event_);
WaitForSingleObject(swap_fence_completion_event_, INFINITE);
swap_fence_completed_value_ = swap_fence_->GetCompletedValue();
}
++current_frame_;
// Start the command list.
uint32_t command_allocator_index =
uint32_t((swap_fence_current_value_ + (kSwapCommandAllocatorCount - 1)) %
kSwapCommandAllocatorCount);
auto command_allocator = swap_command_allocators_[command_allocator_index];
command_allocator->Reset();
swap_command_list_->Reset(command_allocator, nullptr);
// Bind the back buffer as a render target and clear it.
D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource =
swap_chain_buffers_[swap_chain_back_buffer_index_];
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
swap_command_list_->ResourceBarrier(1, &barrier);
D3D12_CPU_DESCRIPTOR_HANDLE back_buffer_rtv = GetSwapChainBackBufferRTV();
swap_command_list_->OMSetRenderTargets(1, &back_buffer_rtv, TRUE, nullptr);
float clear_color[4];
if (cvars::d3d12_random_clear_color) {
clear_color[0] = rand() / float(RAND_MAX); // NOLINT(runtime/threadsafe_fn)
clear_color[1] = 1.0f;
clear_color[2] = 0.0f;
} else {
clear_color[0] = 238.0f / 255.0f;
clear_color[1] = 238.0f / 255.0f;
clear_color[2] = 238.0f / 255.0f;
}
clear_color[3] = 1.0f;
swap_command_list_->ClearRenderTargetView(back_buffer_rtv, clear_color, 0,
nullptr);
}
void D3D12Context::EndSwap() {
if (!target_window_ || context_lost_) {
return;
}
auto direct_queue = GetD3D12Provider()->GetDirectQueue();
// Switch the back buffer to presentation state.
D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource =
swap_chain_buffers_[swap_chain_back_buffer_index_];
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
swap_command_list_->ResourceBarrier(1, &barrier);
// Submit the command list.
swap_command_list_->Close();
ID3D12CommandList* execute_command_lists[] = {swap_command_list_};
direct_queue->ExecuteCommandLists(1, execute_command_lists);
// Present and check if the context was lost.
HRESULT result = swap_chain_->Present(0, 0);
if (result == DXGI_ERROR_DEVICE_RESET ||
result == DXGI_ERROR_DEVICE_REMOVED) {
context_lost_ = true;
return;
}
// Signal the fence to wait for frame resources to become free again.
direct_queue->Signal(swap_fence_, swap_fence_current_value_++);
// Get the back buffer index for the next frame.
swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex();
}
std::unique_ptr<RawImage> D3D12Context::Capture() {
@ -325,19 +361,6 @@ std::unique_ptr<RawImage> D3D12Context::Capture() {
return nullptr;
}
void D3D12Context::AwaitAllFramesCompletion() {
// Await the last frame since previous frames must be completed before it.
if (context_lost_) {
return;
}
uint32_t await_frame = current_queue_frame_ + (kQueuedFrames - 1);
if (await_frame >= kQueuedFrames) {
await_frame -= kQueuedFrames;
}
fences_[await_frame]->Await();
last_completed_frame_ = current_frame_ - 1;
}
D3D12_CPU_DESCRIPTOR_HANDLE D3D12Context::GetSwapChainBufferRTV(
uint32_t buffer_index) const {
return GetD3D12Provider()->OffsetRTVDescriptor(swap_chain_rtv_heap_start_,

View File

@ -12,8 +12,6 @@
#include <memory>
#include "xenia/ui/d3d12/command_list.h"
#include "xenia/ui/d3d12/cpu_fence.h"
#include "xenia/ui/d3d12/d3d12_immediate_drawer.h"
#include "xenia/ui/d3d12/d3d12_provider.h"
#include "xenia/ui/graphics_context.h"
@ -45,16 +43,6 @@ class D3D12Context : public GraphicsContext {
return static_cast<D3D12Provider*>(provider_);
}
// The count of copies of transient objects (like command lists, dynamic
// descriptor heaps) that must be kept when rendering with this context.
static constexpr uint32_t kQueuedFrames = 3;
// The current absolute frame number.
uint64_t GetCurrentFrame() { return current_frame_; }
// The last completed frame - it's fine to destroy objects used in it.
uint64_t GetLastCompletedFrame() { return last_completed_frame_; }
uint32_t GetCurrentQueueFrame() { return current_queue_frame_; }
void AwaitAllFramesCompletion();
static constexpr DXGI_FORMAT kSwapChainFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
ID3D12Resource* GetSwapChainBuffer(uint32_t buffer_index) const {
return swap_chain_buffers_[buffer_index];
@ -71,8 +59,15 @@ class D3D12Context : public GraphicsContext {
width = swap_chain_width_;
height = swap_chain_height_;
}
// Inside the current BeginSwap/EndSwap pair.
uint64_t GetSwapCurrentFenceValue() const {
return swap_fence_current_value_;
}
uint64_t GetSwapCompletedFenceValue() const {
return swap_fence_completed_value_;
}
ID3D12GraphicsCommandList* GetSwapCommandList() const {
return swap_command_lists_[current_queue_frame_]->GetCommandList();
return swap_command_list_;
}
private:
@ -85,15 +80,8 @@ class D3D12Context : public GraphicsContext {
bool InitializeSwapChainBuffers();
void Shutdown();
bool initialized_fully_ = false;
bool context_lost_ = false;
uint64_t current_frame_ = 1;
uint64_t last_completed_frame_ = 0;
uint32_t current_queue_frame_ = 1;
std::unique_ptr<CPUFence> fences_[kQueuedFrames] = {};
static constexpr uint32_t kSwapChainBufferCount = 3;
IDXGISwapChain3* swap_chain_ = nullptr;
uint32_t swap_chain_width_ = 0, swap_chain_height_ = 0;
@ -101,7 +89,19 @@ class D3D12Context : public GraphicsContext {
uint32_t swap_chain_back_buffer_index_ = 0;
ID3D12DescriptorHeap* swap_chain_rtv_heap_ = nullptr;
D3D12_CPU_DESCRIPTOR_HANDLE swap_chain_rtv_heap_start_;
std::unique_ptr<CommandList> swap_command_lists_[kQueuedFrames] = {};
uint64_t swap_fence_current_value_ = 1;
uint64_t swap_fence_completed_value_ = 0;
HANDLE swap_fence_completion_event_ = nullptr;
ID3D12Fence* swap_fence_ = nullptr;
static constexpr uint32_t kSwapCommandAllocatorCount = 3;
ID3D12CommandAllocator* swap_command_allocators_[kSwapCommandAllocatorCount] =
{};
// Current command allocator is:
// ((swap_fence_current_value_ + (kSwapCommandAllocatorCount - 1))) %
// kSwapCommandAllocatorCount.
ID3D12GraphicsCommandList* swap_command_list_ = nullptr;
std::unique_ptr<D3D12ImmediateDrawer> immediate_drawer_ = nullptr;
};

View File

@ -287,9 +287,10 @@ bool D3D12ImmediateDrawer::Initialize() {
// Create pools for draws.
vertex_buffer_pool_ =
std::make_unique<UploadBufferPool>(context_, 2 * 1024 * 1024);
std::make_unique<UploadBufferPool>(device, 2 * 1024 * 1024);
texture_descriptor_pool_ = std::make_unique<DescriptorHeapPool>(
context_, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2048);
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 2048);
texture_descriptor_pool_heap_index_ = DescriptorHeapPool::kHeapIndexInvalid;
// Reset the current state.
current_command_list_ = nullptr;
@ -398,7 +399,7 @@ void D3D12ImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
&location_source, nullptr);
SubmittedTextureUpload submitted_upload;
submitted_upload.buffer = buffer;
submitted_upload.frame = context_->GetCurrentFrame();
submitted_upload.fence_value = context_->GetSwapCurrentFenceValue();
texture_uploads_submitted_.push_back(submitted_upload);
} else {
// Defer uploading to the next frame when there's a command list.
@ -416,14 +417,14 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
// Use the compositing command list.
current_command_list_ = context_->GetSwapCommandList();
uint64_t current_frame = context_->GetCurrentFrame();
uint64_t last_completed_frame = context_->GetLastCompletedFrame();
uint64_t completed_fence_value = context_->GetSwapCompletedFenceValue();
uint64_t current_fence_value = context_->GetSwapCurrentFenceValue();
// Remove temporary buffers for completed texture uploads.
auto erase_uploads_end = texture_uploads_submitted_.begin();
while (erase_uploads_end != texture_uploads_submitted_.end()) {
uint64_t upload_frame = erase_uploads_end->frame;
if (upload_frame > last_completed_frame) {
uint64_t upload_fence_value = erase_uploads_end->fence_value;
if (upload_fence_value > completed_fence_value) {
++erase_uploads_end;
break;
}
@ -455,14 +456,14 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
&location_source, nullptr);
SubmittedTextureUpload submitted_upload;
submitted_upload.buffer = pending_upload.buffer;
submitted_upload.frame = current_frame;
submitted_upload.fence_value = current_fence_value;
texture_uploads_submitted_.push_back(submitted_upload);
texture_uploads_pending_.pop_back();
}
vertex_buffer_pool_->BeginFrame();
texture_descriptor_pool_->BeginFrame();
texture_descriptor_pool_full_update_ = 0;
vertex_buffer_pool_->Reclaim(completed_fence_value);
texture_descriptor_pool_->Reclaim(completed_fence_value);
texture_descriptor_pool_heap_index_ = DescriptorHeapPool::kHeapIndexInvalid;
current_render_target_width_ = render_target_width;
current_render_target_height_ = render_target_height;
@ -492,6 +493,7 @@ void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
if (current_command_list_ == nullptr) {
return;
}
uint64_t current_fence_value = context_->GetSwapCurrentFenceValue();
batch_open_ = false;
@ -500,8 +502,8 @@ void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
vertex_buffer_view.StrideInBytes = UINT(sizeof(ImmediateVertex));
vertex_buffer_view.SizeInBytes =
batch.vertex_count * uint32_t(sizeof(ImmediateVertex));
void* vertex_buffer_mapping = vertex_buffer_pool_->RequestFull(
vertex_buffer_view.SizeInBytes, nullptr, nullptr,
void* vertex_buffer_mapping = vertex_buffer_pool_->Request(
current_fence_value, vertex_buffer_view.SizeInBytes, nullptr, nullptr,
&vertex_buffer_view.BufferLocation);
if (vertex_buffer_mapping == nullptr) {
XELOGE("Failed to get a buffer for %u vertices in the immediate drawer",
@ -518,7 +520,8 @@ void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
D3D12_INDEX_BUFFER_VIEW index_buffer_view;
index_buffer_view.SizeInBytes = batch.index_count * sizeof(uint16_t);
index_buffer_view.Format = DXGI_FORMAT_R16_UINT;
void* index_buffer_mapping = vertex_buffer_pool_->RequestFull(
void* index_buffer_mapping = vertex_buffer_pool_->Request(
current_fence_value,
xe::align(index_buffer_view.SizeInBytes, UINT(sizeof(uint32_t))),
nullptr, nullptr, &index_buffer_view.BufferLocation);
if (index_buffer_mapping == nullptr) {
@ -560,15 +563,15 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
}
bool bind_texture = current_texture_ != texture;
uint32_t texture_descriptor_index;
uint64_t texture_full_update = texture_descriptor_pool_->Request(
texture_descriptor_pool_full_update_, bind_texture ? 1 : 0, 1,
texture_descriptor_index);
if (texture_full_update == 0) {
uint64_t texture_heap_index = texture_descriptor_pool_->Request(
context_->GetSwapCurrentFenceValue(), texture_descriptor_pool_heap_index_,
bind_texture ? 1 : 0, 1, texture_descriptor_index);
if (texture_heap_index == DescriptorHeapPool::kHeapIndexInvalid) {
return;
}
if (texture_descriptor_pool_full_update_ != texture_full_update) {
if (texture_descriptor_pool_heap_index_ != texture_heap_index) {
bind_texture = true;
texture_descriptor_pool_full_update_ = texture_full_update;
texture_descriptor_pool_heap_index_ = texture_heap_index;
ID3D12DescriptorHeap* descriptor_heaps[] = {
texture_descriptor_pool_->GetLastRequestHeap(), sampler_heap_};
current_command_list_->SetDescriptorHeaps(2, descriptor_heaps);
@ -672,12 +675,7 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
void D3D12ImmediateDrawer::EndDrawBatch() { batch_open_ = false; }
void D3D12ImmediateDrawer::End() {
texture_descriptor_pool_->EndFrame();
vertex_buffer_pool_->EndFrame();
current_command_list_ = nullptr;
}
void D3D12ImmediateDrawer::End() { current_command_list_ = nullptr; }
} // namespace d3d12
} // namespace ui

View File

@ -14,7 +14,6 @@
#include <memory>
#include <vector>
#include "xenia/ui/d3d12/command_list.h"
#include "xenia/ui/d3d12/d3d12_api.h"
#include "xenia/ui/d3d12/pools.h"
#include "xenia/ui/immediate_drawer.h"
@ -77,6 +76,7 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
std::unique_ptr<UploadBufferPool> vertex_buffer_pool_ = nullptr;
std::unique_ptr<DescriptorHeapPool> texture_descriptor_pool_ = nullptr;
uint64_t texture_descriptor_pool_heap_index_;
struct PendingTextureUpload {
ImmediateTexture* texture;
@ -86,7 +86,7 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
struct SubmittedTextureUpload {
ID3D12Resource* buffer;
uint64_t frame;
uint64_t fence_value;
};
std::deque<SubmittedTextureUpload> texture_uploads_submitted_;
@ -94,7 +94,6 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
int current_render_target_width_, current_render_target_height_;
bool batch_open_ = false;
bool batch_has_index_buffer_;
uint64_t texture_descriptor_pool_full_update_;
D3D_PRIMITIVE_TOPOLOGY current_primitive_topology_;
ImmediateTexture* current_texture_;
SamplerIndex current_sampler_index_;

View File

@ -13,251 +13,208 @@
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/ui/d3d12/d3d12_context.h"
#include "xenia/ui/d3d12/d3d12_util.h"
namespace xe {
namespace ui {
namespace d3d12 {
UploadBufferPool::UploadBufferPool(D3D12Context* context, uint32_t page_size)
: context_(context), page_size_(page_size) {}
UploadBufferPool::UploadBufferPool(ID3D12Device* device, uint32_t page_size)
: device_(device), page_size_(page_size) {}
UploadBufferPool::~UploadBufferPool() {
// Allow mid-frame destruction in cases like device loss.
if (current_mapping_ != nullptr) {
// Don't care about the written range - destroying anyway.
D3D12_RANGE written_range;
written_range.Begin = 0;
written_range.End = 0;
unsent_->buffer->Unmap(0, &written_range);
current_mapping_ = nullptr;
}
current_size_ = 0;
ClearCache();
}
UploadBufferPool::~UploadBufferPool() { ClearCache(); }
void UploadBufferPool::BeginFrame() {
// Recycle submitted pages not used by the GPU anymore.
uint64_t last_completed_frame = context_->GetLastCompletedFrame();
while (sent_first_ != nullptr) {
auto page = sent_first_;
if (page->frame_sent > last_completed_frame) {
void UploadBufferPool::Reclaim(uint64_t completed_submission_index) {
while (submitted_first_) {
if (submitted_first_->last_submission_index > completed_submission_index) {
break;
}
sent_first_ = page->next;
page->next = unsent_;
unsent_ = page;
if (writable_last_) {
writable_last_->next = submitted_first_;
} else {
writable_first_ = submitted_first_;
}
writable_last_ = submitted_first_;
submitted_first_ = submitted_first_->next;
writable_last_->next = nullptr;
}
if (sent_first_ == nullptr) {
sent_last_ = nullptr;
if (!submitted_first_) {
submitted_last_ = nullptr;
}
// Try to create new pages again in this frame if failed in the previous.
page_creation_failed_ = false;
}
void UploadBufferPool::EndFrame() {
// If something is written to the current page, mark it as submitted.
EndPage();
}
void UploadBufferPool::ClearCache() {
assert(current_size_ == 0);
while (unsent_ != nullptr) {
auto next = unsent_->next;
unsent_->buffer->Release();
delete unsent_;
unsent_ = next;
current_page_used_ = 0;
// Deleting anyway, so assuming data not needed anymore.
D3D12_RANGE written_range;
written_range.Begin = 0;
written_range.End = 0;
while (submitted_first_) {
auto next = submitted_first_->next;
submitted_first_->buffer->Unmap(0, &written_range);
submitted_first_->buffer->Release();
delete submitted_first_;
submitted_first_ = next;
}
while (sent_first_ != nullptr) {
auto next = sent_first_->next;
sent_first_->buffer->Release();
delete sent_first_;
sent_first_ = next;
submitted_last_ = nullptr;
while (writable_first_) {
auto next = writable_first_->next;
writable_first_->buffer->Unmap(0, &written_range);
writable_first_->buffer->Release();
delete writable_first_;
writable_first_ = next;
}
sent_last_ = nullptr;
writable_last_ = nullptr;
}
uint8_t* UploadBufferPool::RequestFull(
uint32_t size, ID3D12Resource** buffer_out, uint32_t* offset_out,
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) {
uint8_t* UploadBufferPool::Request(uint64_t submission_index, uint32_t size,
ID3D12Resource** buffer_out,
uint32_t* offset_out,
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) {
assert_true(size <= page_size_);
if (size > page_size_) {
return nullptr;
}
if (page_size_ - current_size_ < size || current_mapping_ == nullptr) {
assert_true(!current_page_used_ ||
submission_index >= writable_first_->last_submission_index);
assert_true(!submitted_last_ ||
submission_index >= submitted_last_->last_submission_index);
if (page_size_ - current_page_used_ < size || !writable_first_) {
// Start a new page if can't fit all the bytes or don't have an open page.
if (!BeginNextPage()) {
return nullptr;
if (writable_first_) {
// Close the page that was current.
if (submitted_last_) {
submitted_last_->next = writable_first_;
} else {
submitted_first_ = writable_first_;
}
submitted_last_ = writable_first_;
writable_first_ = writable_first_->next;
submitted_last_->next = nullptr;
if (!writable_first_) {
writable_last_ = nullptr;
}
}
}
if (buffer_out != nullptr) {
*buffer_out = unsent_->buffer;
}
if (offset_out != nullptr) {
*offset_out = current_size_;
}
if (gpu_address_out != nullptr) {
if (current_gpu_address_ == 0) {
current_gpu_address_ = unsent_->buffer->GetGPUVirtualAddress();
if (!writable_first_) {
// Create a new page if none available.
D3D12_RESOURCE_DESC new_buffer_desc;
util::FillBufferResourceDesc(new_buffer_desc, page_size_,
D3D12_RESOURCE_FLAG_NONE);
ID3D12Resource* new_buffer;
if (FAILED(device_->CreateCommittedResource(
&util::kHeapPropertiesUpload, D3D12_HEAP_FLAG_NONE,
&new_buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
IID_PPV_ARGS(&new_buffer)))) {
XELOGE("Failed to create a D3D upload buffer with %u bytes",
page_size_);
return nullptr;
}
D3D12_RANGE read_range;
read_range.Begin = 0;
read_range.End = 0;
void* new_buffer_mapping;
if (FAILED(new_buffer->Map(0, &read_range, &new_buffer_mapping))) {
XELOGE("Failed to map a D3D upload buffer with %u bytes", page_size_);
new_buffer->Release();
return nullptr;
}
writable_first_ = new Page;
writable_first_->buffer = new_buffer;
writable_first_->gpu_address = new_buffer->GetGPUVirtualAddress();
writable_first_->mapping = new_buffer_mapping;
writable_first_->last_submission_index = submission_index;
writable_first_->next = nullptr;
writable_last_ = writable_first_;
}
*gpu_address_out = current_gpu_address_ + current_size_;
current_page_used_ = 0;
}
uint8_t* mapping = current_mapping_ + current_size_;
current_size_ += size;
writable_first_->last_submission_index = submission_index;
if (buffer_out) {
*buffer_out = writable_first_->buffer;
}
if (offset_out) {
*offset_out = current_page_used_;
}
if (gpu_address_out) {
*gpu_address_out = writable_first_->gpu_address + current_page_used_;
}
uint8_t* mapping =
reinterpret_cast<uint8_t*>(writable_first_->mapping) + current_page_used_;
current_page_used_ += size;
return mapping;
}
uint8_t* UploadBufferPool::RequestPartial(
uint32_t size, ID3D12Resource** buffer_out, uint32_t* offset_out,
uint32_t* size_out, D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) {
if (current_size_ == page_size_ || current_mapping_ == nullptr) {
// Start a new page if can't fit any bytes or don't have an open page.
if (!BeginNextPage()) {
return nullptr;
}
uint64_t submission_index, uint32_t size, ID3D12Resource** buffer_out,
uint32_t* offset_out, uint32_t* size_out,
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out) {
size = std::min(size, page_size_);
if (current_page_used_ < page_size_) {
size = std::min(size, page_size_ - current_page_used_);
}
size = std::min(size, page_size_ - current_size_);
if (buffer_out != nullptr) {
*buffer_out = unsent_->buffer;
uint8_t* mapping =
Request(submission_index, size, buffer_out, offset_out, gpu_address_out);
if (!mapping) {
return nullptr;
}
if (offset_out != nullptr) {
*offset_out = current_size_;
}
if (size_out != nullptr) {
if (size_out) {
*size_out = size;
}
if (gpu_address_out != nullptr) {
if (current_gpu_address_ == 0) {
current_gpu_address_ = unsent_->buffer->GetGPUVirtualAddress();
}
*gpu_address_out = current_gpu_address_ + current_size_;
}
uint8_t* mapping = current_mapping_ + current_size_;
current_size_ += size;
return mapping;
}
void UploadBufferPool::EndPage() {
if (current_mapping_ != nullptr) {
D3D12_RANGE written_range;
written_range.Begin = 0;
written_range.End = current_size_;
unsent_->buffer->Unmap(0, &written_range);
current_mapping_ = nullptr;
}
if (current_size_ != 0) {
auto page = unsent_;
page->frame_sent = context_->GetCurrentFrame();
unsent_ = page->next;
page->next = nullptr;
if (sent_last_ != nullptr) {
sent_last_->next = page;
} else {
sent_first_ = page;
}
sent_last_ = page;
current_size_ = 0;
}
}
constexpr uint64_t DescriptorHeapPool::kHeapIndexInvalid;
bool UploadBufferPool::BeginNextPage() {
EndPage();
if (page_creation_failed_) {
return false;
}
if (unsent_ == nullptr) {
auto device = context_->GetD3D12Provider()->GetDevice();
D3D12_RESOURCE_DESC buffer_desc;
util::FillBufferResourceDesc(buffer_desc, page_size_,
D3D12_RESOURCE_FLAG_NONE);
ID3D12Resource* buffer_resource;
if (FAILED(device->CreateCommittedResource(
&util::kHeapPropertiesUpload, D3D12_HEAP_FLAG_NONE, &buffer_desc,
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
IID_PPV_ARGS(&buffer_resource)))) {
XELOGE("Failed to create a D3D upload buffer with %u bytes", page_size_);
page_creation_failed_ = true;
return false;
}
unsent_ = new UploadBuffer;
unsent_->buffer = buffer_resource;
unsent_->next = nullptr;
}
D3D12_RANGE read_range;
read_range.Begin = 0;
read_range.End = 0;
void* mapping;
if (FAILED(unsent_->buffer->Map(0, &read_range, &mapping))) {
XELOGE("Failed to map a D3D upload buffer with %u bytes", page_size_);
page_creation_failed_ = true;
return false;
}
current_mapping_ = reinterpret_cast<uint8_t*>(mapping);
current_gpu_address_ = 0;
return true;
}
DescriptorHeapPool::DescriptorHeapPool(D3D12Context* context,
DescriptorHeapPool::DescriptorHeapPool(ID3D12Device* device,
D3D12_DESCRIPTOR_HEAP_TYPE type,
uint32_t page_size)
: context_(context), type_(type), page_size_(page_size) {}
: device_(device), type_(type), page_size_(page_size) {}
DescriptorHeapPool::~DescriptorHeapPool() {
// Allow mid-frame destruction in cases like device loss.
current_size_ = 0;
ClearCache();
}
DescriptorHeapPool::~DescriptorHeapPool() { ClearCache(); }
void DescriptorHeapPool::BeginFrame() {
// Don't hold old pages if few descriptors are written, also make 0 usable as
// an invalid page index.
++current_page_;
// Recycle submitted pages not used by the GPU anymore.
uint64_t last_completed_frame = context_->GetLastCompletedFrame();
while (sent_first_ != nullptr) {
auto page = sent_first_;
if (page->frame_sent > last_completed_frame) {
void DescriptorHeapPool::Reclaim(uint64_t completed_submission_index) {
while (submitted_first_) {
if (submitted_first_->last_submission_index > completed_submission_index) {
break;
}
sent_first_ = page->next;
page->next = unsent_;
unsent_ = page;
if (writable_last_) {
writable_last_->next = submitted_first_;
} else {
writable_first_ = submitted_first_;
}
writable_last_ = submitted_first_;
submitted_first_ = submitted_first_->next;
writable_last_->next = nullptr;
}
if (sent_first_ == nullptr) {
sent_last_ = nullptr;
if (!submitted_first_) {
submitted_last_ = nullptr;
}
// Try to create new pages again in this frame if failed in the previous.
page_creation_failed_ = false;
}
void DescriptorHeapPool::EndFrame() { EndPage(); }
void DescriptorHeapPool::ClearCache() {
assert_true(current_size_ == 0);
while (unsent_ != nullptr) {
auto next = unsent_->next;
unsent_->heap->Release();
delete unsent_;
unsent_ = next;
// Not checking current_page_used_ != 0 because asking for 0 descriptors
// returns a valid heap also - but actually the new heap will be different now
// and the old one must be unbound since it doesn't exist anymore.
++current_heap_index_;
current_page_used_ = 0;
while (submitted_first_) {
auto next = submitted_first_->next;
submitted_first_->heap->Release();
delete submitted_first_;
submitted_first_ = next;
}
while (sent_first_ != nullptr) {
auto next = sent_first_->next;
sent_first_->heap->Release();
delete sent_first_;
sent_first_ = next;
submitted_last_ = nullptr;
while (writable_first_) {
auto next = writable_first_->next;
writable_first_->heap->Release();
delete writable_first_;
writable_first_ = next;
}
sent_last_ = nullptr;
writable_last_ = nullptr;
}
uint64_t DescriptorHeapPool::Request(uint64_t previous_full_update,
uint64_t DescriptorHeapPool::Request(uint64_t submission_index,
uint64_t previous_heap_index,
uint32_t count_for_partial_update,
uint32_t count_for_full_update,
uint32_t& index_out) {
@ -265,75 +222,63 @@ uint64_t DescriptorHeapPool::Request(uint64_t previous_full_update,
assert_true(count_for_full_update <= page_size_);
if (count_for_partial_update > count_for_full_update ||
count_for_full_update > page_size_) {
return 0;
return kHeapIndexInvalid;
}
if (page_creation_failed_) {
// Don't touch the page index every call if there was a failure as well.
return 0;
}
assert_true(!current_page_used_ ||
submission_index >= writable_first_->last_submission_index);
assert_true(!submitted_last_ ||
submission_index >= submitted_last_->last_submission_index);
// If the last full update happened on the current page, a partial update is
// possible.
uint32_t count = previous_full_update == current_page_
uint32_t count = previous_heap_index == current_heap_index_
? count_for_partial_update
: count_for_full_update;
// Go to the next page if there's not enough free space on the current one,
// or because the previous page may be outdated. In this case, a full update
// is necessary.
if (page_size_ - current_size_ < count) {
EndPage();
++current_page_;
if (page_size_ - current_page_used_ < count) {
// Close the page that was current.
if (submitted_last_) {
submitted_last_->next = writable_first_;
} else {
submitted_first_ = writable_first_;
}
submitted_last_ = writable_first_;
writable_first_ = writable_first_->next;
submitted_last_->next = nullptr;
if (!writable_first_) {
writable_last_ = nullptr;
}
++current_heap_index_;
current_page_used_ = 0;
count = count_for_full_update;
}
// Create the page if needed (may be the first call for the page).
if (unsent_ == nullptr) {
auto device = context_->GetD3D12Provider()->GetDevice();
D3D12_DESCRIPTOR_HEAP_DESC heap_desc;
heap_desc.Type = type_;
heap_desc.NumDescriptors = page_size_;
heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
heap_desc.NodeMask = 0;
ID3D12DescriptorHeap* heap;
if (FAILED(device->CreateDescriptorHeap(&heap_desc, IID_PPV_ARGS(&heap)))) {
if (!writable_first_) {
D3D12_DESCRIPTOR_HEAP_DESC new_heap_desc;
new_heap_desc.Type = type_;
new_heap_desc.NumDescriptors = page_size_;
new_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
new_heap_desc.NodeMask = 0;
ID3D12DescriptorHeap* new_heap;
if (FAILED(device_->CreateDescriptorHeap(&new_heap_desc,
IID_PPV_ARGS(&new_heap)))) {
XELOGE("Failed to create a heap for %u shader-visible descriptors",
page_size_);
page_creation_failed_ = true;
return 0;
return kHeapIndexInvalid;
}
unsent_ = new DescriptorHeap;
unsent_->heap = heap;
unsent_->next = nullptr;
}
// If starting a new page, get the handles to the beginning of it.
if (current_size_ == 0) {
current_heap_cpu_start_ =
unsent_->heap->GetCPUDescriptorHandleForHeapStart();
current_heap_gpu_start_ =
unsent_->heap->GetGPUDescriptorHandleForHeapStart();
}
index_out = current_size_;
current_size_ += count;
return current_page_;
}
void DescriptorHeapPool::EndPage() {
if (current_size_ != 0) {
auto page = unsent_;
page->frame_sent = context_->GetCurrentFrame();
unsent_ = page->next;
page->next = nullptr;
if (sent_last_ != nullptr) {
sent_last_->next = page;
} else {
sent_first_ = page;
}
sent_last_ = page;
current_size_ = 0;
writable_first_ = new Page;
writable_first_->heap = new_heap;
writable_first_->cpu_start = new_heap->GetCPUDescriptorHandleForHeapStart();
writable_first_->gpu_start = new_heap->GetGPUDescriptorHandleForHeapStart();
writable_first_->last_submission_index = submission_index;
writable_first_->next = nullptr;
writable_last_ = writable_first_;
}
writable_first_->last_submission_index = submission_index;
index_out = current_page_used_;
current_page_used_ += count;
return current_heap_index_;
}
} // namespace d3d12

View File

@ -18,64 +18,60 @@ namespace xe {
namespace ui {
namespace d3d12 {
class D3D12Context;
// Submission index is the fence value or a value derived from it (if reclaiming
// less often than once per fence value, for instance).
class UploadBufferPool {
public:
UploadBufferPool(D3D12Context* context, uint32_t page_size);
UploadBufferPool(ID3D12Device* device, uint32_t page_size);
~UploadBufferPool();
void BeginFrame();
void EndFrame();
void Reclaim(uint64_t completed_submission_index);
void ClearCache();
// Request to write data in a single piece, creating a new page if the current
// one doesn't have enough free space.
uint8_t* RequestFull(uint32_t size, ID3D12Resource** buffer_out,
uint32_t* offset_out,
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out);
uint8_t* Request(uint64_t submission_index, uint32_t size,
ID3D12Resource** buffer_out, uint32_t* offset_out,
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out);
// Request to write data in multiple parts, filling the buffer entirely.
uint8_t* RequestPartial(uint32_t size, ID3D12Resource** buffer_out,
uint32_t* offset_out, uint32_t* size_out,
uint8_t* RequestPartial(uint64_t submission_index, uint32_t size,
ID3D12Resource** buffer_out, uint32_t* offset_out,
uint32_t* size_out,
D3D12_GPU_VIRTUAL_ADDRESS* gpu_address_out);
private:
D3D12Context* context_;
ID3D12Device* device_;
uint32_t page_size_;
void EndPage();
bool BeginNextPage();
struct UploadBuffer {
struct Page {
ID3D12Resource* buffer;
UploadBuffer* next;
uint64_t frame_sent;
D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
void* mapping;
uint64_t last_submission_index;
Page* next;
};
// A list of unsent buffers, with the first one being the current.
UploadBuffer* unsent_ = nullptr;
// A list of sent buffers, moved to unsent in the beginning of a frame.
UploadBuffer* sent_first_ = nullptr;
UploadBuffer* sent_last_ = nullptr;
uint32_t current_size_ = 0;
uint8_t* current_mapping_ = nullptr;
// Not updated until actually requested.
D3D12_GPU_VIRTUAL_ADDRESS current_gpu_address_ = 0;
// Reset in the beginning of a frame - don't try and fail to create a new page
// if failed to create one in the current frame.
bool page_creation_failed_ = false;
// A list of buffers with free space, with the first buffer being the one
// currently being filled.
Page* writable_first_ = nullptr;
Page* writable_last_ = nullptr;
// A list of full buffers that can be reclaimed when the GPU doesn't use them
// anymore.
Page* submitted_first_ = nullptr;
Page* submitted_last_ = nullptr;
uint32_t current_page_used_ = 0;
};
class DescriptorHeapPool {
public:
DescriptorHeapPool(D3D12Context* context, D3D12_DESCRIPTOR_HEAP_TYPE type,
static constexpr uint64_t kHeapIndexInvalid = UINT64_MAX;
DescriptorHeapPool(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type,
uint32_t page_size);
~DescriptorHeapPool();
void BeginFrame();
void EndFrame();
void Reclaim(uint64_t completed_submission_index);
void ClearCache();
// Because all descriptors for a single draw call must be in the same heap,
@ -88,64 +84,64 @@ class DescriptorHeapPool {
//
// If something uses this pool to do partial updates, it must let this
// function determine whether a partial update is possible. For this purpose,
// this function returns a full update number - and it must be called with its
// this function returns the heap reset index - and it must be called with its
// previous return value for the set of descriptors it's updating.
//
// If this function returns a value that is the same as previous_full_update,
// a partial update needs to be done - and space for count_for_partial_update
// is allocated.
// If this function returns a value that is the same as previous_heap_index, a
// partial update needs to be done - and space for count_for_partial_update is
// allocated.
//
// If it's different, all descriptors must be written again - and space for
// count_for_full_update is allocated.
//
// If 0 is returned, there was an error.
// If kHeapIndexInvalid is returned, there was an error.
//
// This MUST be called even if there's nothing to write in a partial update
// (with count_for_partial_update being 0), because a full update may still be
// required.
uint64_t Request(uint64_t previous_full_update,
uint64_t Request(uint64_t submission_index, uint64_t previous_heap_index,
uint32_t count_for_partial_update,
uint32_t count_for_full_update, uint32_t& index_out);
// The current heap, for binding and actually writing - may be called only
// after a successful request because before a request, the heap may not exist
// yet.
ID3D12DescriptorHeap* GetLastRequestHeap() const { return unsent_->heap; }
ID3D12DescriptorHeap* GetLastRequestHeap() const {
return writable_first_->heap;
}
D3D12_CPU_DESCRIPTOR_HANDLE GetLastRequestHeapCPUStart() const {
return current_heap_cpu_start_;
return writable_first_->cpu_start;
}
D3D12_GPU_DESCRIPTOR_HANDLE GetLastRequestHeapGPUStart() const {
return current_heap_gpu_start_;
return writable_first_->gpu_start;
}
private:
D3D12Context* context_;
ID3D12Device* device_;
D3D12_DESCRIPTOR_HEAP_TYPE type_;
uint32_t page_size_;
void EndPage();
bool BeginNextPage();
struct DescriptorHeap {
struct Page {
ID3D12DescriptorHeap* heap;
DescriptorHeap* next;
uint64_t frame_sent;
D3D12_CPU_DESCRIPTOR_HANDLE cpu_start;
D3D12_GPU_DESCRIPTOR_HANDLE gpu_start;
uint64_t last_submission_index;
Page* next;
};
// A list of unsent heaps, with the first one being the current.
DescriptorHeap* unsent_ = nullptr;
// A list of sent heaps, moved to unsent in the beginning of a frame.
DescriptorHeap* sent_first_ = nullptr;
DescriptorHeap* sent_last_ = nullptr;
uint64_t current_page_ = 0;
D3D12_CPU_DESCRIPTOR_HANDLE current_heap_cpu_start_ = {};
D3D12_GPU_DESCRIPTOR_HANDLE current_heap_gpu_start_ = {};
uint32_t current_size_ = 0;
// Reset in the beginning of a frame - don't try and fail to create a new page
// if failed to create one in the current frame.
bool page_creation_failed_ = false;
// A list of heap with free space, with the first buffer being the one
// currently being filled.
Page* writable_first_ = nullptr;
Page* writable_last_ = nullptr;
// A list of full heaps that can be reclaimed when the GPU doesn't use them
// anymore.
Page* submitted_first_ = nullptr;
Page* submitted_last_ = nullptr;
// Monotonically increased when a new request is going to a different
// ID3D12DescriptorHeap than the one that may be bound currently. See Request
// for more information.
uint64_t current_heap_index_ = 0;
uint32_t current_page_used_ = 0;
};
} // namespace d3d12

View File

@ -26,52 +26,41 @@ const char kProggyTinyCompressedDataBase85[10950 + 1] =
static_assert(sizeof(ImmediateVertex) == sizeof(ImDrawVert),
"Vertex types must match");
ImGuiDrawer* ImGuiDrawer::current_drawer_ = nullptr;
ImGuiDrawer::ImGuiDrawer(xe::ui::Window* window)
: window_(window), graphics_context_(window->context()) {
Initialize();
}
ImGuiDrawer::~ImGuiDrawer() {
auto previous_state = ImGui::GetInternalState();
ImGui::SetInternalState(internal_state_.data());
ImGui::Shutdown();
if (previous_state != internal_state_.data()) {
ImGui::SetInternalState(previous_state);
if (internal_state_) {
ImGui::DestroyContext(internal_state_);
internal_state_ = nullptr;
}
current_drawer_ = nullptr;
}
void ImGuiDrawer::Initialize() {
// Setup ImGui internal state.
// This will give us state we can swap to the ImGui globals when in use.
internal_state_.resize(ImGui::GetInternalStateSize());
ImGui::SetInternalState(internal_state_.data(), true);
current_drawer_ = this;
internal_state_ = ImGui::CreateContext();
auto& io = ImGui::GetIO();
font_atlas_ = std::make_unique<ImFontAtlas>();
io.Fonts = font_atlas_.get();
// TODO(gibbed): disable imgui.ini saving for now,
// imgui assumes paths are char* so we can't throw a good path at it on
// Windows.
io.IniFilename = nullptr;
SetupFont();
io.DeltaTime = 1.0f / 60.0f;
io.RenderDrawListsFn = [](ImDrawData* data) {
assert_not_null(current_drawer_);
current_drawer_->RenderDrawLists(data);
};
auto& style = ImGui::GetStyle();
style.ScrollbarRounding = 0;
style.WindowFillAlphaDefault = 1.0f;
style.WindowRounding = 0;
style.Colors[ImGuiCol_Text] = ImVec4(0.89f, 0.90f, 0.90f, 1.00f);
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.06f, 0.00f, 1.00f);
style.Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[ImGuiCol_Border] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f);
@ -87,7 +76,7 @@ void ImGuiDrawer::Initialize() {
ImVec4(0.00f, 1.00f, 0.15f, 0.62f);
style.Colors[ImGuiCol_ScrollbarGrabActive] =
ImVec4(0.00f, 0.91f, 0.09f, 0.40f);
style.Colors[ImGuiCol_ComboBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f);
style.Colors[ImGuiCol_PopupBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f);
style.Colors[ImGuiCol_CheckMark] = ImVec4(0.74f, 0.90f, 0.72f, 0.50f);
style.Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.34f, 0.75f, 0.11f, 1.00f);
@ -97,25 +86,19 @@ void ImGuiDrawer::Initialize() {
style.Colors[ImGuiCol_Header] = ImVec4(0.00f, 0.40f, 0.00f, 0.71f);
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.00f, 0.60f, 0.26f, 0.80f);
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.00f, 0.75f, 0.00f, 0.80f);
style.Colors[ImGuiCol_Column] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
style.Colors[ImGuiCol_ColumnHovered] = ImVec4(0.36f, 0.89f, 0.38f, 1.00f);
style.Colors[ImGuiCol_ColumnActive] = ImVec4(0.13f, 0.50f, 0.11f, 1.00f);
style.Colors[ImGuiCol_Separator] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.36f, 0.89f, 0.38f, 1.00f);
style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.13f, 0.50f, 0.11f, 1.00f);
style.Colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f);
style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f);
style.Colors[ImGuiCol_CloseButton] = ImVec4(0.00f, 0.72f, 0.00f, 0.96f);
style.Colors[ImGuiCol_CloseButtonHovered] =
ImVec4(0.38f, 1.00f, 0.42f, 0.60f);
style.Colors[ImGuiCol_CloseButtonActive] = ImVec4(0.56f, 1.00f, 0.64f, 1.00f);
style.Colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
style.Colors[ImGuiCol_PlotHistogramHovered] =
ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 1.00f, 0.00f, 0.21f);
style.Colors[ImGuiCol_TooltipBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f);
style.Colors[ImGuiCol_ModalWindowDarkening] =
ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
io.KeyMap[ImGuiKey_Tab] = 0x09; // VK_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = 0x25;
@ -230,11 +213,18 @@ void ImGuiDrawer::RenderDrawLists(ImDrawData* data) {
}
ImGuiIO& ImGuiDrawer::GetIO() {
current_drawer_ = this;
ImGui::SetInternalState(internal_state_.data());
ImGui::SetCurrentContext(internal_state_);
return ImGui::GetIO();
}
void ImGuiDrawer::RenderDrawLists() {
ImGui::SetCurrentContext(internal_state_);
auto draw_data = ImGui::GetDrawData();
if (draw_data) {
RenderDrawLists(draw_data);
}
}
void ImGuiDrawer::OnKeyDown(KeyEvent* e) {
auto& io = GetIO();
io.KeysDown[e->key_code()] = true;

View File

@ -17,7 +17,7 @@
#include "xenia/ui/window_listener.h"
struct ImDrawData;
struct ImFontAtlas;
struct ImGuiContext;
struct ImGuiIO;
namespace xe {
@ -34,6 +34,7 @@ class ImGuiDrawer : public WindowListener {
void SetupDefaultInput() {}
ImGuiIO& GetIO();
void RenderDrawLists();
static const uint64_t kIgnoreAlpha = (1ull << 63);
@ -56,8 +57,7 @@ class ImGuiDrawer : public WindowListener {
Window* window_ = nullptr;
GraphicsContext* graphics_context_ = nullptr;
std::vector<uint8_t> internal_state_;
std::unique_ptr<ImFontAtlas> font_atlas_;
ImGuiContext* internal_state_ = nullptr;
std::unique_ptr<ImmediateTexture> font_texture_;
};

View File

@ -256,6 +256,7 @@ void Window::OnPaint(UIEvent* e) {
// Flush ImGui buffers before we swap.
ImGui::Render();
imgui_drawer_->RenderDrawLists();
ForEachListener([e](auto listener) { listener->OnPainted(e); });
on_painted(e);

View File

@ -102,7 +102,7 @@ int window_demo_main(const std::vector<std::wstring>& args) {
window->on_painting.AddListener([&](xe::ui::UIEvent* e) {
auto& io = window->imgui_drawer()->GetIO();
ImGui::ShowTestWindow();
ImGui::ShowDemoWindow();
ImGui::ShowMetricsWindow();
// Continuous paint.

View File

@ -1,73 +0,0 @@
The OpenGL Extension Wrangler Library
Copyright (C) 2002-2007, Milan Ikits <milan ikits[]ieee org>
Copyright (C) 2002-2007, Marcelo E. Magallon <mmagallo[]debian org>
Copyright (C) 2002, Lev Povalahev
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
Mesa 3-D graphics library
Version: 7.0
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyright (c) 2007 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

File diff suppressed because it is too large Load Diff

19231
third_party/GL/glew.c vendored

File diff suppressed because it is too large Load Diff

18984
third_party/GL/glew.h vendored

File diff suppressed because it is too large Load Diff

11358
third_party/GL/glewinfo.c vendored

File diff suppressed because it is too large Load Diff

11767
third_party/GL/glext.h vendored

File diff suppressed because it is too large Load Diff

1767
third_party/GL/glxew.h vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,926 +0,0 @@
#ifndef __glxext_h_
#define __glxext_h_ 1
#ifdef __cplusplus
extern "C" {
#endif
/*
** Copyright (c) 2013-2014 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/*
** This header is generated from the Khronos OpenGL / OpenGL ES XML
** API Registry. The current version of the Registry, generator scripts
** used to make the header, and the header can be found at
** http://www.opengl.org/registry/
**
** Khronos $Revision: 28198 $ on $Date: 2014-09-18 07:42:14 -0700 (Thu, 18 Sep 2014) $
*/
#define GLX_GLXEXT_VERSION 20140918
/* Generated C header for:
* API: glx
* Versions considered: .*
* Versions emitted: 1\.[3-9]
* Default extensions included: glx
* Additional extensions included: _nomatch_^
* Extensions removed: _nomatch_^
*/
#ifndef GLX_VERSION_1_3
#define GLX_VERSION_1_3 1
typedef XID GLXContextID;
typedef struct __GLXFBConfigRec *GLXFBConfig;
typedef XID GLXWindow;
typedef XID GLXPbuffer;
#define GLX_WINDOW_BIT 0x00000001
#define GLX_PIXMAP_BIT 0x00000002
#define GLX_PBUFFER_BIT 0x00000004
#define GLX_RGBA_BIT 0x00000001
#define GLX_COLOR_INDEX_BIT 0x00000002
#define GLX_PBUFFER_CLOBBER_MASK 0x08000000
#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001
#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002
#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004
#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008
#define GLX_AUX_BUFFERS_BIT 0x00000010
#define GLX_DEPTH_BUFFER_BIT 0x00000020
#define GLX_STENCIL_BUFFER_BIT 0x00000040
#define GLX_ACCUM_BUFFER_BIT 0x00000080
#define GLX_CONFIG_CAVEAT 0x20
#define GLX_X_VISUAL_TYPE 0x22
#define GLX_TRANSPARENT_TYPE 0x23
#define GLX_TRANSPARENT_INDEX_VALUE 0x24
#define GLX_TRANSPARENT_RED_VALUE 0x25
#define GLX_TRANSPARENT_GREEN_VALUE 0x26
#define GLX_TRANSPARENT_BLUE_VALUE 0x27
#define GLX_TRANSPARENT_ALPHA_VALUE 0x28
#define GLX_DONT_CARE 0xFFFFFFFF
#define GLX_NONE 0x8000
#define GLX_SLOW_CONFIG 0x8001
#define GLX_TRUE_COLOR 0x8002
#define GLX_DIRECT_COLOR 0x8003
#define GLX_PSEUDO_COLOR 0x8004
#define GLX_STATIC_COLOR 0x8005
#define GLX_GRAY_SCALE 0x8006
#define GLX_STATIC_GRAY 0x8007
#define GLX_TRANSPARENT_RGB 0x8008
#define GLX_TRANSPARENT_INDEX 0x8009
#define GLX_VISUAL_ID 0x800B
#define GLX_SCREEN 0x800C
#define GLX_NON_CONFORMANT_CONFIG 0x800D
#define GLX_DRAWABLE_TYPE 0x8010
#define GLX_RENDER_TYPE 0x8011
#define GLX_X_RENDERABLE 0x8012
#define GLX_FBCONFIG_ID 0x8013
#define GLX_RGBA_TYPE 0x8014
#define GLX_COLOR_INDEX_TYPE 0x8015
#define GLX_MAX_PBUFFER_WIDTH 0x8016
#define GLX_MAX_PBUFFER_HEIGHT 0x8017
#define GLX_MAX_PBUFFER_PIXELS 0x8018
#define GLX_PRESERVED_CONTENTS 0x801B
#define GLX_LARGEST_PBUFFER 0x801C
#define GLX_WIDTH 0x801D
#define GLX_HEIGHT 0x801E
#define GLX_EVENT_MASK 0x801F
#define GLX_DAMAGED 0x8020
#define GLX_SAVED 0x8021
#define GLX_WINDOW 0x8022
#define GLX_PBUFFER 0x8023
#define GLX_PBUFFER_HEIGHT 0x8040
#define GLX_PBUFFER_WIDTH 0x8041
typedef GLXFBConfig *( *PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements);
typedef GLXFBConfig *( *PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);
typedef int ( *PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value);
typedef XVisualInfo *( *PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config);
typedef GLXWindow ( *PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);
typedef void ( *PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win);
typedef GLXPixmap ( *PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);
typedef void ( *PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap);
typedef GLXPbuffer ( *PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list);
typedef void ( *PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf);
typedef void ( *PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
typedef GLXContext ( *PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
typedef Bool ( *PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
typedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLEPROC) (void);
typedef int ( *PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value);
typedef void ( *PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask);
typedef void ( *PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask);
#ifdef GLX_GLXEXT_PROTOTYPES
GLXFBConfig *glXGetFBConfigs (Display *dpy, int screen, int *nelements);
GLXFBConfig *glXChooseFBConfig (Display *dpy, int screen, const int *attrib_list, int *nelements);
int glXGetFBConfigAttrib (Display *dpy, GLXFBConfig config, int attribute, int *value);
XVisualInfo *glXGetVisualFromFBConfig (Display *dpy, GLXFBConfig config);
GLXWindow glXCreateWindow (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);
void glXDestroyWindow (Display *dpy, GLXWindow win);
GLXPixmap glXCreatePixmap (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);
void glXDestroyPixmap (Display *dpy, GLXPixmap pixmap);
GLXPbuffer glXCreatePbuffer (Display *dpy, GLXFBConfig config, const int *attrib_list);
void glXDestroyPbuffer (Display *dpy, GLXPbuffer pbuf);
void glXQueryDrawable (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);
GLXContext glXCreateNewContext (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
Bool glXMakeContextCurrent (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
GLXDrawable glXGetCurrentReadDrawable (void);
int glXQueryContext (Display *dpy, GLXContext ctx, int attribute, int *value);
void glXSelectEvent (Display *dpy, GLXDrawable draw, unsigned long event_mask);
void glXGetSelectedEvent (Display *dpy, GLXDrawable draw, unsigned long *event_mask);
#endif
#endif /* GLX_VERSION_1_3 */
#ifndef GLX_VERSION_1_4
#define GLX_VERSION_1_4 1
typedef void ( *__GLXextFuncPtr)(void);
#define GLX_SAMPLE_BUFFERS 100000
#define GLX_SAMPLES 100001
typedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName);
#ifdef GLX_GLXEXT_PROTOTYPES
__GLXextFuncPtr glXGetProcAddress (const GLubyte *procName);
#endif
#endif /* GLX_VERSION_1_4 */
#ifndef GLX_ARB_context_flush_control
#define GLX_ARB_context_flush_control 1
#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
#endif /* GLX_ARB_context_flush_control */
#ifndef GLX_ARB_create_context
#define GLX_ARB_create_context 1
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GLX_CONTEXT_FLAGS_ARB 0x2094
typedef GLXContext ( *PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
#ifdef GLX_GLXEXT_PROTOTYPES
GLXContext glXCreateContextAttribsARB (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
#endif
#endif /* GLX_ARB_create_context */
#ifndef GLX_ARB_create_context_profile
#define GLX_ARB_create_context_profile 1
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
#endif /* GLX_ARB_create_context_profile */
#ifndef GLX_ARB_create_context_robustness
#define GLX_ARB_create_context_robustness 1
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
#endif /* GLX_ARB_create_context_robustness */
#ifndef GLX_ARB_fbconfig_float
#define GLX_ARB_fbconfig_float 1
#define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9
#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004
#endif /* GLX_ARB_fbconfig_float */
#ifndef GLX_ARB_framebuffer_sRGB
#define GLX_ARB_framebuffer_sRGB 1
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
#endif /* GLX_ARB_framebuffer_sRGB */
#ifndef GLX_ARB_get_proc_address
#define GLX_ARB_get_proc_address 1
typedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName);
#ifdef GLX_GLXEXT_PROTOTYPES
__GLXextFuncPtr glXGetProcAddressARB (const GLubyte *procName);
#endif
#endif /* GLX_ARB_get_proc_address */
#ifndef GLX_ARB_multisample
#define GLX_ARB_multisample 1
#define GLX_SAMPLE_BUFFERS_ARB 100000
#define GLX_SAMPLES_ARB 100001
#endif /* GLX_ARB_multisample */
#ifndef GLX_ARB_robustness_application_isolation
#define GLX_ARB_robustness_application_isolation 1
#define GLX_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008
#endif /* GLX_ARB_robustness_application_isolation */
#ifndef GLX_ARB_robustness_share_group_isolation
#define GLX_ARB_robustness_share_group_isolation 1
#endif /* GLX_ARB_robustness_share_group_isolation */
#ifndef GLX_ARB_vertex_buffer_object
#define GLX_ARB_vertex_buffer_object 1
#define GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095
#endif /* GLX_ARB_vertex_buffer_object */
#ifndef GLX_3DFX_multisample
#define GLX_3DFX_multisample 1
#define GLX_SAMPLE_BUFFERS_3DFX 0x8050
#define GLX_SAMPLES_3DFX 0x8051
#endif /* GLX_3DFX_multisample */
#ifndef GLX_AMD_gpu_association
#define GLX_AMD_gpu_association 1
#define GLX_GPU_VENDOR_AMD 0x1F00
#define GLX_GPU_RENDERER_STRING_AMD 0x1F01
#define GLX_GPU_OPENGL_VERSION_STRING_AMD 0x1F02
#define GLX_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2
#define GLX_GPU_RAM_AMD 0x21A3
#define GLX_GPU_CLOCK_AMD 0x21A4
#define GLX_GPU_NUM_PIPES_AMD 0x21A5
#define GLX_GPU_NUM_SIMD_AMD 0x21A6
#define GLX_GPU_NUM_RB_AMD 0x21A7
#define GLX_GPU_NUM_SPI_AMD 0x21A8
typedef unsigned int ( *PFNGLXGETGPUIDSAMDPROC) (unsigned int maxCount, unsigned int *ids);
typedef int ( *PFNGLXGETGPUINFOAMDPROC) (unsigned int id, int property, GLenum dataType, unsigned int size, void *data);
typedef unsigned int ( *PFNGLXGETCONTEXTGPUIDAMDPROC) (GLXContext ctx);
typedef GLXContext ( *PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC) (unsigned int id, GLXContext share_list);
typedef GLXContext ( *PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (unsigned int id, GLXContext share_context, const int *attribList);
typedef Bool ( *PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC) (GLXContext ctx);
typedef Bool ( *PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (GLXContext ctx);
typedef GLXContext ( *PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void);
typedef void ( *PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC) (GLXContext dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
#ifdef GLX_GLXEXT_PROTOTYPES
unsigned int glXGetGPUIDsAMD (unsigned int maxCount, unsigned int *ids);
int glXGetGPUInfoAMD (unsigned int id, int property, GLenum dataType, unsigned int size, void *data);
unsigned int glXGetContextGPUIDAMD (GLXContext ctx);
GLXContext glXCreateAssociatedContextAMD (unsigned int id, GLXContext share_list);
GLXContext glXCreateAssociatedContextAttribsAMD (unsigned int id, GLXContext share_context, const int *attribList);
Bool glXDeleteAssociatedContextAMD (GLXContext ctx);
Bool glXMakeAssociatedContextCurrentAMD (GLXContext ctx);
GLXContext glXGetCurrentAssociatedContextAMD (void);
void glXBlitContextFramebufferAMD (GLXContext dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
#endif
#endif /* GLX_AMD_gpu_association */
#ifndef GLX_EXT_buffer_age
#define GLX_EXT_buffer_age 1
#define GLX_BACK_BUFFER_AGE_EXT 0x20F4
#endif /* GLX_EXT_buffer_age */
#ifndef GLX_EXT_create_context_es2_profile
#define GLX_EXT_create_context_es2_profile 1
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
#endif /* GLX_EXT_create_context_es2_profile */
#ifndef GLX_EXT_create_context_es_profile
#define GLX_EXT_create_context_es_profile 1
#define GLX_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
#endif /* GLX_EXT_create_context_es_profile */
#ifndef GLX_EXT_fbconfig_packed_float
#define GLX_EXT_fbconfig_packed_float 1
#define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT 0x20B1
#define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT 0x00000008
#endif /* GLX_EXT_fbconfig_packed_float */
#ifndef GLX_EXT_framebuffer_sRGB
#define GLX_EXT_framebuffer_sRGB 1
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2
#endif /* GLX_EXT_framebuffer_sRGB */
#ifndef GLX_EXT_import_context
#define GLX_EXT_import_context 1
#define GLX_SHARE_CONTEXT_EXT 0x800A
#define GLX_VISUAL_ID_EXT 0x800B
#define GLX_SCREEN_EXT 0x800C
typedef Display *( *PFNGLXGETCURRENTDISPLAYEXTPROC) (void);
typedef int ( *PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value);
typedef GLXContextID ( *PFNGLXGETCONTEXTIDEXTPROC) (const GLXContext context);
typedef GLXContext ( *PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID);
typedef void ( *PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context);
#ifdef GLX_GLXEXT_PROTOTYPES
Display *glXGetCurrentDisplayEXT (void);
int glXQueryContextInfoEXT (Display *dpy, GLXContext context, int attribute, int *value);
GLXContextID glXGetContextIDEXT (const GLXContext context);
GLXContext glXImportContextEXT (Display *dpy, GLXContextID contextID);
void glXFreeContextEXT (Display *dpy, GLXContext context);
#endif
#endif /* GLX_EXT_import_context */
#ifndef GLX_EXT_stereo_tree
#define GLX_EXT_stereo_tree 1
typedef struct {
int type;
unsigned long serial;
Bool send_event;
Display *display;
int extension;
int evtype;
GLXDrawable window;
Bool stereo_tree;
} GLXStereoNotifyEventEXT;
#define GLX_STEREO_TREE_EXT 0x20F5
#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001
#define GLX_STEREO_NOTIFY_EXT 0x00000000
#endif /* GLX_EXT_stereo_tree */
#ifndef GLX_EXT_swap_control
#define GLX_EXT_swap_control 1
#define GLX_SWAP_INTERVAL_EXT 0x20F1
#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
typedef void ( *PFNGLXSWAPINTERVALEXTPROC) (Display *dpy, GLXDrawable drawable, int interval);
#ifdef GLX_GLXEXT_PROTOTYPES
void glXSwapIntervalEXT (Display *dpy, GLXDrawable drawable, int interval);
#endif
#endif /* GLX_EXT_swap_control */
#ifndef GLX_EXT_swap_control_tear
#define GLX_EXT_swap_control_tear 1
#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
#endif /* GLX_EXT_swap_control_tear */
#ifndef GLX_EXT_texture_from_pixmap
#define GLX_EXT_texture_from_pixmap 1
#define GLX_TEXTURE_1D_BIT_EXT 0x00000001
#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1
#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2
#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3
#define GLX_Y_INVERTED_EXT 0x20D4
#define GLX_TEXTURE_FORMAT_EXT 0x20D5
#define GLX_TEXTURE_TARGET_EXT 0x20D6
#define GLX_MIPMAP_TEXTURE_EXT 0x20D7
#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8
#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9
#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA
#define GLX_TEXTURE_1D_EXT 0x20DB
#define GLX_TEXTURE_2D_EXT 0x20DC
#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD
#define GLX_FRONT_LEFT_EXT 0x20DE
#define GLX_FRONT_RIGHT_EXT 0x20DF
#define GLX_BACK_LEFT_EXT 0x20E0
#define GLX_BACK_RIGHT_EXT 0x20E1
#define GLX_FRONT_EXT 0x20DE
#define GLX_BACK_EXT 0x20E0
#define GLX_AUX0_EXT 0x20E2
#define GLX_AUX1_EXT 0x20E3
#define GLX_AUX2_EXT 0x20E4
#define GLX_AUX3_EXT 0x20E5
#define GLX_AUX4_EXT 0x20E6
#define GLX_AUX5_EXT 0x20E7
#define GLX_AUX6_EXT 0x20E8
#define GLX_AUX7_EXT 0x20E9
#define GLX_AUX8_EXT 0x20EA
#define GLX_AUX9_EXT 0x20EB
typedef void ( *PFNGLXBINDTEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);
typedef void ( *PFNGLXRELEASETEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer);
#ifdef GLX_GLXEXT_PROTOTYPES
void glXBindTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);
void glXReleaseTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer);
#endif
#endif /* GLX_EXT_texture_from_pixmap */
#ifndef GLX_EXT_visual_info
#define GLX_EXT_visual_info 1
#define GLX_X_VISUAL_TYPE_EXT 0x22
#define GLX_TRANSPARENT_TYPE_EXT 0x23
#define GLX_TRANSPARENT_INDEX_VALUE_EXT 0x24
#define GLX_TRANSPARENT_RED_VALUE_EXT 0x25
#define GLX_TRANSPARENT_GREEN_VALUE_EXT 0x26
#define GLX_TRANSPARENT_BLUE_VALUE_EXT 0x27
#define GLX_TRANSPARENT_ALPHA_VALUE_EXT 0x28
#define GLX_NONE_EXT 0x8000
#define GLX_TRUE_COLOR_EXT 0x8002
#define GLX_DIRECT_COLOR_EXT 0x8003
#define GLX_PSEUDO_COLOR_EXT 0x8004
#define GLX_STATIC_COLOR_EXT 0x8005
#define GLX_GRAY_SCALE_EXT 0x8006
#define GLX_STATIC_GRAY_EXT 0x8007
#define GLX_TRANSPARENT_RGB_EXT 0x8008
#define GLX_TRANSPARENT_INDEX_EXT 0x8009
#endif /* GLX_EXT_visual_info */
#ifndef GLX_EXT_visual_rating
#define GLX_EXT_visual_rating 1
#define GLX_VISUAL_CAVEAT_EXT 0x20
#define GLX_SLOW_VISUAL_EXT 0x8001
#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
#endif /* GLX_EXT_visual_rating */
#ifndef GLX_INTEL_swap_event
#define GLX_INTEL_swap_event 1
#define GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000
#define GLX_EXCHANGE_COMPLETE_INTEL 0x8180
#define GLX_COPY_COMPLETE_INTEL 0x8181
#define GLX_FLIP_COMPLETE_INTEL 0x8182
#endif /* GLX_INTEL_swap_event */
#ifndef GLX_MESA_agp_offset
#define GLX_MESA_agp_offset 1
typedef unsigned int ( *PFNGLXGETAGPOFFSETMESAPROC) (const void *pointer);
#ifdef GLX_GLXEXT_PROTOTYPES
unsigned int glXGetAGPOffsetMESA (const void *pointer);
#endif
#endif /* GLX_MESA_agp_offset */
#ifndef GLX_MESA_copy_sub_buffer
#define GLX_MESA_copy_sub_buffer 1
typedef void ( *PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
#ifdef GLX_GLXEXT_PROTOTYPES
void glXCopySubBufferMESA (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
#endif
#endif /* GLX_MESA_copy_sub_buffer */
#ifndef GLX_MESA_pixmap_colormap
#define GLX_MESA_pixmap_colormap 1
typedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap);
#ifdef GLX_GLXEXT_PROTOTYPES
GLXPixmap glXCreateGLXPixmapMESA (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap);
#endif
#endif /* GLX_MESA_pixmap_colormap */
#ifndef GLX_MESA_query_renderer
#define GLX_MESA_query_renderer 1
#define GLX_RENDERER_VENDOR_ID_MESA 0x8183
#define GLX_RENDERER_DEVICE_ID_MESA 0x8184
#define GLX_RENDERER_VERSION_MESA 0x8185
#define GLX_RENDERER_ACCELERATED_MESA 0x8186
#define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187
#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188
#define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189
#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A
#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B
#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C
#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D
#define GLX_RENDERER_ID_MESA 0x818E
typedef Bool ( *PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int *value);
typedef const char *( *PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC) (int attribute);
typedef Bool ( *PFNGLXQUERYRENDERERINTEGERMESAPROC) (Display *dpy, int screen, int renderer, int attribute, unsigned int *value);
typedef const char *( *PFNGLXQUERYRENDERERSTRINGMESAPROC) (Display *dpy, int screen, int renderer, int attribute);
#ifdef GLX_GLXEXT_PROTOTYPES
Bool glXQueryCurrentRendererIntegerMESA (int attribute, unsigned int *value);
const char *glXQueryCurrentRendererStringMESA (int attribute);
Bool glXQueryRendererIntegerMESA (Display *dpy, int screen, int renderer, int attribute, unsigned int *value);
const char *glXQueryRendererStringMESA (Display *dpy, int screen, int renderer, int attribute);
#endif
#endif /* GLX_MESA_query_renderer */
#ifndef GLX_MESA_release_buffers
#define GLX_MESA_release_buffers 1
typedef Bool ( *PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable);
#ifdef GLX_GLXEXT_PROTOTYPES
Bool glXReleaseBuffersMESA (Display *dpy, GLXDrawable drawable);
#endif
#endif /* GLX_MESA_release_buffers */
#ifndef GLX_MESA_set_3dfx_mode
#define GLX_MESA_set_3dfx_mode 1
#define GLX_3DFX_WINDOW_MODE_MESA 0x1
#define GLX_3DFX_FULLSCREEN_MODE_MESA 0x2
typedef Bool ( *PFNGLXSET3DFXMODEMESAPROC) (int mode);
#ifdef GLX_GLXEXT_PROTOTYPES
Bool glXSet3DfxModeMESA (int mode);
#endif
#endif /* GLX_MESA_set_3dfx_mode */
#ifndef GLX_NV_copy_buffer
#define GLX_NV_copy_buffer 1
typedef void ( *PFNGLXCOPYBUFFERSUBDATANVPROC) (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
typedef void ( *PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC) (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
#ifdef GLX_GLXEXT_PROTOTYPES
void glXCopyBufferSubDataNV (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
void glXNamedCopyBufferSubDataNV (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
#endif
#endif /* GLX_NV_copy_buffer */
#ifndef GLX_NV_copy_image
#define GLX_NV_copy_image 1
typedef void ( *PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
#ifdef GLX_GLXEXT_PROTOTYPES
void glXCopyImageSubDataNV (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
#endif
#endif /* GLX_NV_copy_image */
#ifndef GLX_NV_delay_before_swap
#define GLX_NV_delay_before_swap 1
typedef Bool ( *PFNGLXDELAYBEFORESWAPNVPROC) (Display *dpy, GLXDrawable drawable, GLfloat seconds);
#ifdef GLX_GLXEXT_PROTOTYPES
Bool glXDelayBeforeSwapNV (Display *dpy, GLXDrawable drawable, GLfloat seconds);
#endif
#endif /* GLX_NV_delay_before_swap */
#ifndef GLX_NV_float_buffer
#define GLX_NV_float_buffer 1
#define GLX_FLOAT_COMPONENTS_NV 0x20B0
#endif /* GLX_NV_float_buffer */
#ifndef GLX_NV_multisample_coverage
#define GLX_NV_multisample_coverage 1
#define GLX_COVERAGE_SAMPLES_NV 100001
#define GLX_COLOR_SAMPLES_NV 0x20B3
#endif /* GLX_NV_multisample_coverage */
#ifndef GLX_NV_present_video
#define GLX_NV_present_video 1
#define GLX_NUM_VIDEO_SLOTS_NV 0x20F0
typedef unsigned int *( *PFNGLXENUMERATEVIDEODEVICESNVPROC) (Display *dpy, int screen, int *nelements);
typedef int ( *PFNGLXBINDVIDEODEVICENVPROC) (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list);
#ifdef GLX_GLXEXT_PROTOTYPES
unsigned int *glXEnumerateVideoDevicesNV (Display *dpy, int screen, int *nelements);
int glXBindVideoDeviceNV (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list);
#endif
#endif /* GLX_NV_present_video */
#ifndef GLX_NV_swap_group
#define GLX_NV_swap_group 1
typedef Bool ( *PFNGLXJOINSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint group);
typedef Bool ( *PFNGLXBINDSWAPBARRIERNVPROC) (Display *dpy, GLuint group, GLuint barrier);
typedef Bool ( *PFNGLXQUERYSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);
typedef Bool ( *PFNGLXQUERYMAXSWAPGROUPSNVPROC) (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);
typedef Bool ( *PFNGLXQUERYFRAMECOUNTNVPROC) (Display *dpy, int screen, GLuint *count);
typedef Bool ( *PFNGLXRESETFRAMECOUNTNVPROC) (Display *dpy, int screen);
#ifdef GLX_GLXEXT_PROTOTYPES
Bool glXJoinSwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint group);
Bool glXBindSwapBarrierNV (Display *dpy, GLuint group, GLuint barrier);
Bool glXQuerySwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);
Bool glXQueryMaxSwapGroupsNV (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);
Bool glXQueryFrameCountNV (Display *dpy, int screen, GLuint *count);
Bool glXResetFrameCountNV (Display *dpy, int screen);
#endif
#endif /* GLX_NV_swap_group */
#ifndef GLX_NV_video_capture
#define GLX_NV_video_capture 1
typedef XID GLXVideoCaptureDeviceNV;
#define GLX_DEVICE_ID_NV 0x20CD
#define GLX_UNIQUE_ID_NV 0x20CE
#define GLX_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF
typedef int ( *PFNGLXBINDVIDEOCAPTUREDEVICENVPROC) (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device);
typedef GLXVideoCaptureDeviceNV *( *PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC) (Display *dpy, int screen, int *nelements);
typedef void ( *PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device);
typedef int ( *PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value);
typedef void ( *PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device);
#ifdef GLX_GLXEXT_PROTOTYPES
int glXBindVideoCaptureDeviceNV (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device);
GLXVideoCaptureDeviceNV *glXEnumerateVideoCaptureDevicesNV (Display *dpy, int screen, int *nelements);
void glXLockVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device);
int glXQueryVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value);
void glXReleaseVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device);
#endif
#endif /* GLX_NV_video_capture */
#ifndef GLX_NV_video_out
#define GLX_NV_video_out 1
typedef unsigned int GLXVideoDeviceNV;
#define GLX_VIDEO_OUT_COLOR_NV 0x20C3
#define GLX_VIDEO_OUT_ALPHA_NV 0x20C4
#define GLX_VIDEO_OUT_DEPTH_NV 0x20C5
#define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6
#define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7
#define GLX_VIDEO_OUT_FRAME_NV 0x20C8
#define GLX_VIDEO_OUT_FIELD_1_NV 0x20C9
#define GLX_VIDEO_OUT_FIELD_2_NV 0x20CA
#define GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB
#define GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC
typedef int ( *PFNGLXGETVIDEODEVICENVPROC) (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice);
typedef int ( *PFNGLXRELEASEVIDEODEVICENVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice);
typedef int ( *PFNGLXBINDVIDEOIMAGENVPROC) (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer);
typedef int ( *PFNGLXRELEASEVIDEOIMAGENVPROC) (Display *dpy, GLXPbuffer pbuf);
typedef int ( *PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock);
typedef int ( *PFNGLXGETVIDEOINFONVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
#ifdef GLX_GLXEXT_PROTOTYPES
int glXGetVideoDeviceNV (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice);
int glXReleaseVideoDeviceNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice);
int glXBindVideoImageNV (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer);
int glXReleaseVideoImageNV (Display *dpy, GLXPbuffer pbuf);
int glXSendPbufferToVideoNV (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock);
int glXGetVideoInfoNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
#endif
#endif /* GLX_NV_video_out */
#ifndef GLX_OML_swap_method
#define GLX_OML_swap_method 1
#define GLX_SWAP_METHOD_OML 0x8060
#define GLX_SWAP_EXCHANGE_OML 0x8061
#define GLX_SWAP_COPY_OML 0x8062
#define GLX_SWAP_UNDEFINED_OML 0x8063
#endif /* GLX_OML_swap_method */
#ifndef GLX_OML_sync_control
#define GLX_OML_sync_control 1
#ifndef GLEXT_64_TYPES_DEFINED
/* This code block is duplicated in glext.h, so must be protected */
#define GLEXT_64_TYPES_DEFINED
/* Define int32_t, int64_t, and uint64_t types for UST/MSC */
/* (as used in the GLX_OML_sync_control extension). */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#include <inttypes.h>
#elif defined(__sun__) || defined(__digital__)
#include <inttypes.h>
#if defined(__STDC__)
#if defined(__arch64__) || defined(_LP64)
typedef long int int64_t;
typedef unsigned long int uint64_t;
#else
typedef long long int int64_t;
typedef unsigned long long int uint64_t;
#endif /* __arch64__ */
#endif /* __STDC__ */
#elif defined( __VMS ) || defined(__sgi)
#include <inttypes.h>
#elif defined(__SCO__) || defined(__USLC__)
#include <stdint.h>
#elif defined(__UNIXOS2__) || defined(__SOL64__)
typedef long int int32_t;
typedef long long int int64_t;
typedef unsigned long long int uint64_t;
#elif defined(_WIN32) && defined(__GNUC__)
#include <stdint.h>
#elif defined(_WIN32)
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
/* Fallback if nothing above works */
#include <inttypes.h>
#endif
#endif
typedef Bool ( *PFNGLXGETSYNCVALUESOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);
typedef Bool ( *PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
typedef int64_t ( *PFNGLXSWAPBUFFERSMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder);
typedef Bool ( *PFNGLXWAITFORMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);
typedef Bool ( *PFNGLXWAITFORSBCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);
#ifdef GLX_GLXEXT_PROTOTYPES
Bool glXGetSyncValuesOML (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);
Bool glXGetMscRateOML (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
int64_t glXSwapBuffersMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder);
Bool glXWaitForMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);
Bool glXWaitForSbcOML (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);
#endif
#endif /* GLX_OML_sync_control */
#ifndef GLX_SGIS_blended_overlay
#define GLX_SGIS_blended_overlay 1
#define GLX_BLENDED_RGBA_SGIS 0x8025
#endif /* GLX_SGIS_blended_overlay */
#ifndef GLX_SGIS_multisample
#define GLX_SGIS_multisample 1
#define GLX_SAMPLE_BUFFERS_SGIS 100000
#define GLX_SAMPLES_SGIS 100001
#endif /* GLX_SGIS_multisample */
#ifndef GLX_SGIS_shared_multisample
#define GLX_SGIS_shared_multisample 1
#define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026
#define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027
#endif /* GLX_SGIS_shared_multisample */
#ifndef GLX_SGIX_dmbuffer
#define GLX_SGIX_dmbuffer 1
typedef XID GLXPbufferSGIX;
#ifdef _DM_BUFFER_H_
#define GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024
typedef Bool ( *PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer);
#ifdef GLX_GLXEXT_PROTOTYPES
Bool glXAssociateDMPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer);
#endif
#endif /* _DM_BUFFER_H_ */
#endif /* GLX_SGIX_dmbuffer */
#ifndef GLX_SGIX_fbconfig
#define GLX_SGIX_fbconfig 1
typedef struct __GLXFBConfigRec *GLXFBConfigSGIX;
#define GLX_WINDOW_BIT_SGIX 0x00000001
#define GLX_PIXMAP_BIT_SGIX 0x00000002
#define GLX_RGBA_BIT_SGIX 0x00000001
#define GLX_COLOR_INDEX_BIT_SGIX 0x00000002
#define GLX_DRAWABLE_TYPE_SGIX 0x8010
#define GLX_RENDER_TYPE_SGIX 0x8011
#define GLX_X_RENDERABLE_SGIX 0x8012
#define GLX_FBCONFIG_ID_SGIX 0x8013
#define GLX_RGBA_TYPE_SGIX 0x8014
#define GLX_COLOR_INDEX_TYPE_SGIX 0x8015
typedef int ( *PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value);
typedef GLXFBConfigSGIX *( *PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements);
typedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap);
typedef GLXContext ( *PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct);
typedef XVisualInfo *( *PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config);
typedef GLXFBConfigSGIX ( *PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) (Display *dpy, XVisualInfo *vis);
#ifdef GLX_GLXEXT_PROTOTYPES
int glXGetFBConfigAttribSGIX (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value);
GLXFBConfigSGIX *glXChooseFBConfigSGIX (Display *dpy, int screen, int *attrib_list, int *nelements);
GLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap);
GLXContext glXCreateContextWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct);
XVisualInfo *glXGetVisualFromFBConfigSGIX (Display *dpy, GLXFBConfigSGIX config);
GLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *dpy, XVisualInfo *vis);
#endif
#endif /* GLX_SGIX_fbconfig */
#ifndef GLX_SGIX_hyperpipe
#define GLX_SGIX_hyperpipe 1
typedef struct {
char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
int networkId;
} GLXHyperpipeNetworkSGIX;
typedef struct {
char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
int channel;
unsigned int participationType;
int timeSlice;
} GLXHyperpipeConfigSGIX;
typedef struct {
char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
int srcXOrigin, srcYOrigin, srcWidth, srcHeight;
int destXOrigin, destYOrigin, destWidth, destHeight;
} GLXPipeRect;
typedef struct {
char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */
int XOrigin, YOrigin, maxHeight, maxWidth;
} GLXPipeRectLimits;
#define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80
#define GLX_BAD_HYPERPIPE_CONFIG_SGIX 91
#define GLX_BAD_HYPERPIPE_SGIX 92
#define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001
#define GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002
#define GLX_PIPE_RECT_SGIX 0x00000001
#define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002
#define GLX_HYPERPIPE_STEREO_SGIX 0x00000003
#define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004
#define GLX_HYPERPIPE_ID_SGIX 0x8030
typedef GLXHyperpipeNetworkSGIX *( *PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Display *dpy, int *npipes);
typedef int ( *PFNGLXHYPERPIPECONFIGSGIXPROC) (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId);
typedef GLXHyperpipeConfigSGIX *( *PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId, int *npipes);
typedef int ( *PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId);
typedef int ( *PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId);
typedef int ( *PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList);
typedef int ( *PFNGLXHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList);
typedef int ( *PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList);
#ifdef GLX_GLXEXT_PROTOTYPES
GLXHyperpipeNetworkSGIX *glXQueryHyperpipeNetworkSGIX (Display *dpy, int *npipes);
int glXHyperpipeConfigSGIX (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId);
GLXHyperpipeConfigSGIX *glXQueryHyperpipeConfigSGIX (Display *dpy, int hpId, int *npipes);
int glXDestroyHyperpipeConfigSGIX (Display *dpy, int hpId);
int glXBindHyperpipeSGIX (Display *dpy, int hpId);
int glXQueryHyperpipeBestAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList);
int glXHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList);
int glXQueryHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList);
#endif
#endif /* GLX_SGIX_hyperpipe */
#ifndef GLX_SGIX_pbuffer
#define GLX_SGIX_pbuffer 1
#define GLX_PBUFFER_BIT_SGIX 0x00000004
#define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000
#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001
#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002
#define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004
#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008
#define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010
#define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020
#define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040
#define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080
#define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100
#define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016
#define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017
#define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018
#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019
#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A
#define GLX_PRESERVED_CONTENTS_SGIX 0x801B
#define GLX_LARGEST_PBUFFER_SGIX 0x801C
#define GLX_WIDTH_SGIX 0x801D
#define GLX_HEIGHT_SGIX 0x801E
#define GLX_EVENT_MASK_SGIX 0x801F
#define GLX_DAMAGED_SGIX 0x8020
#define GLX_SAVED_SGIX 0x8021
#define GLX_WINDOW_SGIX 0x8022
#define GLX_PBUFFER_SGIX 0x8023
typedef GLXPbufferSGIX ( *PFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list);
typedef void ( *PFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf);
typedef int ( *PFNGLXQUERYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value);
typedef void ( *PFNGLXSELECTEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long mask);
typedef void ( *PFNGLXGETSELECTEDEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long *mask);
#ifdef GLX_GLXEXT_PROTOTYPES
GLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list);
void glXDestroyGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf);
int glXQueryGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value);
void glXSelectEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long mask);
void glXGetSelectedEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long *mask);
#endif
#endif /* GLX_SGIX_pbuffer */
#ifndef GLX_SGIX_swap_barrier
#define GLX_SGIX_swap_barrier 1
typedef void ( *PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier);
typedef Bool ( *PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max);
#ifdef GLX_GLXEXT_PROTOTYPES
void glXBindSwapBarrierSGIX (Display *dpy, GLXDrawable drawable, int barrier);
Bool glXQueryMaxSwapBarriersSGIX (Display *dpy, int screen, int *max);
#endif
#endif /* GLX_SGIX_swap_barrier */
#ifndef GLX_SGIX_swap_group
#define GLX_SGIX_swap_group 1
typedef void ( *PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member);
#ifdef GLX_GLXEXT_PROTOTYPES
void glXJoinSwapGroupSGIX (Display *dpy, GLXDrawable drawable, GLXDrawable member);
#endif
#endif /* GLX_SGIX_swap_group */
#ifndef GLX_SGIX_video_resize
#define GLX_SGIX_video_resize 1
#define GLX_SYNC_FRAME_SGIX 0x00000000
#define GLX_SYNC_SWAP_SGIX 0x00000001
typedef int ( *PFNGLXBINDCHANNELTOWINDOWSGIXPROC) (Display *display, int screen, int channel, Window window);
typedef int ( *PFNGLXCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int x, int y, int w, int h);
typedef int ( *PFNGLXQUERYCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh);
typedef int ( *PFNGLXQUERYCHANNELDELTASSGIXPROC) (Display *display, int screen, int channel, int *x, int *y, int *w, int *h);
typedef int ( *PFNGLXCHANNELRECTSYNCSGIXPROC) (Display *display, int screen, int channel, GLenum synctype);
#ifdef GLX_GLXEXT_PROTOTYPES
int glXBindChannelToWindowSGIX (Display *display, int screen, int channel, Window window);
int glXChannelRectSGIX (Display *display, int screen, int channel, int x, int y, int w, int h);
int glXQueryChannelRectSGIX (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh);
int glXQueryChannelDeltasSGIX (Display *display, int screen, int channel, int *x, int *y, int *w, int *h);
int glXChannelRectSyncSGIX (Display *display, int screen, int channel, GLenum synctype);
#endif
#endif /* GLX_SGIX_video_resize */
#ifndef GLX_SGIX_video_source
#define GLX_SGIX_video_source 1
typedef XID GLXVideoSourceSGIX;
#ifdef _VL_H
typedef GLXVideoSourceSGIX ( *PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode);
typedef void ( *PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource);
#ifdef GLX_GLXEXT_PROTOTYPES
GLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode);
void glXDestroyGLXVideoSourceSGIX (Display *dpy, GLXVideoSourceSGIX glxvideosource);
#endif
#endif /* _VL_H */
#endif /* GLX_SGIX_video_source */
#ifndef GLX_SGIX_visual_select_group
#define GLX_SGIX_visual_select_group 1
#define GLX_VISUAL_SELECT_GROUP_SGIX 0x8028
#endif /* GLX_SGIX_visual_select_group */
#ifndef GLX_SGI_cushion
#define GLX_SGI_cushion 1
typedef void ( *PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion);
#ifdef GLX_GLXEXT_PROTOTYPES
void glXCushionSGI (Display *dpy, Window window, float cushion);
#endif
#endif /* GLX_SGI_cushion */
#ifndef GLX_SGI_make_current_read
#define GLX_SGI_make_current_read 1
typedef Bool ( *PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
typedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void);
#ifdef GLX_GLXEXT_PROTOTYPES
Bool glXMakeCurrentReadSGI (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
GLXDrawable glXGetCurrentReadDrawableSGI (void);
#endif
#endif /* GLX_SGI_make_current_read */
#ifndef GLX_SGI_swap_control
#define GLX_SGI_swap_control 1
typedef int ( *PFNGLXSWAPINTERVALSGIPROC) (int interval);
#ifdef GLX_GLXEXT_PROTOTYPES
int glXSwapIntervalSGI (int interval);
#endif
#endif /* GLX_SGI_swap_control */
#ifndef GLX_SGI_video_sync
#define GLX_SGI_video_sync 1
typedef int ( *PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count);
typedef int ( *PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count);
#ifdef GLX_GLXEXT_PROTOTYPES
int glXGetVideoSyncSGI (unsigned int *count);
int glXWaitVideoSyncSGI (int divisor, int remainder, unsigned int *count);
#endif
#endif /* GLX_SGI_video_sync */
#ifndef GLX_SUN_get_transparent_index
#define GLX_SUN_get_transparent_index 1
typedef Status ( *PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex);
#ifdef GLX_GLXEXT_PROTOTYPES
Status glXGetTransparentIndexSUN (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex);
#endif
#endif /* GLX_SUN_get_transparent_index */
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

1448
third_party/GL/wglew.h vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,840 +0,0 @@
#ifndef __wglext_h_
#define __wglext_h_ 1
#ifdef __cplusplus
extern "C" {
#endif
/*
** Copyright (c) 2013-2014 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/*
** This header is generated from the Khronos OpenGL / OpenGL ES XML
** API Registry. The current version of the Registry, generator scripts
** used to make the header, and the header can be found at
** http://www.opengl.org/registry/
**
** Khronos $Revision: 27684 $ on $Date: 2014-08-11 01:21:35 -0700 (Mon, 11 Aug 2014) $
*/
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#endif
#define WGL_WGLEXT_VERSION 20140810
/* Generated C header for:
* API: wgl
* Versions considered: .*
* Versions emitted: _nomatch_^
* Default extensions included: wgl
* Additional extensions included: _nomatch_^
* Extensions removed: _nomatch_^
*/
#ifndef WGL_ARB_buffer_region
#define WGL_ARB_buffer_region 1
#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001
#define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002
#define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004
#define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008
typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType);
typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion);
typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height);
typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc);
#ifdef WGL_WGLEXT_PROTOTYPES
HANDLE WINAPI wglCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType);
VOID WINAPI wglDeleteBufferRegionARB (HANDLE hRegion);
BOOL WINAPI wglSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height);
BOOL WINAPI wglRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc);
#endif
#endif /* WGL_ARB_buffer_region */
#ifndef WGL_ARB_context_flush_control
#define WGL_ARB_context_flush_control 1
#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
#endif /* WGL_ARB_context_flush_control */
#ifndef WGL_ARB_create_context
#define WGL_ARB_create_context 1
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
#define WGL_CONTEXT_FLAGS_ARB 0x2094
#define ERROR_INVALID_VERSION_ARB 0x2095
typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);
#ifdef WGL_WGLEXT_PROTOTYPES
HGLRC WINAPI wglCreateContextAttribsARB (HDC hDC, HGLRC hShareContext, const int *attribList);
#endif
#endif /* WGL_ARB_create_context */
#ifndef WGL_ARB_create_context_profile
#define WGL_ARB_create_context_profile 1
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define ERROR_INVALID_PROFILE_ARB 0x2096
#endif /* WGL_ARB_create_context_profile */
#ifndef WGL_ARB_create_context_robustness
#define WGL_ARB_create_context_robustness 1
#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
#endif /* WGL_ARB_create_context_robustness */
#ifndef WGL_ARB_extensions_string
#define WGL_ARB_extensions_string 1
typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);
#ifdef WGL_WGLEXT_PROTOTYPES
const char *WINAPI wglGetExtensionsStringARB (HDC hdc);
#endif
#endif /* WGL_ARB_extensions_string */
#ifndef WGL_ARB_framebuffer_sRGB
#define WGL_ARB_framebuffer_sRGB 1
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
#endif /* WGL_ARB_framebuffer_sRGB */
#ifndef WGL_ARB_make_current_read
#define WGL_ARB_make_current_read 1
#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043
#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054
typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
HDC WINAPI wglGetCurrentReadDCARB (void);
#endif
#endif /* WGL_ARB_make_current_read */
#ifndef WGL_ARB_multisample
#define WGL_ARB_multisample 1
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
#define WGL_SAMPLES_ARB 0x2042
#endif /* WGL_ARB_multisample */
#ifndef WGL_ARB_pbuffer
#define WGL_ARB_pbuffer 1
DECLARE_HANDLE(HPBUFFERARB);
#define WGL_DRAW_TO_PBUFFER_ARB 0x202D
#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E
#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F
#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030
#define WGL_PBUFFER_LARGEST_ARB 0x2033
#define WGL_PBUFFER_WIDTH_ARB 0x2034
#define WGL_PBUFFER_HEIGHT_ARB 0x2035
#define WGL_PBUFFER_LOST_ARB 0x2036
typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer);
typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC);
typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer);
typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue);
#ifdef WGL_WGLEXT_PROTOTYPES
HPBUFFERARB WINAPI wglCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB hPbuffer);
int WINAPI wglReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC);
BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB hPbuffer);
BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue);
#endif
#endif /* WGL_ARB_pbuffer */
#ifndef WGL_ARB_pixel_format
#define WGL_ARB_pixel_format 1
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_DRAW_TO_BITMAP_ARB 0x2002
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_NEED_PALETTE_ARB 0x2004
#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
#define WGL_SWAP_METHOD_ARB 0x2007
#define WGL_NUMBER_OVERLAYS_ARB 0x2008
#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
#define WGL_TRANSPARENT_ARB 0x200A
#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
#define WGL_SHARE_DEPTH_ARB 0x200C
#define WGL_SHARE_STENCIL_ARB 0x200D
#define WGL_SHARE_ACCUM_ARB 0x200E
#define WGL_SUPPORT_GDI_ARB 0x200F
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_STEREO_ARB 0x2012
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_RED_BITS_ARB 0x2015
#define WGL_RED_SHIFT_ARB 0x2016
#define WGL_GREEN_BITS_ARB 0x2017
#define WGL_GREEN_SHIFT_ARB 0x2018
#define WGL_BLUE_BITS_ARB 0x2019
#define WGL_BLUE_SHIFT_ARB 0x201A
#define WGL_ALPHA_BITS_ARB 0x201B
#define WGL_ALPHA_SHIFT_ARB 0x201C
#define WGL_ACCUM_BITS_ARB 0x201D
#define WGL_ACCUM_RED_BITS_ARB 0x201E
#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_AUX_BUFFERS_ARB 0x2024
#define WGL_NO_ACCELERATION_ARB 0x2025
#define WGL_GENERIC_ACCELERATION_ARB 0x2026
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_SWAP_EXCHANGE_ARB 0x2028
#define WGL_SWAP_COPY_ARB 0x2029
#define WGL_SWAP_UNDEFINED_ARB 0x202A
#define WGL_TYPE_RGBA_ARB 0x202B
#define WGL_TYPE_COLORINDEX_ARB 0x202C
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);
BOOL WINAPI wglChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
#endif
#endif /* WGL_ARB_pixel_format */
#ifndef WGL_ARB_pixel_format_float
#define WGL_ARB_pixel_format_float 1
#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0
#endif /* WGL_ARB_pixel_format_float */
#ifndef WGL_ARB_render_texture
#define WGL_ARB_render_texture 1
#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070
#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071
#define WGL_TEXTURE_FORMAT_ARB 0x2072
#define WGL_TEXTURE_TARGET_ARB 0x2073
#define WGL_MIPMAP_TEXTURE_ARB 0x2074
#define WGL_TEXTURE_RGB_ARB 0x2075
#define WGL_TEXTURE_RGBA_ARB 0x2076
#define WGL_NO_TEXTURE_ARB 0x2077
#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078
#define WGL_TEXTURE_1D_ARB 0x2079
#define WGL_TEXTURE_2D_ARB 0x207A
#define WGL_MIPMAP_LEVEL_ARB 0x207B
#define WGL_CUBE_MAP_FACE_ARB 0x207C
#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D
#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E
#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F
#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080
#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081
#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082
#define WGL_FRONT_LEFT_ARB 0x2083
#define WGL_FRONT_RIGHT_ARB 0x2084
#define WGL_BACK_LEFT_ARB 0x2085
#define WGL_BACK_RIGHT_ARB 0x2086
#define WGL_AUX0_ARB 0x2087
#define WGL_AUX1_ARB 0x2088
#define WGL_AUX2_ARB 0x2089
#define WGL_AUX3_ARB 0x208A
#define WGL_AUX4_ARB 0x208B
#define WGL_AUX5_ARB 0x208C
#define WGL_AUX6_ARB 0x208D
#define WGL_AUX7_ARB 0x208E
#define WGL_AUX8_ARB 0x208F
#define WGL_AUX9_ARB 0x2090
typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);
typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);
typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer);
BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer);
BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList);
#endif
#endif /* WGL_ARB_render_texture */
#ifndef WGL_ARB_robustness_application_isolation
#define WGL_ARB_robustness_application_isolation 1
#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008
#endif /* WGL_ARB_robustness_application_isolation */
#ifndef WGL_ARB_robustness_share_group_isolation
#define WGL_ARB_robustness_share_group_isolation 1
#endif /* WGL_ARB_robustness_share_group_isolation */
#ifndef WGL_3DFX_multisample
#define WGL_3DFX_multisample 1
#define WGL_SAMPLE_BUFFERS_3DFX 0x2060
#define WGL_SAMPLES_3DFX 0x2061
#endif /* WGL_3DFX_multisample */
#ifndef WGL_3DL_stereo_control
#define WGL_3DL_stereo_control 1
#define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055
#define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056
#define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057
#define WGL_STEREO_POLARITY_INVERT_3DL 0x2058
typedef BOOL (WINAPI * PFNWGLSETSTEREOEMITTERSTATE3DLPROC) (HDC hDC, UINT uState);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglSetStereoEmitterState3DL (HDC hDC, UINT uState);
#endif
#endif /* WGL_3DL_stereo_control */
#ifndef WGL_AMD_gpu_association
#define WGL_AMD_gpu_association 1
#define WGL_GPU_VENDOR_AMD 0x1F00
#define WGL_GPU_RENDERER_STRING_AMD 0x1F01
#define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02
#define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2
#define WGL_GPU_RAM_AMD 0x21A3
#define WGL_GPU_CLOCK_AMD 0x21A4
#define WGL_GPU_NUM_PIPES_AMD 0x21A5
#define WGL_GPU_NUM_SIMD_AMD 0x21A6
#define WGL_GPU_NUM_RB_AMD 0x21A7
#define WGL_GPU_NUM_SPI_AMD 0x21A8
typedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids);
typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, int property, GLenum dataType, UINT size, void *data);
typedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc);
typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id);
typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList);
typedef BOOL (WINAPI * PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) (HGLRC hglrc);
typedef BOOL (WINAPI * PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (HGLRC hglrc);
typedef HGLRC (WINAPI * PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void);
typedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
#ifdef WGL_WGLEXT_PROTOTYPES
UINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids);
INT WINAPI wglGetGPUInfoAMD (UINT id, int property, GLenum dataType, UINT size, void *data);
UINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc);
HGLRC WINAPI wglCreateAssociatedContextAMD (UINT id);
HGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList);
BOOL WINAPI wglDeleteAssociatedContextAMD (HGLRC hglrc);
BOOL WINAPI wglMakeAssociatedContextCurrentAMD (HGLRC hglrc);
HGLRC WINAPI wglGetCurrentAssociatedContextAMD (void);
VOID WINAPI wglBlitContextFramebufferAMD (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
#endif
#endif /* WGL_AMD_gpu_association */
#ifndef WGL_ATI_pixel_format_float
#define WGL_ATI_pixel_format_float 1
#define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0
#endif /* WGL_ATI_pixel_format_float */
#ifndef WGL_EXT_create_context_es2_profile
#define WGL_EXT_create_context_es2_profile 1
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
#endif /* WGL_EXT_create_context_es2_profile */
#ifndef WGL_EXT_create_context_es_profile
#define WGL_EXT_create_context_es_profile 1
#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
#endif /* WGL_EXT_create_context_es_profile */
#ifndef WGL_EXT_depth_float
#define WGL_EXT_depth_float 1
#define WGL_DEPTH_FLOAT_EXT 0x2040
#endif /* WGL_EXT_depth_float */
#ifndef WGL_EXT_display_color_table
#define WGL_EXT_display_color_table 1
typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id);
typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length);
typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id);
typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id);
#ifdef WGL_WGLEXT_PROTOTYPES
GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort id);
GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *table, GLuint length);
GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort id);
VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort id);
#endif
#endif /* WGL_EXT_display_color_table */
#ifndef WGL_EXT_extensions_string
#define WGL_EXT_extensions_string 1
typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void);
#ifdef WGL_WGLEXT_PROTOTYPES
const char *WINAPI wglGetExtensionsStringEXT (void);
#endif
#endif /* WGL_EXT_extensions_string */
#ifndef WGL_EXT_framebuffer_sRGB
#define WGL_EXT_framebuffer_sRGB 1
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9
#endif /* WGL_EXT_framebuffer_sRGB */
#ifndef WGL_EXT_make_current_read
#define WGL_EXT_make_current_read 1
#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043
typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);
HDC WINAPI wglGetCurrentReadDCEXT (void);
#endif
#endif /* WGL_EXT_make_current_read */
#ifndef WGL_EXT_multisample
#define WGL_EXT_multisample 1
#define WGL_SAMPLE_BUFFERS_EXT 0x2041
#define WGL_SAMPLES_EXT 0x2042
#endif /* WGL_EXT_multisample */
#ifndef WGL_EXT_pbuffer
#define WGL_EXT_pbuffer 1
DECLARE_HANDLE(HPBUFFEREXT);
#define WGL_DRAW_TO_PBUFFER_EXT 0x202D
#define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E
#define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F
#define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030
#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031
#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032
#define WGL_PBUFFER_LARGEST_EXT 0x2033
#define WGL_PBUFFER_WIDTH_EXT 0x2034
#define WGL_PBUFFER_HEIGHT_EXT 0x2035
typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer);
typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC);
typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer);
typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue);
#ifdef WGL_WGLEXT_PROTOTYPES
HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);
HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT hPbuffer);
int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC);
BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT hPbuffer);
BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue);
#endif
#endif /* WGL_EXT_pbuffer */
#ifndef WGL_EXT_pixel_format
#define WGL_EXT_pixel_format 1
#define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000
#define WGL_DRAW_TO_WINDOW_EXT 0x2001
#define WGL_DRAW_TO_BITMAP_EXT 0x2002
#define WGL_ACCELERATION_EXT 0x2003
#define WGL_NEED_PALETTE_EXT 0x2004
#define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005
#define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006
#define WGL_SWAP_METHOD_EXT 0x2007
#define WGL_NUMBER_OVERLAYS_EXT 0x2008
#define WGL_NUMBER_UNDERLAYS_EXT 0x2009
#define WGL_TRANSPARENT_EXT 0x200A
#define WGL_TRANSPARENT_VALUE_EXT 0x200B
#define WGL_SHARE_DEPTH_EXT 0x200C
#define WGL_SHARE_STENCIL_EXT 0x200D
#define WGL_SHARE_ACCUM_EXT 0x200E
#define WGL_SUPPORT_GDI_EXT 0x200F
#define WGL_SUPPORT_OPENGL_EXT 0x2010
#define WGL_DOUBLE_BUFFER_EXT 0x2011
#define WGL_STEREO_EXT 0x2012
#define WGL_PIXEL_TYPE_EXT 0x2013
#define WGL_COLOR_BITS_EXT 0x2014
#define WGL_RED_BITS_EXT 0x2015
#define WGL_RED_SHIFT_EXT 0x2016
#define WGL_GREEN_BITS_EXT 0x2017
#define WGL_GREEN_SHIFT_EXT 0x2018
#define WGL_BLUE_BITS_EXT 0x2019
#define WGL_BLUE_SHIFT_EXT 0x201A
#define WGL_ALPHA_BITS_EXT 0x201B
#define WGL_ALPHA_SHIFT_EXT 0x201C
#define WGL_ACCUM_BITS_EXT 0x201D
#define WGL_ACCUM_RED_BITS_EXT 0x201E
#define WGL_ACCUM_GREEN_BITS_EXT 0x201F
#define WGL_ACCUM_BLUE_BITS_EXT 0x2020
#define WGL_ACCUM_ALPHA_BITS_EXT 0x2021
#define WGL_DEPTH_BITS_EXT 0x2022
#define WGL_STENCIL_BITS_EXT 0x2023
#define WGL_AUX_BUFFERS_EXT 0x2024
#define WGL_NO_ACCELERATION_EXT 0x2025
#define WGL_GENERIC_ACCELERATION_EXT 0x2026
#define WGL_FULL_ACCELERATION_EXT 0x2027
#define WGL_SWAP_EXCHANGE_EXT 0x2028
#define WGL_SWAP_COPY_EXT 0x2029
#define WGL_SWAP_UNDEFINED_EXT 0x202A
#define WGL_TYPE_RGBA_EXT 0x202B
#define WGL_TYPE_COLORINDEX_EXT 0x202C
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues);
typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues);
BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues);
BOOL WINAPI wglChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
#endif
#endif /* WGL_EXT_pixel_format */
#ifndef WGL_EXT_pixel_format_packed_float
#define WGL_EXT_pixel_format_packed_float 1
#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8
#endif /* WGL_EXT_pixel_format_packed_float */
#ifndef WGL_EXT_swap_control
#define WGL_EXT_swap_control 1
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglSwapIntervalEXT (int interval);
int WINAPI wglGetSwapIntervalEXT (void);
#endif
#endif /* WGL_EXT_swap_control */
#ifndef WGL_EXT_swap_control_tear
#define WGL_EXT_swap_control_tear 1
#endif /* WGL_EXT_swap_control_tear */
#ifndef WGL_I3D_digital_video_control
#define WGL_I3D_digital_video_control 1
#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050
#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051
#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052
#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053
typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue);
typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue);
BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue);
#endif
#endif /* WGL_I3D_digital_video_control */
#ifndef WGL_I3D_gamma
#define WGL_I3D_gamma 1
#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E
#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F
typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue);
typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue);
typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue);
typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue);
BOOL WINAPI wglSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue);
BOOL WINAPI wglGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue);
BOOL WINAPI wglSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue);
#endif
#endif /* WGL_I3D_gamma */
#ifndef WGL_I3D_genlock
#define WGL_I3D_genlock 1
#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044
#define WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D 0x2045
#define WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D 0x2046
#define WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D 0x2047
#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048
#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049
#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A
#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B
#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C
typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC);
typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC);
typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag);
typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource);
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource);
typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge);
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge);
typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate);
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate);
typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay);
typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay);
typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglEnableGenlockI3D (HDC hDC);
BOOL WINAPI wglDisableGenlockI3D (HDC hDC);
BOOL WINAPI wglIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag);
BOOL WINAPI wglGenlockSourceI3D (HDC hDC, UINT uSource);
BOOL WINAPI wglGetGenlockSourceI3D (HDC hDC, UINT *uSource);
BOOL WINAPI wglGenlockSourceEdgeI3D (HDC hDC, UINT uEdge);
BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge);
BOOL WINAPI wglGenlockSampleRateI3D (HDC hDC, UINT uRate);
BOOL WINAPI wglGetGenlockSampleRateI3D (HDC hDC, UINT *uRate);
BOOL WINAPI wglGenlockSourceDelayI3D (HDC hDC, UINT uDelay);
BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay);
BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay);
#endif
#endif /* WGL_I3D_genlock */
#ifndef WGL_I3D_image_buffer
#define WGL_I3D_image_buffer 1
#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001
#define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002
typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags);
typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress);
typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count);
typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count);
#ifdef WGL_WGLEXT_PROTOTYPES
LPVOID WINAPI wglCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags);
BOOL WINAPI wglDestroyImageBufferI3D (HDC hDC, LPVOID pAddress);
BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count);
BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count);
#endif
#endif /* WGL_I3D_image_buffer */
#ifndef WGL_I3D_swap_frame_lock
#define WGL_I3D_swap_frame_lock 1
typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void);
typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void);
typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag);
typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglEnableFrameLockI3D (void);
BOOL WINAPI wglDisableFrameLockI3D (void);
BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *pFlag);
BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *pFlag);
#endif
#endif /* WGL_I3D_swap_frame_lock */
#ifndef WGL_I3D_swap_frame_usage
#define WGL_I3D_swap_frame_usage 1
typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage);
typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void);
typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void);
typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglGetFrameUsageI3D (float *pUsage);
BOOL WINAPI wglBeginFrameTrackingI3D (void);
BOOL WINAPI wglEndFrameTrackingI3D (void);
BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage);
#endif
#endif /* WGL_I3D_swap_frame_usage */
#ifndef WGL_NV_DX_interop
#define WGL_NV_DX_interop 1
#define WGL_ACCESS_READ_ONLY_NV 0x00000000
#define WGL_ACCESS_READ_WRITE_NV 0x00000001
#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002
typedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle);
typedef HANDLE (WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice);
typedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice);
typedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access);
typedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject);
typedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access);
typedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects);
typedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglDXSetResourceShareHandleNV (void *dxObject, HANDLE shareHandle);
HANDLE WINAPI wglDXOpenDeviceNV (void *dxDevice);
BOOL WINAPI wglDXCloseDeviceNV (HANDLE hDevice);
HANDLE WINAPI wglDXRegisterObjectNV (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access);
BOOL WINAPI wglDXUnregisterObjectNV (HANDLE hDevice, HANDLE hObject);
BOOL WINAPI wglDXObjectAccessNV (HANDLE hObject, GLenum access);
BOOL WINAPI wglDXLockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects);
BOOL WINAPI wglDXUnlockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects);
#endif
#endif /* WGL_NV_DX_interop */
#ifndef WGL_NV_DX_interop2
#define WGL_NV_DX_interop2 1
#endif /* WGL_NV_DX_interop2 */
#ifndef WGL_NV_copy_image
#define WGL_NV_copy_image 1
typedef BOOL (WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglCopyImageSubDataNV (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);
#endif
#endif /* WGL_NV_copy_image */
#ifndef WGL_NV_delay_before_swap
#define WGL_NV_delay_before_swap 1
typedef BOOL (WINAPI * PFNWGLDELAYBEFORESWAPNVPROC) (HDC hDC, GLfloat seconds);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglDelayBeforeSwapNV (HDC hDC, GLfloat seconds);
#endif
#endif /* WGL_NV_delay_before_swap */
#ifndef WGL_NV_float_buffer
#define WGL_NV_float_buffer 1
#define WGL_FLOAT_COMPONENTS_NV 0x20B0
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3
#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4
#define WGL_TEXTURE_FLOAT_R_NV 0x20B5
#define WGL_TEXTURE_FLOAT_RG_NV 0x20B6
#define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7
#define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8
#endif /* WGL_NV_float_buffer */
#ifndef WGL_NV_gpu_affinity
#define WGL_NV_gpu_affinity 1
DECLARE_HANDLE(HGPUNV);
struct _GPU_DEVICE {
DWORD cb;
CHAR DeviceName[32];
CHAR DeviceString[128];
DWORD Flags;
RECT rcVirtualScreen;
};
typedef struct _GPU_DEVICE *PGPU_DEVICE;
#define ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0
#define ERROR_MISSING_AFFINITY_MASK_NV 0x20D1
typedef BOOL (WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu);
typedef BOOL (WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice);
typedef HDC (WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList);
typedef BOOL (WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu);
typedef BOOL (WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglEnumGpusNV (UINT iGpuIndex, HGPUNV *phGpu);
BOOL WINAPI wglEnumGpuDevicesNV (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice);
HDC WINAPI wglCreateAffinityDCNV (const HGPUNV *phGpuList);
BOOL WINAPI wglEnumGpusFromAffinityDCNV (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu);
BOOL WINAPI wglDeleteDCNV (HDC hdc);
#endif
#endif /* WGL_NV_gpu_affinity */
#ifndef WGL_NV_multisample_coverage
#define WGL_NV_multisample_coverage 1
#define WGL_COVERAGE_SAMPLES_NV 0x2042
#define WGL_COLOR_SAMPLES_NV 0x20B9
#endif /* WGL_NV_multisample_coverage */
#ifndef WGL_NV_present_video
#define WGL_NV_present_video 1
DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV);
#define WGL_NUM_VIDEO_SLOTS_NV 0x20F0
typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList);
typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue);
#ifdef WGL_WGLEXT_PROTOTYPES
int WINAPI wglEnumerateVideoDevicesNV (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList);
BOOL WINAPI wglBindVideoDeviceNV (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);
BOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue);
#endif
#endif /* WGL_NV_present_video */
#ifndef WGL_NV_render_depth_texture
#define WGL_NV_render_depth_texture 1
#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3
#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4
#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5
#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6
#define WGL_DEPTH_COMPONENT_NV 0x20A7
#endif /* WGL_NV_render_depth_texture */
#ifndef WGL_NV_render_texture_rectangle
#define WGL_NV_render_texture_rectangle 1
#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0
#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1
#define WGL_TEXTURE_RECTANGLE_NV 0x20A2
#endif /* WGL_NV_render_texture_rectangle */
#ifndef WGL_NV_swap_group
#define WGL_NV_swap_group 1
typedef BOOL (WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group);
typedef BOOL (WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier);
typedef BOOL (WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier);
typedef BOOL (WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers);
typedef BOOL (WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count);
typedef BOOL (WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglJoinSwapGroupNV (HDC hDC, GLuint group);
BOOL WINAPI wglBindSwapBarrierNV (GLuint group, GLuint barrier);
BOOL WINAPI wglQuerySwapGroupNV (HDC hDC, GLuint *group, GLuint *barrier);
BOOL WINAPI wglQueryMaxSwapGroupsNV (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers);
BOOL WINAPI wglQueryFrameCountNV (HDC hDC, GLuint *count);
BOOL WINAPI wglResetFrameCountNV (HDC hDC);
#endif
#endif /* WGL_NV_swap_group */
#ifndef WGL_NV_vertex_array_range
#define WGL_NV_vertex_array_range 1
typedef void *(WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);
typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer);
#ifdef WGL_WGLEXT_PROTOTYPES
void *WINAPI wglAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);
void WINAPI wglFreeMemoryNV (void *pointer);
#endif
#endif /* WGL_NV_vertex_array_range */
#ifndef WGL_NV_video_capture
#define WGL_NV_video_capture 1
DECLARE_HANDLE(HVIDEOINPUTDEVICENV);
#define WGL_UNIQUE_ID_NV 0x20CE
#define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF
typedef BOOL (WINAPI * PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice);
typedef UINT (WINAPI * PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList);
typedef BOOL (WINAPI * PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice);
typedef BOOL (WINAPI * PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue);
typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglBindVideoCaptureDeviceNV (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice);
UINT WINAPI wglEnumerateVideoCaptureDevicesNV (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList);
BOOL WINAPI wglLockVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice);
BOOL WINAPI wglQueryVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue);
BOOL WINAPI wglReleaseVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice);
#endif
#endif /* WGL_NV_video_capture */
#ifndef WGL_NV_video_output
#define WGL_NV_video_output 1
DECLARE_HANDLE(HPVIDEODEV);
#define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0
#define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1
#define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2
#define WGL_VIDEO_OUT_COLOR_NV 0x20C3
#define WGL_VIDEO_OUT_ALPHA_NV 0x20C4
#define WGL_VIDEO_OUT_DEPTH_NV 0x20C5
#define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6
#define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7
#define WGL_VIDEO_OUT_FRAME 0x20C8
#define WGL_VIDEO_OUT_FIELD_1 0x20C9
#define WGL_VIDEO_OUT_FIELD_2 0x20CA
#define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB
#define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC
typedef BOOL (WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice);
typedef BOOL (WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice);
typedef BOOL (WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer);
typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer);
typedef BOOL (WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock);
typedef BOOL (WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglGetVideoDeviceNV (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice);
BOOL WINAPI wglReleaseVideoDeviceNV (HPVIDEODEV hVideoDevice);
BOOL WINAPI wglBindVideoImageNV (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer);
BOOL WINAPI wglReleaseVideoImageNV (HPBUFFERARB hPbuffer, int iVideoBuffer);
BOOL WINAPI wglSendPbufferToVideoNV (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock);
BOOL WINAPI wglGetVideoInfoNV (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);
#endif
#endif /* WGL_NV_video_output */
#ifndef WGL_OML_sync_control
#define WGL_OML_sync_control 1
typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);
typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator);
typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);
typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);
typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);
#ifdef WGL_WGLEXT_PROTOTYPES
BOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);
BOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator);
INT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);
INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);
BOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);
BOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);
#endif
#endif /* WGL_OML_sync_control */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,55 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crunch", "crunch\crunch.2008.vcproj", "{8F645BA1-B996-49EB-859B-970A671DE05D}"
ProjectSection(ProjectDependencies) = postProject
{CF2E70E8-7133-4D96-92C7-68BB406C0664} = {CF2E70E8-7133-4D96-92C7-68BB406C0664}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crnlib", "crnlib\crnlib.2008.vcproj", "{CF2E70E8-7133-4D96-92C7-68BB406C0664}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug_DLL|Win32 = Debug_DLL|Win32
Debug_DLL|x64 = Debug_DLL|x64
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release_DLL|Win32 = Release_DLL|Win32
Release_DLL|x64 = Release_DLL|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug_DLL|Win32.ActiveCfg = Debug|Win32
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug_DLL|x64.ActiveCfg = Debug|x64
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug|Win32.ActiveCfg = Debug|Win32
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug|Win32.Build.0 = Debug|Win32
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug|x64.ActiveCfg = Debug|x64
{8F645BA1-B996-49EB-859B-970A671DE05D}.Debug|x64.Build.0 = Debug|x64
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release_DLL|Win32.ActiveCfg = Release|Win32
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release_DLL|x64.ActiveCfg = Release|x64
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release|Win32.ActiveCfg = Release|Win32
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release|Win32.Build.0 = Release|Win32
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release|x64.ActiveCfg = Release|x64
{8F645BA1-B996-49EB-859B-970A671DE05D}.Release|x64.Build.0 = Release|x64
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug_DLL|Win32.ActiveCfg = Debug_DLL|Win32
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug_DLL|Win32.Build.0 = Debug_DLL|Win32
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug|Win32.ActiveCfg = Debug|Win32
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug|Win32.Build.0 = Debug|Win32
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug|x64.ActiveCfg = Debug|x64
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Debug|x64.Build.0 = Debug|x64
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release_DLL|Win32.ActiveCfg = Release_DLL|Win32
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release_DLL|Win32.Build.0 = Release_DLL|Win32
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release_DLL|x64.ActiveCfg = Release_DLL|x64
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release_DLL|x64.Build.0 = Release_DLL|x64
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release|Win32.ActiveCfg = Release|Win32
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release|Win32.Build.0 = Release|Win32
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release|x64.ActiveCfg = Release|x64
{CF2E70E8-7133-4D96-92C7-68BB406C0664}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_workspace_file>
<Workspace title="Workspace">
<Project filename="crunch/crunch.cbp" active="1">
<Depends filename="crnlib/crnlib.cbp" />
</Project>
<Project filename="crnlib/crnlib.cbp" />
</Workspace>
</CodeBlocks_workspace_file>

View File

@ -1,74 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example1", "example1\example1.2008.vcproj", "{8F745B42-F996-49EB-859B-970A671DE05D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example2", "example2\example2.2008.vcproj", "{AF745B42-F996-49EB-859B-970A671DEF5E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example3", "example3\example3.2008.vcproj", "{AF745B42-E296-46EB-859B-970A671DEF5E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug_DLL|Win32 = Debug_DLL|Win32
Debug_DLL|x64 = Debug_DLL|x64
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release_DLL|Win32 = Release_DLL|Win32
Release_DLL|x64 = Release_DLL|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug_DLL|Win32.ActiveCfg = Debug_DLL|Win32
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug_DLL|Win32.Build.0 = Debug_DLL|Win32
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug|Win32.ActiveCfg = Debug|Win32
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug|Win32.Build.0 = Debug|Win32
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug|x64.ActiveCfg = Debug|x64
{8F745B42-F996-49EB-859B-970A671DE05D}.Debug|x64.Build.0 = Debug|x64
{8F745B42-F996-49EB-859B-970A671DE05D}.Release_DLL|Win32.ActiveCfg = Release_DLL|Win32
{8F745B42-F996-49EB-859B-970A671DE05D}.Release_DLL|Win32.Build.0 = Release_DLL|Win32
{8F745B42-F996-49EB-859B-970A671DE05D}.Release_DLL|x64.ActiveCfg = Release_DLL|x64
{8F745B42-F996-49EB-859B-970A671DE05D}.Release_DLL|x64.Build.0 = Release_DLL|x64
{8F745B42-F996-49EB-859B-970A671DE05D}.Release|Win32.ActiveCfg = Release|Win32
{8F745B42-F996-49EB-859B-970A671DE05D}.Release|Win32.Build.0 = Release|Win32
{8F745B42-F996-49EB-859B-970A671DE05D}.Release|x64.ActiveCfg = Release|x64
{8F745B42-F996-49EB-859B-970A671DE05D}.Release|x64.Build.0 = Release|x64
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug_DLL|Win32.ActiveCfg = Debug_DLL|Win32
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug_DLL|Win32.Build.0 = Debug_DLL|Win32
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug|Win32.ActiveCfg = Debug|Win32
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug|Win32.Build.0 = Debug|Win32
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug|x64.ActiveCfg = Debug|x64
{AF745B42-F996-49EB-859B-970A671DEF5E}.Debug|x64.Build.0 = Debug|x64
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release_DLL|Win32.ActiveCfg = Release_DLL|Win32
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release_DLL|Win32.Build.0 = Release_DLL|Win32
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release_DLL|x64.ActiveCfg = Release_DLL|x64
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release_DLL|x64.Build.0 = Release_DLL|x64
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release|Win32.ActiveCfg = Release|Win32
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release|Win32.Build.0 = Release|Win32
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release|x64.ActiveCfg = Release|x64
{AF745B42-F996-49EB-859B-970A671DEF5E}.Release|x64.Build.0 = Release|x64
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug_DLL|Win32.ActiveCfg = Debug_DLL|Win32
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug_DLL|Win32.Build.0 = Debug_DLL|Win32
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug|Win32.ActiveCfg = Debug|Win32
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug|Win32.Build.0 = Debug|Win32
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug|x64.ActiveCfg = Debug|x64
{AF745B42-E296-46EB-859B-970A671DEF5E}.Debug|x64.Build.0 = Debug|x64
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release_DLL|Win32.ActiveCfg = Release_DLL|Win32
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release_DLL|Win32.Build.0 = Release_DLL|Win32
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release_DLL|x64.ActiveCfg = Release_DLL|x64
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release_DLL|x64.Build.0 = Release_DLL|x64
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release|Win32.ActiveCfg = Release|Win32
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release|Win32.Build.0 = Release|Win32
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release|x64.ActiveCfg = Release|x64
{AF745B42-E296-46EB-859B-970A671DEF5E}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_workspace_file>
<Workspace title="Workspace">
<Project filename="crunch/crunch_linux.cbp" active="1">
<Depends filename="crnlib/crnlib_linux.cbp" />
</Project>
<Project filename="crnlib/crnlib_linux.cbp" />
</Workspace>
</CodeBlocks_workspace_file>

View File

@ -1,96 +0,0 @@
COMPILE_OPTIONS = -O3 -fomit-frame-pointer -ffast-math -fno-math-errno -g -fno-strict-aliasing -Wall -Wno-unused-value -Wno-unused -march=core2
LINKER_OPTIONS = -lpthread -g
OBJECTS = \
crn_arealist.o \
crn_assert.o \
crn_checksum.o \
crn_colorized_console.o \
crn_command_line_params.o \
crn_comp.o \
crn_console.o \
crn_core.o \
crn_data_stream.o \
crn_mipmapped_texture.o \
crn_decomp.o \
crn_dxt1.o \
crn_dxt5a.o \
crn_dxt.o \
crn_dxt_endpoint_refiner.o \
crn_dxt_fast.o \
crn_dxt_hc_common.o \
crn_dxt_hc.o \
crn_dxt_image.o \
crn_dynamic_string.o \
crn_file_utils.o \
crn_find_files.o \
crn_hash.o \
crn_hash_map.o \
crn_huffman_codes.o \
crn_image_utils.o \
crnlib.o \
crn_math.o \
crn_mem.o \
crn_pixel_format.o \
crn_platform.o \
crn_prefix_coding.o \
crn_qdxt1.o \
crn_qdxt5.o \
crn_rand.o \
crn_resample_filters.o \
crn_resampler.o \
crn_ryg_dxt.o \
crn_sparse_bit_array.o \
crn_stb_image.o \
crn_strutils.o \
crn_symbol_codec.o \
crn_texture_file_types.o \
crn_threaded_resampler.o \
crn_threading_pthreads.o \
crn_timer.o \
crn_utils.o \
crn_value.o \
crn_vector.o \
crn_zeng.o \
crn_texture_comp.o \
crn_texture_conversion.o \
crn_dds_comp.o \
crn_lzma_codec.o \
crn_ktx_texture.o \
crn_etc.o \
crn_rg_etc1.o \
crn_miniz.o \
crn_jpge.o \
crn_jpgd.o \
lzma_7zBuf2.o \
lzma_7zBuf.o \
lzma_7zCrc.o \
lzma_7zFile.o \
lzma_7zStream.o \
lzma_Alloc.o \
lzma_Bcj2.o \
lzma_Bra86.o \
lzma_Bra.o \
lzma_BraIA64.o \
lzma_LzFind.o \
lzma_LzmaDec.o \
lzma_LzmaEnc.o \
lzma_LzmaLib.o
all: crunch
%.o: %.cpp
g++ $< -o $@ -c $(COMPILE_OPTIONS)
crunch.o: ../crunch/crunch.cpp
g++ $< -o $@ -c -I../inc -I../crnlib $(COMPILE_OPTIONS)
corpus_gen.o: ../crunch/corpus_gen.cpp
g++ $< -o $@ -c -I../inc -I../crnlib $(COMPILE_OPTIONS)
corpus_test.o: ../crunch/corpus_test.cpp
g++ $< -o $@ -c -I../inc -I../crnlib $(COMPILE_OPTIONS)
crunch: $(OBJECTS) crunch.o corpus_gen.o corpus_test.o
g++ $(OBJECTS) crunch.o corpus_gen.o corpus_test.o -o crunch $(LINKER_OPTIONS)

View File

@ -1,698 +0,0 @@
// File: crn_arealist.cpp - 2D shape algebra (currently unused)
// See Copyright Notice and license at the end of inc/crnlib.h
// Ported from the PowerView DOS image viewer, a product I wrote back in 1993. Not currently used in the open source release of crnlib.
#include "crn_core.h"
#include "crn_arealist.h"
#define RECT_DEBUG
namespace crnlib
{
static void area_fatal_error(const char* pFunc, const char* pMsg, ...)
{
pFunc;
va_list args;
va_start(args, pMsg);
char buf[512];
#ifdef _MSC_VER
_vsnprintf_s(buf, sizeof(buf), pMsg, args);
#else
vsnprintf(buf, sizeof(buf), pMsg, args);
#endif
va_end(args);
CRNLIB_FAIL(buf);
}
static Area * delete_area(Area_List *Plist, Area *Parea)
{
Area *p, *q;
#ifdef RECT_DEBUG
if ((Parea == Plist->Phead) || (Parea == Plist->Ptail))
area_fatal_error("delete_area", "tried to remove head or tail");
#endif
p = Parea->Pprev;
q = Parea->Pnext;
p->Pnext = q;
q->Pprev = p;
Parea->Pnext = Plist->Pfree;
Parea->Pprev = NULL;
Plist->Pfree = Parea;
return (q);
}
static Area * alloc_area(Area_List *Plist)
{
Area *p = Plist->Pfree;
if (p == NULL)
{
if (Plist->next_free == Plist->total_areas)
area_fatal_error("alloc_area", "Out of areas!");
p = Plist->Phead + Plist->next_free;
Plist->next_free++;
}
else
Plist->Pfree = p->Pnext;
return (p);
}
static Area * insert_area_before(Area_List *Plist, Area *Parea,
int x1, int y1, int x2, int y2)
{
Area *p, *Pnew_area = alloc_area(Plist);
p = Parea->Pprev;
p->Pnext = Pnew_area;
Pnew_area->Pprev = p;
Pnew_area->Pnext = Parea;
Parea->Pprev = Pnew_area;
Pnew_area->x1 = x1;
Pnew_area->y1 = y1;
Pnew_area->x2 = x2;
Pnew_area->y2 = y2;
return (Pnew_area);
}
static Area * insert_area_after(Area_List *Plist, Area *Parea,
int x1, int y1, int x2, int y2)
{
Area *p, *Pnew_area = alloc_area(Plist);
p = Parea->Pnext;
p->Pprev = Pnew_area;
Pnew_area->Pnext = p;
Pnew_area->Pprev = Parea;
Parea->Pnext = Pnew_area;
Pnew_area->x1 = x1;
Pnew_area->y1 = y1;
Pnew_area->x2 = x2;
Pnew_area->y2 = y2;
return (Pnew_area);
}
void Area_List_deinit(Area_List* Pobj_base)
{
Area_List *Plist = (Area_List *)Pobj_base;
if (!Plist)
return;
if (Plist->Phead)
{
crnlib_free(Plist->Phead);
Plist->Phead = NULL;
}
crnlib_free(Plist);
}
Area_List * Area_List_init(int max_areas)
{
Area_List *Plist = (Area_List*)crnlib_calloc(1, sizeof(Area_List));
Plist->total_areas = max_areas + 2;
Plist->Phead = (Area *)crnlib_calloc(max_areas + 2, sizeof(Area));
Plist->Ptail = Plist->Phead + 1;
Plist->Phead->Pprev = NULL;
Plist->Phead->Pnext = Plist->Ptail;
Plist->Ptail->Pprev = Plist->Phead;
Plist->Ptail->Pnext = NULL;
Plist->Pfree = NULL;
Plist->next_free = 2;
return (Plist);
}
void Area_List_print(Area_List *Plist)
{
Area *Parea = Plist->Phead->Pnext;
while (Parea != Plist->Ptail)
{
printf("%04i %04i : %04i %04i\n", Parea->x1, Parea->y1, Parea->x2, Parea->y2);
Parea = Parea->Pnext;
}
}
Area_List * Area_List_dup_new(Area_List *Plist,
int x_ofs, int y_ofs)
{
int i;
Area_List *Pnew_list = (Area_List*)crnlib_calloc(1, sizeof(Area_List));
Pnew_list->total_areas = Plist->total_areas;
Pnew_list->Phead = (Area *)crnlib_malloc(sizeof(Area) * Plist->total_areas);
Pnew_list->Ptail = Pnew_list->Phead + 1;
Pnew_list->Pfree = (Plist->Pfree) ? ((Plist->Pfree - Plist->Phead) + Pnew_list->Phead) : NULL;
Pnew_list->next_free = Plist->next_free;
memcpy(Pnew_list->Phead, Plist->Phead, sizeof(Area) * Plist->total_areas);
for (i = 0; i < Plist->total_areas; i++)
{
Pnew_list->Phead[i].Pnext = (Plist->Phead[i].Pnext == NULL) ? NULL : (Plist->Phead[i].Pnext - Plist->Phead) + Pnew_list->Phead;
Pnew_list->Phead[i].Pprev = (Plist->Phead[i].Pprev == NULL) ? NULL : (Plist->Phead[i].Pprev - Plist->Phead) + Pnew_list->Phead;
Pnew_list->Phead[i].x1 += x_ofs;
Pnew_list->Phead[i].y1 += y_ofs;
Pnew_list->Phead[i].x2 += x_ofs;
Pnew_list->Phead[i].y2 += y_ofs;
}
return (Pnew_list);
}
uint Area_List_get_num(Area_List* Plist)
{
uint num = 0;
Area *Parea = Plist->Phead->Pnext;
while (Parea != Plist->Ptail)
{
num++;
Parea = Parea->Pnext;
}
return num;
}
void Area_List_dup(Area_List *Psrc_list, Area_List *Pdst_list,
int x_ofs, int y_ofs)
{
int i;
if (Psrc_list->total_areas != Pdst_list->total_areas)
area_fatal_error("Area_List_dup", "Src and Dst total_areas must be equal!");
Pdst_list->Pfree = (Psrc_list->Pfree) ? ((Psrc_list->Pfree - Psrc_list->Phead) + Pdst_list->Phead) : NULL;
Pdst_list->next_free = Psrc_list->next_free;
memcpy(Pdst_list->Phead, Psrc_list->Phead, sizeof(Area) * Psrc_list->total_areas);
if ((x_ofs) || (y_ofs))
{
for (i = 0; i < Psrc_list->total_areas; i++)
{
Pdst_list->Phead[i].Pnext = (Psrc_list->Phead[i].Pnext == NULL) ? NULL : (Psrc_list->Phead[i].Pnext - Psrc_list->Phead) + Pdst_list->Phead;
Pdst_list->Phead[i].Pprev = (Psrc_list->Phead[i].Pprev == NULL) ? NULL : (Psrc_list->Phead[i].Pprev - Psrc_list->Phead) + Pdst_list->Phead;
Pdst_list->Phead[i].x1 += x_ofs;
Pdst_list->Phead[i].y1 += y_ofs;
Pdst_list->Phead[i].x2 += x_ofs;
Pdst_list->Phead[i].y2 += y_ofs;
}
}
else
{
for (i = 0; i < Psrc_list->total_areas; i++)
{
Pdst_list->Phead[i].Pnext = (Psrc_list->Phead[i].Pnext == NULL) ? NULL : (Psrc_list->Phead[i].Pnext - Psrc_list->Phead) + Pdst_list->Phead;
Pdst_list->Phead[i].Pprev = (Psrc_list->Phead[i].Pprev == NULL) ? NULL : (Psrc_list->Phead[i].Pprev - Psrc_list->Phead) + Pdst_list->Phead;
}
}
}
void Area_List_copy(
Area_List *Psrc_list, Area_List *Pdst_list,
int x_ofs, int y_ofs)
{
Area *Parea = Psrc_list->Phead->Pnext;
Area_List_clear(Pdst_list);
if ((x_ofs) || (y_ofs))
{
Area *Pprev_area = Pdst_list->Phead;
while (Parea != Psrc_list->Ptail)
{
// Area *p, *Pnew_area;
Area *Pnew_area;
if (Pdst_list->next_free == Pdst_list->total_areas)
area_fatal_error("Area_List_copy", "Out of areas!");
Pnew_area = Pdst_list->Phead + Pdst_list->next_free;
Pdst_list->next_free++;
Pnew_area->Pprev = Pprev_area;
Pprev_area->Pnext = Pnew_area;
Pnew_area->x1 = Parea->x1 + x_ofs;
Pnew_area->y1 = Parea->y1 + y_ofs;
Pnew_area->x2 = Parea->x2 + x_ofs;
Pnew_area->y2 = Parea->y2 + y_ofs;
Pprev_area = Pnew_area;
Parea = Parea->Pnext;
}
Pprev_area->Pnext = Pdst_list->Ptail;
}
else
{
#if 0
while (Parea != Psrc_list->Ptail)
{
insert_area_after(Pdst_list, Pdst_list->Phead,
Parea->x1,
Parea->y1,
Parea->x2,
Parea->y2);
Parea = Parea->Pnext;
}
#endif
Area *Pprev_area = Pdst_list->Phead;
while (Parea != Psrc_list->Ptail)
{
// Area *p, *Pnew_area;
Area *Pnew_area;
if (Pdst_list->next_free == Pdst_list->total_areas)
area_fatal_error("Area_List_copy", "Out of areas!");
Pnew_area = Pdst_list->Phead + Pdst_list->next_free;
Pdst_list->next_free++;
Pnew_area->Pprev = Pprev_area;
Pprev_area->Pnext = Pnew_area;
Pnew_area->x1 = Parea->x1;
Pnew_area->y1 = Parea->y1;
Pnew_area->x2 = Parea->x2;
Pnew_area->y2 = Parea->y2;
Pprev_area = Pnew_area;
Parea = Parea->Pnext;
}
Pprev_area->Pnext = Pdst_list->Ptail;
}
}
void Area_List_clear(Area_List *Plist)
{
Plist->Phead->Pnext = Plist->Ptail;
Plist->Ptail->Pprev = Plist->Phead;
Plist->Pfree = NULL;
Plist->next_free = 2;
}
void Area_List_set(Area_List *Plist, int x1, int y1, int x2, int y2)
{
Plist->Pfree = NULL;
Plist->Phead[2].x1 = x1;
Plist->Phead[2].y1 = y1;
Plist->Phead[2].x2 = x2;
Plist->Phead[2].y2 = y2;
Plist->Phead[2].Pprev = Plist->Phead;
Plist->Phead->Pnext = Plist->Phead + 2;
Plist->Phead[2].Pnext = Plist->Ptail;
Plist->Ptail->Pprev = Plist->Phead + 2;
Plist->next_free = 3;
}
void Area_List_remove(Area_List *Plist,
int x1, int y1, int x2, int y2)
{
int l, h;
Area *Parea = Plist->Phead->Pnext;
#ifdef RECT_DEBUG
if ((x1 > x2) || (y1 > y2))
area_fatal_error("area_list_remove", "invalid coords: %i %i %i %i", x1, y1, x2, y2);
#endif
while (Parea != Plist->Ptail)
{
// Not touching
if ((x2 < Parea->x1) || (x1 > Parea->x2) ||
(y2 < Parea->y1) || (y1 > Parea->y2))
{
Parea = Parea->Pnext;
continue;
}
// Completely covers
if ((x1 <= Parea->x1) && (x2 >= Parea->x2) &&
(y1 <= Parea->y1) && (y2 >= Parea->y2))
{
if ((x1 == Parea->x1) && (x2 == Parea->x2) &&
(y1 == Parea->y1) && (y2 == Parea->y2))
{
delete_area(Plist, Parea);
return;
}
Parea = delete_area(Plist, Parea);
continue;
}
// top
if (y1 > Parea->y1)
{
insert_area_before(Plist, Parea,
Parea->x1, Parea->y1,
Parea->x2, y1 - 1);
}
// bottom
if (y2 < Parea->y2)
{
insert_area_before(Plist, Parea,
Parea->x1, y2 + 1,
Parea->x2, Parea->y2);
}
l = math::maximum(y1, Parea->y1);
h = math::minimum(y2, Parea->y2);
// left middle
if (x1 > Parea->x1)
{
insert_area_before(Plist, Parea,
Parea->x1, l,
x1 - 1, h);
}
// right middle
if (x2 < Parea->x2)
{
insert_area_before(Plist, Parea,
x2 + 1, l,
Parea->x2, h);
}
// early out - we know there's nothing else to remove, as areas can
// never overlap
if ((x1 >= Parea->x1) && (x2 <= Parea->x2) &&
(y1 >= Parea->y1) && (y2 <= Parea->y2))
{
delete_area(Plist, Parea);
return;
}
Parea = delete_area(Plist, Parea);
}
}
void Area_List_insert(Area_List *Plist,
int x1, int y1, int x2, int y2,
bool combine)
{
Area *Parea = Plist->Phead->Pnext;
#ifdef RECT_DEBUG
if ((x1 > x2) || (y1 > y2))
area_fatal_error("Area_List_insert", "invalid coords: %i %i %i %i", x1, y1, x2, y2);
#endif
while (Parea != Plist->Ptail)
{
// totally covers
if ((x1 <= Parea->x1) && (x2 >= Parea->x2) &&
(y1 <= Parea->y1) && (y2 >= Parea->y2))
{
Parea = delete_area(Plist, Parea);
continue;
}
// intersects
if ((x2 >= Parea->x1) && (x1 <= Parea->x2) &&
(y2 >= Parea->y1) && (y1 <= Parea->y2))
{
int ax1, ay1, ax2, ay2;
ax1 = Parea->x1;
ay1 = Parea->y1;
ax2 = Parea->x2;
ay2 = Parea->y2;
if (x1 < ax1)
Area_List_insert(Plist, x1, math::maximum(y1, ay1), ax1 - 1, math::minimum(y2, ay2), combine);
if (x2 > ax2)
Area_List_insert(Plist, ax2 + 1, math::maximum(y1, ay1), x2, math::minimum(y2, ay2), combine);
if (y1 < ay1)
Area_List_insert(Plist, x1, y1, x2, ay1 - 1, combine);
if (y2 > ay2)
Area_List_insert(Plist, x1, ay2 + 1, x2, y2, combine);
return;
}
if (combine)
{
if ((x1 == Parea->x1) && (x2 == Parea->x2))
{
if ((y2 == Parea->y1 - 1) || (y1 == Parea->y2 + 1))
{
delete_area(Plist, Parea);
Area_List_insert(Plist, x1, math::minimum(y1, Parea->y1), x2, math::maximum(y2, Parea->y2), CRNLIB_TRUE);
return;
}
}
else if ((y1 == Parea->y1) && (y2 == Parea->y2))
{
if ((x2 == Parea->x1 - 1) || (x1 == Parea->x2 + 1))
{
delete_area(Plist, Parea);
Area_List_insert(Plist, math::minimum(x1, Parea->x1), y1, math::maximum(x2, Parea->x2), y2, CRNLIB_TRUE);
return;
}
}
}
Parea = Parea->Pnext;
}
insert_area_before(Plist, Parea, x1, y1, x2, y2);
}
void Area_List_intersect_area(Area_List *Plist,
int x1, int y1, int x2, int y2)
{
Area *Parea = Plist->Phead->Pnext;
while (Parea != Plist->Ptail)
{
// doesn't cover
if ((x2 < Parea->x1) || (x1 > Parea->x2) ||
(y2 < Parea->y1) || (y1 > Parea->y2))
{
Parea = delete_area(Plist, Parea);
continue;
}
// totally covers
if ((x1 <= Parea->x1) && (x2 >= Parea->x2) &&
(y1 <= Parea->y1) && (y2 >= Parea->y2))
{
Parea = Parea->Pnext;
continue;
}
// Oct 21- should insert after, because deleted area will access the NEXT area!
// insert_area_after(Plist, Parea,
// math::maximum(x1, Parea->x1),
// math::maximum(y1, Parea->y1),
// math::minimum(x2, Parea->x2),
// math::minimum(y2, Parea->y2));
insert_area_before(Plist, Parea,
math::maximum(x1, Parea->x1),
math::maximum(y1, Parea->y1),
math::minimum(x2, Parea->x2),
math::minimum(y2, Parea->y2));
Parea = delete_area(Plist, Parea);
}
}
#if 0
void Area_List_intersect_Area_List(
Area_List *Pouter_list,
Area_List *Pinner_list,
Area_List *Pdst_list)
{
Area *Parea1 = Pouter_list->Phead->Pnext;
while (Parea1 != Pouter_list->Ptail)
{
Area *Parea2 = Pinner_list->Phead->Pnext;
int x1, y1, x2, y2;
x1 = Parea1->x1; x2 = Parea1->x2;
y1 = Parea1->y1; y2 = Parea1->y2;
while (Parea2 != Pinner_list->Ptail)
{
if ((x1 <= Parea2->x2) && (x2 >= Parea2->x1) &&
(y1 <= Parea2->y2) && (y2 >= Parea2->y1))
{
insert_area_after(Pdst_list, Pdst_list->Phead,
math::maximum(x1, Parea2->x1),
math::maximum(y1, Parea2->y1),
math::minimum(x2, Parea2->x2),
math::minimum(y2, Parea2->y2));
}
Parea2 = Parea2->Pnext;
}
Parea1 = Parea1->Pnext;
}
}
#endif
#if 1
void Area_List_intersect_Area_List(Area_List *Pouter_list,
Area_List *Pinner_list,
Area_List *Pdst_list)
{
Area *Parea1 = Pouter_list->Phead->Pnext;
while (Parea1 != Pouter_list->Ptail)
{
Area *Parea2 = Pinner_list->Phead->Pnext;
int x1, y1, x2, y2;
x1 = Parea1->x1; x2 = Parea1->x2;
y1 = Parea1->y1; y2 = Parea1->y2;
while (Parea2 != Pinner_list->Ptail)
{
if ((x1 <= Parea2->x2) && (x2 >= Parea2->x1) &&
(y1 <= Parea2->y2) && (y2 >= Parea2->y1))
{
int nx1, ny1, nx2, ny2;
nx1 = math::maximum(x1, Parea2->x1);
ny1 = math::maximum(y1, Parea2->y1);
nx2 = math::minimum(x2, Parea2->x2);
ny2 = math::minimum(y2, Parea2->y2);
if (Pdst_list->Phead->Pnext == Pdst_list->Ptail)
{
insert_area_after(Pdst_list, Pdst_list->Phead,
nx1, ny1, nx2, ny2);
}
else
{
Area_Ptr Ptemp = Pdst_list->Phead->Pnext;
if ((Ptemp->x1 == nx1) && (Ptemp->x2 == nx2))
{
if (Ptemp->y1 == (ny2+1))
{
Ptemp->y1 = ny1;
goto next;
}
else if (Ptemp->y2 == (ny1-1))
{
Ptemp->y2 = ny2;
goto next;
}
}
else if ((Ptemp->y1 == ny1) && (Ptemp->y2 == ny2))
{
if (Ptemp->x1 == (nx2+1))
{
Ptemp->x1 = nx1;
goto next;
}
else if (Ptemp->x2 == (nx1-1))
{
Ptemp->x2 = nx2;
goto next;
}
}
insert_area_after(Pdst_list, Pdst_list->Phead,
nx1, ny1, nx2, ny2);
}
}
next:
Parea2 = Parea2->Pnext;
}
Parea1 = Parea1->Pnext;
}
}
#endif
Area_List_Ptr Area_List_create_optimal(Area_List_Ptr Plist)
{
Area_Ptr Parea = Plist->Phead->Pnext, Parea_after;
int num = 2;
Area_List_Ptr Pnew_list;
while (Parea != Plist->Ptail)
{
num++;
Parea = Parea->Pnext;
}
Pnew_list = Area_List_init(num);
Parea = Plist->Phead->Pnext;
Parea_after = Pnew_list->Phead;
while (Parea != Plist->Ptail)
{
Parea_after = insert_area_after(Pnew_list, Parea_after,
Parea->x1, Parea->y1,
Parea->x2, Parea->y2);
Parea = Parea->Pnext;
}
return (Pnew_list);
}
} // namespace crnlib

Some files were not shown because too many files have changed in this diff Show More