1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

UpdateF, dx reinit

This commit is contained in:
Brian Fiete 2022-05-15 08:00:55 -07:00
parent fa2cb7ba56
commit e87bf5b029
24 changed files with 1029 additions and 415 deletions

View file

@ -45,7 +45,8 @@ namespace Beefy
#endif #endif
{ {
public delegate void UpdateDelegate(bool batchStart); public delegate void UpdateDelegate(bool batchStart);
public delegate void DrawDelegate(); public delegate void UpdateFDelegate(float updatePct);
public delegate void DrawDelegate(bool forceDraw);
public static BFApp sApp; public static BFApp sApp;
public int32 mUpdateCnt; public int32 mUpdateCnt;
@ -106,7 +107,7 @@ namespace Beefy
static extern void BFApp_Shutdown(); static extern void BFApp_Shutdown();
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
static extern void BFApp_SetCallbacks(void* updateDelegate, void* drawDelegate); static extern void BFApp_SetCallbacks(void* updateDelegate, void* updateFDelegate, void* drawDelegate);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
static extern char8* BFApp_GetInstallDir(); static extern char8* BFApp_GetInstallDir();
@ -132,7 +133,11 @@ namespace Beefy
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
public static extern void* BFApp_GetSoundManager(); public static extern void* BFApp_GetSoundManager();
[CallingConvention(.Stdcall), CLink]
public static extern int BFApp_GetCriticalThreadId(int32 idx);
UpdateDelegate mUpdateDelegate ~ delete _; UpdateDelegate mUpdateDelegate ~ delete _;
UpdateFDelegate mUpdateFDelegate ~ delete _;
DrawDelegate mDrawDelegate ~ delete _; DrawDelegate mDrawDelegate ~ delete _;
#if STUDIO_CLIENT #if STUDIO_CLIENT
@ -165,9 +170,9 @@ namespace Beefy
} }
#endif #endif
static void Static_Draw() static void Static_Draw(bool forceDraw)
{ {
sApp.Draw(); sApp.Draw(forceDraw);
} }
static void Static_Update(bool batchStart) static void Static_Update(bool batchStart)
@ -175,6 +180,11 @@ namespace Beefy
sApp.Update(batchStart); sApp.Update(batchStart);
} }
static void Static_UpdateF(float updatePct)
{
sApp.UpdateF(updatePct);
}
float mLastUpdateDelta; // In seconds float mLastUpdateDelta; // In seconds
public this() public this()
@ -198,9 +208,10 @@ namespace Beefy
BFApp_SetRefreshRate(mRefreshRate); BFApp_SetRefreshRate(mRefreshRate);
mUpdateDelegate = new => Static_Update; mUpdateDelegate = new => Static_Update;
mUpdateFDelegate = new => Static_UpdateF;
mDrawDelegate = new => Static_Draw; mDrawDelegate = new => Static_Draw;
#endif #endif
BFApp_SetCallbacks(mUpdateDelegate.GetFuncPtr(), mDrawDelegate.GetFuncPtr()); BFApp_SetCallbacks(mUpdateDelegate.GetFuncPtr(), mUpdateFDelegate.GetFuncPtr(), mDrawDelegate.GetFuncPtr());
} }
#if STUDIO_CLIENT #if STUDIO_CLIENT
@ -515,6 +526,14 @@ namespace Beefy
structuredData.Load(resFileName); structuredData.Load(resFileName);
mResourceManager.ParseConfigData(structuredData); mResourceManager.ParseConfigData(structuredData);
} }
for (int32 i = 0; true; i++)
{
int threadId = BFApp_GetCriticalThreadId(i);
if (threadId == 0)
break;
GC.ExcludeThreadId(threadId);
}
} }
public void InitGraphics() public void InitGraphics()
@ -671,6 +690,14 @@ namespace Beefy
//Utils.BFRT_CPP("gBFGC.MutatorSectionExit()"); //Utils.BFRT_CPP("gBFGC.MutatorSectionExit()");
} }
public virtual void UpdateF(float updatePct)
{
for (int32 windowIdx = 0; windowIdx < mWindows.Count; windowIdx++)
{
mWindows[windowIdx].UpdateF(updatePct);
}
}
public virtual void DoDraw() public virtual void DoDraw()
{ {
} }
@ -695,12 +722,11 @@ namespace Beefy
} }
#endif #endif
public virtual void Draw() public virtual void Draw(bool forceDraw)
{ {
#if STUDIO_CLIENT #if STUDIO_CLIENT
#endif #endif
PerfTimer.ZoneStart("BFApp.Draw"); PerfTimer.ZoneStart("BFApp.Draw");
PerfTimer.Message("Client Draw Start"); PerfTimer.Message("Client Draw Start");
@ -716,7 +742,8 @@ namespace Beefy
for (BFWindow window in mWindows) for (BFWindow window in mWindows)
{ {
if ((window.mVisible) && ((window.mIsDirty) || (mAutoDirty))) if ((window.mVisible) &&
((window.mIsDirty) || (mAutoDirty) || (forceDraw)))
{ {
window.PreDraw(mGraphics); window.PreDraw(mGraphics);
if (mColorMatrix != null) if (mColorMatrix != null)

View file

@ -664,6 +664,11 @@ namespace Beefy
public virtual void Update() public virtual void Update()
{ {
} }
public virtual void UpdateF(float updatePct)
{
}
} }
#else #else
public class BFWindow : BFWindowBase, IStudioClientWindow public class BFWindow : BFWindowBase, IStudioClientWindow

View file

@ -19,6 +19,11 @@ namespace Beefy.theme.dark
public bool mAllowOpen = true; public bool mAllowOpen = true;
public bool mIsReversed; public bool mIsReversed;
public this()
{
mAlwaysUpdateF = true;
}
public override void Draw(Graphics g) public override void Draw(Graphics g)
{ {
base.Draw(g); base.Draw(g);
@ -52,9 +57,9 @@ namespace Beefy.theme.dark
mRot = mIsOpen ? (Math.PI_f / 2) : 0; mRot = mIsOpen ? (Math.PI_f / 2) : 0;
} }
public override void Update() public override void UpdateF(float updatePct)
{ {
base.Update(); base.UpdateF(updatePct);
int childCount = mItem.mChildItems.Count; int childCount = mItem.mChildItems.Count;
@ -62,15 +67,17 @@ namespace Beefy.theme.dark
if ((mIsOpen) && (mRot < Math.PI_f / 2)) if ((mIsOpen) && (mRot < Math.PI_f / 2))
{ {
mRot = Math.Min(Math.PI_f / 2, mRot + rotSpeed); mRot = Math.Min(Math.PI_f / 2, mRot + rotSpeed * updatePct);
mItem.mListView.mListSizeDirty = true; mItem.mListView.mListSizeDirty = true;
MarkDirty(); MarkDirty();
mWidgetWindow.mTempWantsUpdateF = true;
} }
else if ((!mIsOpen) && (mRot > 0)) else if ((!mIsOpen) && (mRot > 0))
{ {
mRot = (float)Math.Max(0, mRot - rotSpeed); mRot = (float)Math.Max(0, mRot - rotSpeed * updatePct);
mItem.mListView.mListSizeDirty = true; mItem.mListView.mListSizeDirty = true;
MarkDirty(); MarkDirty();
mWidgetWindow.mTempWantsUpdateF = true;
} }
float x; float x;
@ -876,6 +883,25 @@ namespace Beefy.theme.dark
} }
} }
} }
public override void UpdateFAll(float updatePct)
{
if (mVisible)
{
base.UpdateFAll(updatePct);
if (mChildItems != null)
{
for (int32 anIdx = 0; anIdx < mChildItems.Count; anIdx++)
{
Widget child = mChildItems[anIdx];
Debug.Assert(child.mParent == this);
Debug.Assert(child.mWidgetWindow == mWidgetWindow);
child.UpdateFAll(updatePct);
}
}
}
}
} }
public class DarkListView : ListView public class DarkListView : ListView

View file

@ -37,9 +37,9 @@ namespace Beefy.utils
get { return mPct != 1.0f; } get { return mPct != 1.0f; }
} }
public void Update() public void Update(float updatePct = 1.0f)
{ {
mPct = Math.Min(1.0f, mPct + mSpeed * mSpeedScale); mPct = Math.Min(1.0f, mPct + mSpeed * mSpeedScale * updatePct);
} }
public void Set(double val, bool immediate = false) public void Set(double val, bool immediate = false)

View file

@ -788,10 +788,15 @@ namespace Beefy.widgets
public override void UpdateAll() public override void UpdateAll()
{ {
base.UpdateAll(); base.UpdateAll();
UpdateListSize(); UpdateListSize();
} }
public override void UpdateFAll(float updatePct)
{
base.UpdateFAll(updatePct);
UpdateListSize();
}
public virtual float GetListWidth() public virtual float GetListWidth()
{ {
float columnWidths = 0; float columnWidths = 0;
@ -802,7 +807,7 @@ namespace Beefy.widgets
public void UpdateListSize() public void UpdateListSize()
{ {
// Do this in UpdateAll to give children a change to resize items // Do this in UpdateAll to give children a chance to resize items
if (mListSizeDirty) if (mListSizeDirty)
{ {
float listWidth = GetListWidth(); float listWidth = GetListWidth();

View file

@ -50,6 +50,7 @@ namespace Beefy.widgets
mScrollContentContainer.mClipGfx = true; mScrollContentContainer.mClipGfx = true;
mScrollContentContainer.mClipMouse = true; mScrollContentContainer.mClipMouse = true;
AddWidget(mScrollContentContainer); AddWidget(mScrollContentContainer);
mAlwaysUpdateF = true;
} }
public ~this() public ~this()
@ -248,15 +249,23 @@ namespace Beefy.widgets
{ {
base.Update(); base.Update();
if ((mHorzPos.IsMoving) || (mVertPos.IsMoving))
{
mHorzPos.Update();
mVertPos.Update();
UpdateContentPosition();
MarkDirty();
}
} }
public override void UpdateF(float updatePct)
{
base.UpdateF(updatePct);
if ((mHorzPos.IsMoving) || (mVertPos.IsMoving))
{
mWidgetWindow.mTempWantsUpdateF = true;
mHorzPos.Update(updatePct);
mVertPos.Update(updatePct);
UpdateContentPosition();
MarkDirty();
}
}
public override void MouseWheel(float x, float y, float deltaX, float deltaY) public override void MouseWheel(float x, float y, float deltaX, float deltaY)
{ {
base.MouseWheel(x, y, deltaX, deltaY); base.MouseWheel(x, y, deltaX, deltaY);

View file

@ -39,6 +39,7 @@ namespace Beefy.widgets
public float mWidth; public float mWidth;
public float mHeight; public float mHeight;
public int32 mUpdateCnt; public int32 mUpdateCnt;
public double mUpdateCntF;
public String mIdStr ~ delete _; public String mIdStr ~ delete _;
public List<Widget> mChildWidgets; public List<Widget> mChildWidgets;
public MouseFlag mMouseFlags; public MouseFlag mMouseFlags;
@ -56,6 +57,7 @@ namespace Beefy.widgets
public bool mDeferredDelete; public bool mDeferredDelete;
public Insets mMouseInsets ~ delete _; public Insets mMouseInsets ~ delete _;
public bool mAutoFocus; public bool mAutoFocus;
public bool mAlwaysUpdateF;
public float X { get { return mX; } set { mX = value; } } public float X { get { return mX; } set { mX = value; } }
public float Y { get { return mY; } set { mY = value; } } public float Y { get { return mY; } set { mY = value; } }
@ -455,8 +457,16 @@ namespace Beefy.widgets
public virtual void Update() public virtual void Update()
{ {
mUpdateCnt++; mUpdateCnt++;
if ((mAlwaysUpdateF) && (mWidgetWindow != null))
UpdateF((float)(mUpdateCnt - mUpdateCntF));
mUpdateCntF = mUpdateCnt;
} }
public virtual void UpdateF(float updatePct)
{
mUpdateCntF += updatePct;
}
public void DeferDelete() public void DeferDelete()
{ {
mDeferredDelete = true; mDeferredDelete = true;
@ -487,6 +497,31 @@ namespace Beefy.widgets
} }
} }
public virtual void UpdateFAll(float updatePct)
{
UpdateF(updatePct);
if (mDeferredDelete)
{
delete this;
return;
}
// Removed self?
if (mWidgetWindow == null)
return;
if (mChildWidgets != null)
{
for (int32 anIdx = 0; anIdx < mChildWidgets.Count; anIdx++)
{
Widget child = mChildWidgets[anIdx];
Debug.Assert(child.mParent == this);
Debug.Assert(child.mWidgetWindow == mWidgetWindow);
child.UpdateFAll(updatePct);
}
}
}
public virtual void Resize(float x, float y, float width, float height) public virtual void Resize(float x, float y, float width, float height)
{ {
Debug.Assert(width >= 0); Debug.Assert(width >= 0);

View file

@ -62,6 +62,8 @@ namespace Beefy.widgets
public bool mHasMouseInside; public bool mHasMouseInside;
public bool mHasProxyMouseInside; public bool mHasProxyMouseInside;
public bool mIsKeyDownHandled; public bool mIsKeyDownHandled;
public bool mWantsUpdateF;
public bool mTempWantsUpdateF;
public int32 mContentClientWidth; public int32 mContentClientWidth;
public int32 mContentClientHeight; public int32 mContentClientHeight;
@ -153,9 +155,19 @@ namespace Beefy.widgets
return; return;
base.Update(); base.Update();
RehupMouse(false); RehupMouse(false);
mTempWantsUpdateF = false;
mRootWidget.UpdateAll(); mRootWidget.UpdateAll();
} }
public override void UpdateF(float updatePct)
{
if (mRootWidget == null)
return;
base.Update();
if (mWantsUpdateF || mTempWantsUpdateF)
mRootWidget.UpdateFAll(updatePct);
}
public override int32 CloseQuery() public override int32 CloseQuery()
{ {
bool hadFalse = false; bool hadFalse = false;

View file

@ -133,6 +133,8 @@ namespace System
public extern static void SetMaxPausePercentage(int maxPausePercentage); // 0 = disabled. Defaults to 20. public extern static void SetMaxPausePercentage(int maxPausePercentage); // 0 = disabled. Defaults to 20.
[CallingConvention(.Cdecl)] [CallingConvention(.Cdecl)]
extern static void AddPendingThread(void* internalThread); extern static void AddPendingThread(void* internalThread);
[CallingConvention(.Cdecl)]
public extern static void ExcludeThreadId(int thereadId);
#else #else
public static void Collect(bool async = true) {} public static void Collect(bool async = true) {}
private static void MarkAllStaticMembers() {} private static void MarkAllStaticMembers() {}
@ -144,6 +146,7 @@ namespace System
public static void SetCollectFreeThreshold(int freeBytes) {} public static void SetCollectFreeThreshold(int freeBytes) {}
public static void SetMaxPausePercentage(int maxPausePercentage) {} public static void SetMaxPausePercentage(int maxPausePercentage) {}
static void AddPendingThread(void* internalThreadInfo) {} static void AddPendingThread(void* internalThreadInfo) {}
public static void ExcludeThreadId(int thereadId) {}
#endif #endif
static void MarkDerefedObject(Object* obj) static void MarkDerefedObject(Object* obj)

View file

@ -1429,6 +1429,9 @@ bool BFGC::ScanThreads()
thread = mThreadList[threadIdx++]; thread = mThreadList[threadIdx++];
} }
if (thread->mExcluded)
continue;
if (!thread->mRunning) if (!thread->mRunning)
{ {
AutoCrit autoCrit(mCritSect); AutoCrit autoCrit(mCritSect);
@ -2367,11 +2370,12 @@ void BFGC::SuspendThreads()
auto curThreadId = GetCurrentThreadId(); auto curThreadId = GetCurrentThreadId();
for (auto thread : mThreadList) for (auto thread : mThreadList)
{ {
if ((thread->mThreadId != curThreadId) && (thread->mRunning) && (thread->WantsSuspend())) if ((thread->mThreadId != curThreadId) && (!thread->mExcluded) && (thread->mRunning) && (thread->WantsSuspend()))
{ {
// We must lock this before suspending so we can access mStackMarkableObjects // We must lock this before suspending so we can access mStackMarkableObjects
// Otherwise we could deadlock // Otherwise we could deadlock
thread->mCritSect.Lock(); thread->mCritSect.Lock();
thread->mSuspended = true;
BfpThreadResult result; BfpThreadResult result;
BfpThread_Suspend(thread->mThreadHandle, &result); BfpThread_Suspend(thread->mThreadHandle, &result);
@ -2386,11 +2390,12 @@ void BFGC::ResumeThreads()
auto curThreadId = GetCurrentThreadId(); auto curThreadId = GetCurrentThreadId();
for (auto thread : mThreadList) for (auto thread : mThreadList)
{ {
if ((thread->mThreadId != curThreadId) && (thread->mRunning) && (thread->WantsSuspend())) if ((thread->mThreadId != curThreadId) && (thread->mSuspended) && (thread->mRunning) && (thread->WantsSuspend()))
{ {
// Previously locked in SuspendThreads // Previously locked in SuspendThreads
thread->mCritSect.Unlock(); thread->mCritSect.Unlock();
thread->mSuspended = false;
BfpThread_Resume(thread->mThreadHandle, NULL); BfpThread_Resume(thread->mThreadHandle, NULL);
} }
} }
@ -2743,6 +2748,16 @@ void BFGC::SetMaxRawDeferredObjectFreePercentage(intptr maxPercentage)
mMaxRawDeferredObjectFreePercentage = maxPercentage; mMaxRawDeferredObjectFreePercentage = maxPercentage;
} }
void BFGC::ExcludeThreadId(intptr threadId)
{
Beefy::AutoCrit autoCrit(mCritSect);
for (auto thread : mThreadList)
{
if (thread->mThreadId == threadId)
thread->mExcluded = true;
}
}
using namespace bf::System; using namespace bf::System;
void GC::Run() void GC::Run()
@ -2832,6 +2847,11 @@ BFRT_EXPORT void bf::System::GC::SetMaxRawDeferredObjectFreePercentage(intptr ma
gBFGC.SetMaxRawDeferredObjectFreePercentage(maxPercentage); gBFGC.SetMaxRawDeferredObjectFreePercentage(maxPercentage);
} }
BFRT_EXPORT void bf::System::GC::ExcludeThreadId(intptr threadId)
{
gBFGC.ExcludeThreadId(threadId);
}
#else // BF_GC_SUPPORTED #else // BF_GC_SUPPORTED
void* BfObjectAllocate(intptr size, bf::System::Type* type) void* BfObjectAllocate(intptr size, bf::System::Type* type)

View file

@ -181,6 +181,8 @@ public:
intptr mStackStart; intptr mStackStart;
intptr mLastStackPtr; intptr mLastStackPtr;
bool mRunning; bool mRunning;
bool mExcluded;
bool mSuspended;
Beefy::Array<bf::System::Object*> mStackMarkableObjects; Beefy::Array<bf::System::Object*> mStackMarkableObjects;
ThreadInfo() ThreadInfo()
@ -192,6 +194,8 @@ public:
mTEB = NULL; mTEB = NULL;
mStackStart = NULL; mStackStart = NULL;
mRunning = true; mRunning = true;
mExcluded = false;
mSuspended = false;
} }
~ThreadInfo(); ~ThreadInfo();
@ -424,6 +428,7 @@ public:
void SetCollectFreeThreshold(int freeBytes); void SetCollectFreeThreshold(int freeBytes);
void SetMaxPausePercentage(int maxPausePercentage); void SetMaxPausePercentage(int maxPausePercentage);
void SetMaxRawDeferredObjectFreePercentage(intptr maxPercentage); void SetMaxRawDeferredObjectFreePercentage(intptr maxPercentage);
void ExcludeThreadId(intptr threadId);
}; };
extern BFGC gBFGC; extern BFGC gBFGC;
@ -488,6 +493,7 @@ namespace bf
BFRT_EXPORT static void SetCollectFreeThreshold(intptr freeBytes); BFRT_EXPORT static void SetCollectFreeThreshold(intptr freeBytes);
BFRT_EXPORT static void SetMaxPausePercentage(intptr maxPausePercentage); BFRT_EXPORT static void SetMaxPausePercentage(intptr maxPausePercentage);
BFRT_EXPORT static void SetMaxRawDeferredObjectFreePercentage(intptr maxPercentage); BFRT_EXPORT static void SetMaxRawDeferredObjectFreePercentage(intptr maxPercentage);
BFRT_EXPORT static void ExcludeThreadId(intptr threadId);
}; };
} }
} }

View file

@ -19,10 +19,11 @@ BFApp::BFApp()
mTitle = "Beefy Application"; mTitle = "Beefy Application";
mRefreshRate = 60; mRefreshRate = 60;
mLastProcessTick = BFTickCount(); mLastProcessTick = BFTickCount();
mFrameTimeAcc = 0; mPhysFrameTimeAcc = 0;
mDrawEnabled = true; mDrawEnabled = true;
mUpdateFunc = NULL; mUpdateFunc = NULL;
mUpdateFFunc = NULL;
mDrawFunc = NULL; mDrawFunc = NULL;
gBFApp = this; gBFApp = this;
@ -43,6 +44,12 @@ BFApp::BFApp()
mRunning = false; mRunning = false;
mRenderDevice = NULL; mRenderDevice = NULL;
mVSynched = false; mVSynched = false;
mVSyncActive = false;
mForceNextDraw = false;
mUpdateCnt = 0;
mUpdateCntF = 0;
mClientUpdateCntF = 0;
} }
BFApp::~BFApp() BFApp::~BFApp()
@ -90,10 +97,16 @@ void BFApp::Update(bool batchStart)
mPendingWindowDeleteList.clear(); mPendingWindowDeleteList.clear();
} }
void BFApp::UpdateF(float updatePct)
{
mUpdateFFunc(updatePct);
}
void BFApp::Draw() void BFApp::Draw()
{ {
gPerfManager->ZoneStart("BFApp::Draw"); gPerfManager->ZoneStart("BFApp::Draw");
mDrawFunc(); mDrawFunc(mForceNextDraw);
mForceNextDraw = false;
gPerfManager->ZoneEnd(); gPerfManager->ZoneEnd();
} }
@ -103,90 +116,88 @@ void BFApp::Process()
{ {
//Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Process"); //Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Process");
RenderWindow* headRenderWindow = NULL;
float physRefreshRate = 0;
if (!mRenderDevice->mRenderWindowList.IsEmpty())
{
headRenderWindow = mRenderDevice->mRenderWindowList[0];
physRefreshRate = headRenderWindow->GetRefreshRate();
}
if (physRefreshRate <= 0)
physRefreshRate = 60.0f;
float ticksPerFrame = 1;
float physTicksPerFrame = 1000.0f / physRefreshRate;
if (mInProcess) if (mInProcess)
return; // No reentry return; // No reentry
mInProcess = true; mInProcess = true;
int updates;
uint32 tickNow = BFTickCount(); uint32 tickNow = BFTickCount();
const int vSyncTestingPeriod = 250; const int vSyncTestingPeriod = 250;
if (mRefreshRate != 0) bool didVBlankWait = false;
if (mVSyncActive)
{ {
float ticksPerFrame = 1000.0f / mRefreshRate; // Have a time limit in the cases we miss the vblank
int ticksSinceLastProcess = tickNow - mLastProcessTick; if (mVSyncEvent.WaitFor((int)(physTicksPerFrame + 1)))
didVBlankWait = true;
mUpdateSampleCount++;
mUpdateSampleTimes += ticksSinceLastProcess;
//TODO: Turn off mVSynched based on error calculations - (?)
// Two VSync failures in a row means we set mVSyncFailed and permanently disable it
if (mUpdateSampleTimes >= vSyncTestingPeriod)
{
int expectedFrames = (int)(mUpdateSampleTimes / ticksPerFrame);
if (mUpdateSampleCount > expectedFrames * 1.5)
{
if (!mVSynched)
mVSyncFailed = true;
mVSynched = false;
}
else
if (!mVSyncFailed)
mVSynched = true;
mUpdateSampleCount = 0;
mUpdateSampleTimes = 0;
}
mFrameTimeAcc += tickNow - mLastProcessTick;
bool vSynched = mVSynched;
if (vSynched)
{
// For the startup, try not to go hyper during those first samplings
if (mUpdateSampleTimes <= vSyncTestingPeriod)
{
if (ticksSinceLastProcess < ticksPerFrame / 1.5)
vSynched = false;
}
}
if (vSynched)
{
updates = std::max(1, (int)(mFrameTimeAcc / ticksPerFrame + 0.5f));
mFrameTimeAcc = std::max(0.0f, mFrameTimeAcc - ticksPerFrame * updates);
}
else
{
updates = std::max(0, (int)(mFrameTimeAcc / ticksPerFrame));
mFrameTimeAcc = mFrameTimeAcc - ticksPerFrame * updates;
}
if (updates > mRefreshRate)
{
// If more than 1 second of updates is queued, just re-sync
updates = 1;
mFrameTimeAcc = 0;
}
// Compensate for "slow start" by limiting the number of catchup-updates we can do when starting the app
int maxUpdates = BF_MIN(mNumPhysUpdates + 1, mMaxUpdatesPerDraw);
updates = BF_MIN(updates, maxUpdates);
/*if (updates > 2)
OutputDebugStrF("Updates: %d TickDelta: %d\n", updates, tickNow - mLastProcessTick);*/
} }
else
updates = 1; // RefreshRate of 0 means to update as fast as possible
if (updates == 0) if (mRefreshRate > 0)
{ ticksPerFrame = 1000.0f / mRefreshRate;
// Yield int ticksSinceLastProcess = tickNow - mLastProcessTick;
BfpThread_Sleep(1);
} mUpdateSampleCount++;
mUpdateSampleTimes += ticksSinceLastProcess;
//TODO: Turn off mVSynched based on error calculations - (?)
// Two VSync failures in a row means we set mVSyncFailed and permanently disable it
if (mUpdateSampleTimes >= vSyncTestingPeriod)
{
int expectedFrames = (int)(mUpdateSampleTimes / ticksPerFrame);
if (mUpdateSampleCount > expectedFrames * 1.5)
{
if (!mVSynched)
mVSyncFailed = true;
mVSynched = false;
}
else
{
if (!mVSyncFailed)
mVSynched = true;
}
mUpdateSampleCount = 0;
mUpdateSampleTimes = 0;
}
mPhysFrameTimeAcc += tickNow - mLastProcessTick;
if (didVBlankWait)
{
// Try to keep time synced with vblank
if (mPhysFrameTimeAcc < physTicksPerFrame * 2)
{
float timeAdjust = physTicksPerFrame - mPhysFrameTimeAcc + 0.001f;
mPhysFrameTimeAcc += timeAdjust;
}
}
/*if (updates > 2)
OutputDebugStrF("Updates: %d TickDelta: %d\n", updates, tickNow - mLastProcessTick);*/
// Compensate for "slow start" by limiting the number of catchup-updates we can do when starting the app
int maxUpdates = BF_MIN(mNumPhysUpdates + 1, mMaxUpdatesPerDraw);
while (mPhysFrameTimeAcc >= physTicksPerFrame)
{
mPhysFrameTimeAcc -= physTicksPerFrame;
mUpdateCntF += physTicksPerFrame / ticksPerFrame;
}
static uint32 lastUpdate = BFTickCount(); static uint32 lastUpdate = BFTickCount();
@ -202,17 +213,46 @@ void BFApp::Process()
} }
#endif #endif
if (updates > 0)
mNumPhysUpdates++;
for (int updateNum = 0; updateNum < updates; updateNum++) int didUpdateCnt = 0;
if (mClientUpdateCntF - mUpdateCntF > physRefreshRate / 2)
{ {
if (!mRunning) // Too large of a difference, just sync
break; mClientUpdateCntF = mUpdateCntF - 1;
Update(updateNum == 0);
} }
if ((mRunning) && (updates > 0)) while ((int)mClientUpdateCntF < (int)mUpdateCntF)
{
Update(didUpdateCnt == 0);
didUpdateCnt++;
mClientUpdateCntF = (int)mClientUpdateCntF + 1.000001;
if (didUpdateCnt >= maxUpdates)
break;
}
// Only attempt UpdateF updates if our rates aren't nearl) the same
if ((mRefreshRate != 0) && (fabs(physRefreshRate - mRefreshRate) / (float)mRefreshRate > 0.1f))
{
float updateFAmt = (float)(mUpdateCntF - mClientUpdateCntF);
if ((updateFAmt > 0.05f) && (updateFAmt < 1.0f) && (didUpdateCnt < maxUpdates))
{
UpdateF(updateFAmt);
didUpdateCnt++;
mClientUpdateCntF = mUpdateCntF;
}
}
if (didUpdateCnt > 0)
mNumPhysUpdates++;
if ((mRunning) && (didUpdateCnt == 0))
{
BfpThread_Sleep(1);
}
if ((mRunning) &&
((didUpdateCnt != 0) || (mForceNextDraw)))
Draw(); Draw();
#ifdef PERIODIC_PERF_TIMING #ifdef PERIODIC_PERF_TIMING
@ -229,6 +269,8 @@ void BFApp::Process()
void BFApp::RemoveWindow(BFWindow* window) void BFApp::RemoveWindow(BFWindow* window)
{ {
AutoCrit autoCrit(mCritSect);
auto itr = std::find(mWindowList.begin(), mWindowList.end(), window); auto itr = std::find(mWindowList.begin(), mWindowList.end(), window);
if (itr == mWindowList.end()) // Allow benign failure (double removal) if (itr == mWindowList.end()) // Allow benign failure (double removal)
return; return;

View file

@ -1,12 +1,14 @@
#pragma once #pragma once
#include "Common.h" #include "Common.h"
#include "util/CritSect.h"
#include <list> #include <list>
NS_BF_BEGIN; NS_BF_BEGIN;
typedef void (*BFApp_UpdateFunc)(bool batchStart); typedef void (*BFApp_UpdateFunc)(bool batchStart);
typedef void (*BFApp_DrawFunc)(); typedef void (*BFApp_UpdateFFunc)(float updatePct);
typedef void (*BFApp_DrawFunc)(bool forceDraw);
class BFApp; class BFApp;
class BFSoundManager; class BFSoundManager;
@ -50,12 +52,15 @@ public:
class BFApp class BFApp
{ {
public: public:
CritSect mCritSect;
String mTitle; String mTitle;
String mInstallDir; String mInstallDir;
String mDataDir; String mDataDir;
bool mDrawEnabled; bool mDrawEnabled;
float mRefreshRate; float mRefreshRate;
int mMaxUpdatesPerDraw; int mMaxUpdatesPerDraw;
double mUpdateCntF;
double mClientUpdateCntF;
bool mInProcess; bool mInProcess;
bool mRunning; bool mRunning;
@ -63,16 +68,20 @@ public:
int mSysDialogCnt; int mSysDialogCnt;
int mUpdateCnt; int mUpdateCnt;
int mNumPhysUpdates; int mNumPhysUpdates;
SyncEvent mVSyncEvent;
volatile bool mVSyncActive;
bool mVSynched; bool mVSynched;
bool mVSyncFailed; bool mVSyncFailed;
bool mForceNextDraw;
int mUpdateSampleCount; int mUpdateSampleCount;
int mUpdateSampleTimes; int mUpdateSampleTimes;
uint32 mLastProcessTick; uint32 mLastProcessTick;
float mFrameTimeAcc; float mPhysFrameTimeAcc;
BFApp_UpdateFunc mUpdateFunc; BFApp_UpdateFunc mUpdateFunc;
BFApp_UpdateFFunc mUpdateFFunc;
BFApp_DrawFunc mDrawFunc; BFApp_DrawFunc mDrawFunc;
int mCursor; int mCursor;
@ -81,6 +90,7 @@ public:
public: public:
virtual void Update(bool batchStart); virtual void Update(bool batchStart);
virtual void UpdateF(float updatePct);
virtual void Draw(); virtual void Draw();
virtual void Process(); virtual void Process();
virtual void PhysSetCursor() = 0; virtual void PhysSetCursor() = 0;
@ -114,6 +124,8 @@ public:
virtual FileStream* OpenBinaryFile(const StringImpl& fileName); virtual FileStream* OpenBinaryFile(const StringImpl& fileName);
virtual BFSoundManager* GetSoundManager() { return NULL; } virtual BFSoundManager* GetSoundManager() { return NULL; }
virtual intptr GetCriticalThreadId(int idx) { return 0; }
}; };
extern BFApp* gBFApp; extern BFApp* gBFApp;

View file

@ -210,9 +210,10 @@ BF_EXPORT const char* BF_CALLTYPE BFApp_GetDataDir()
return gBFApp->mDataDir.c_str(); return gBFApp->mDataDir.c_str();
} }
BF_EXPORT void BF_CALLTYPE BFApp_SetCallbacks(BFApp_UpdateFunc updateFunc, BFApp_DrawFunc drawFunc) BF_EXPORT void BF_CALLTYPE BFApp_SetCallbacks(BFApp_UpdateFunc updateFunc, BFApp_UpdateFFunc updateFFunc, BFApp_DrawFunc drawFunc)
{ {
gBFApp->mUpdateFunc = updateFunc; gBFApp->mUpdateFunc = updateFunc;
gBFApp->mUpdateFFunc = updateFFunc;
gBFApp->mDrawFunc = drawFunc; gBFApp->mDrawFunc = drawFunc;
//public delegate void UpdateProc(); //public delegate void UpdateProc();
} }
@ -276,6 +277,11 @@ BF_EXPORT BFSoundManager* BF_CALLTYPE BFApp_GetSoundManager()
return gBFApp->GetSoundManager(); return gBFApp->GetSoundManager();
} }
BF_EXPORT intptr BF_CALLTYPE BFApp_GetCriticalThreadId(int idx)
{
return gBFApp->GetCriticalThreadId(idx);
}
/// ///
BF_EXPORT void BF_CALLTYPE BFWindow_SetCallbacks(BFWindow* window, BFWindow_MovedFunc movedFunc, BFWindow_CloseQueryFunc closeQueryFunc, BFWindow_ClosedFunc closedFunc, BF_EXPORT void BF_CALLTYPE BFWindow_SetCallbacks(BFWindow* window, BFWindow_MovedFunc movedFunc, BFWindow_CloseQueryFunc closeQueryFunc, BFWindow_ClosedFunc closedFunc,

View file

@ -62,6 +62,7 @@ RenderDevice::RenderDevice() :
mCurRenderTarget = NULL; mCurRenderTarget = NULL;
mCurDrawLayer = NULL; mCurDrawLayer = NULL;
mPhysRenderWindow = NULL; mPhysRenderWindow = NULL;
mApp = NULL;
} }
RenderDevice::~RenderDevice() RenderDevice::~RenderDevice()

View file

@ -76,6 +76,8 @@ public:
virtual void SetAsTarget() = 0; virtual void SetAsTarget() = 0;
virtual void Resized() = 0; virtual void Resized() = 0;
virtual void Present() = 0; virtual void Present() = 0;
virtual float GetRefreshRate() { return 60.0f; }
virtual bool WaitForVBlank() { return false; }
}; };
const int DRAWBUFFER_IDXBUFFER_SIZE = 8*1024; const int DRAWBUFFER_IDXBUFFER_SIZE = 8*1024;
@ -175,6 +177,14 @@ public:
mElementData = NULL; mElementData = NULL;
mNumElements = 0; mNumElements = 0;
} }
VertexDefinition(VertexDefinition* src)
{
mElementData = new VertexDefData[src->mNumElements];
mNumElements = src->mNumElements;
memcpy(mElementData, src->mElementData, sizeof(VertexDefData) * mNumElements);
}
virtual ~VertexDefinition() virtual ~VertexDefinition()
{ {
delete [] mElementData; delete [] mElementData;
@ -262,6 +272,7 @@ class RenderDevice
public: public:
Array<DrawBatch*> mDrawBatchPool; Array<DrawBatch*> mDrawBatchPool;
BFApp* mApp;
RenderWindow* mPhysRenderWindow; RenderWindow* mPhysRenderWindow;
RenderState* mPhysRenderState; RenderState* mPhysRenderState;
int mResizeCount; int mResizeCount;

View file

@ -18,6 +18,7 @@ using namespace DirectX;
//#include <D3DX11async.h> //#include <D3DX11async.h>
//#include <D3DX10math.h> //#include <D3DX10math.h>
//#include <DxErr.h> //#include <DxErr.h>
#include <dxgi1_3.h>
#pragma warning(pop) #pragma warning(pop)
#include "util/AllocDebug.h" #include "util/AllocDebug.h"
@ -192,6 +193,7 @@ void DXShaderParam::SetFloat4(float x, float y, float z, float w)
DXShader::DXShader() DXShader::DXShader()
{ {
//? mD3DEffect = NULL; //? mD3DEffect = NULL;
mVertexDef = NULL;
mD3DPixelShader = NULL; mD3DPixelShader = NULL;
mD3DVertexShader = NULL; mD3DVertexShader = NULL;
mD3DLayout = NULL; mD3DLayout = NULL;
@ -201,25 +203,235 @@ DXShader::DXShader()
DXShader::~DXShader() DXShader::~DXShader()
{ {
DXShaderParamMap::iterator itr = mParamsMap.begin(); delete mVertexDef;
while (itr != mParamsMap.end()) ReleaseNative();
{
delete itr->second;
++itr;
}
if (mD3DLayout != NULL)
mD3DLayout->Release();
if (mD3DVertexShader != NULL)
mD3DVertexShader->Release();
if (mD3DPixelShader != NULL)
mD3DPixelShader->Release();
if (mConstBuffer != NULL)
mConstBuffer->Release();
//? if (mD3DEffect != NULL) //? if (mD3DEffect != NULL)
//? mD3DEffect->Release(); //? mD3DEffect->Release();
} }
void DXShader::ReleaseNative()
{
if (mD3DLayout != NULL)
mD3DLayout->Release();
mD3DLayout = NULL;
if (mD3DVertexShader != NULL)
mD3DVertexShader->Release();
mD3DVertexShader = NULL;
if (mD3DPixelShader != NULL)
mD3DPixelShader->Release();
mD3DPixelShader = NULL;
if (mConstBuffer != NULL)
mConstBuffer->Release();
mConstBuffer = NULL;
}
extern "C"
typedef HRESULT(WINAPI* Func_D3DX10CompileFromFileW)(LPCWSTR pSrcFile, CONST D3D10_SHADER_MACRO* pDefines, LPD3D10INCLUDE pInclude,
LPCSTR pFunctionName, LPCSTR pProfile, UINT Flags1, UINT Flags2, ID3D10Blob** ppShader, ID3D10Blob** ppErrorMsgs);
static Func_D3DX10CompileFromFileW gFunc_D3DX10CompileFromFileW;
static bool LoadDXShader(const StringImpl& filePath, const StringImpl& entry, const StringImpl& profile, ID3D10Blob** outBuffer)
{
HRESULT hr;
String outObj = filePath + "_" + entry + "_" + profile;
bool useCache = false;
auto srcDate = ::BfpFile_GetTime_LastWrite(filePath.c_str());
auto cacheDate = ::BfpFile_GetTime_LastWrite(outObj.c_str());
if (cacheDate >= srcDate)
useCache = true;
if (!useCache)
{
if (gFunc_D3DX10CompileFromFileW == NULL)
{
auto lib = LoadLibraryA("D3DCompiler_47.dll");
if (lib != NULL)
gFunc_D3DX10CompileFromFileW = (Func_D3DX10CompileFromFileW)::GetProcAddress(lib, "D3DCompileFromFile");
}
if (gFunc_D3DX10CompileFromFileW == NULL)
useCache = true;
}
if (!useCache)
{
if (gFunc_D3DX10CompileFromFileW == NULL)
{
auto lib = LoadLibraryA("D3DCompiler_47.dll");
if (lib != NULL)
gFunc_D3DX10CompileFromFileW = (Func_D3DX10CompileFromFileW)::GetProcAddress(lib, "D3DCompileFromFile");
}
ID3D10Blob* errorMessage = NULL;
auto dxResult = gFunc_D3DX10CompileFromFileW(UTF8Decode(filePath).c_str(), NULL, NULL, entry.c_str(), profile.c_str(),
D3D10_SHADER_DEBUG | D3D10_SHADER_ENABLE_STRICTNESS, 0, outBuffer, &errorMessage);
if (DXFAILED(dxResult))
{
if (errorMessage != NULL)
{
BF_FATAL(StrFormat("Vertex shader load failed: %s", (char*)errorMessage->GetBufferPointer()).c_str());
errorMessage->Release();
}
else
BF_FATAL("Shader load failed");
return false;
}
auto ptr = (*outBuffer)->GetBufferPointer();
int size = (int)(*outBuffer)->GetBufferSize();
FILE* fp = fopen(outObj.c_str(), "wb");
if (fp != NULL)
{
fwrite(ptr, 1, size, fp);
fclose(fp);
}
return true;
}
FILE* fp = fopen(outObj.c_str(), "rb");
if (fp == NULL)
{
BF_FATAL("Failed to load compiled shader");
return false;
}
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
fseek(fp, 0, SEEK_SET);
D3D10CreateBlob(size, outBuffer);
auto ptr = (*outBuffer)->GetBufferPointer();
fread(ptr, 1, size, fp);
fclose(fp);
return true;
}
bool DXShader::Load()
{
//HRESULT hr;
ID3D10Blob* errorMessage = NULL;
ID3D10Blob* vertexShaderBuffer = NULL;
ID3D10Blob* pixelShaderBuffer = NULL;
LoadDXShader(mSrcPath + ".fx", "VS", "vs_4_0", &vertexShaderBuffer);
LoadDXShader(mSrcPath + ".fx", "PS", "ps_4_0", &pixelShaderBuffer);
defer(
{
vertexShaderBuffer->Release();
pixelShaderBuffer->Release();
});
mHas2DPosition = false;
mVertexSize = 0;
mD3DLayout = NULL;
static const char* semanticNames[] = {
"POSITION",
"POSITION",
"COLOR",
"TEXCOORD",
"NORMAL",
"BINORMAL",
"TANGENT",
"BLENDINDICES",
"BLENDWEIGHT",
"DEPTH",
"FOG",
"POINTSIZE",
"SAMPLE",
"TESSELLATEFACTOR" };
static const DXGI_FORMAT dxgiFormat[] = {
DXGI_FORMAT_R32_FLOAT/*VertexElementFormat_Single*/,
DXGI_FORMAT_R32G32_FLOAT/*VertexElementFormat_Vector2*/,
DXGI_FORMAT_R32G32B32_FLOAT/*VertexElementFormat_Vector3*/,
DXGI_FORMAT_R32G32B32A32_FLOAT/*VertexElementFormat_Vector4*/,
DXGI_FORMAT_R8G8B8A8_UNORM/*VertexElementFormat_Color*/,
DXGI_FORMAT_R8G8B8A8_UINT/*VertexElementFormat_Byte4*/,
DXGI_FORMAT_R16G16_UINT/*VertexElementFormat_Short2*/,
DXGI_FORMAT_R16G16B16A16_UINT/*VertexElementFormat_Short4*/,
DXGI_FORMAT_R16G16_UNORM/*VertexElementFormat_NormalizedShort2*/,
DXGI_FORMAT_R16G16B16A16_UNORM/*VertexElementFormat_NormalizedShort4*/,
DXGI_FORMAT_R16G16_FLOAT/*VertexElementFormat_HalfVector2*/,
DXGI_FORMAT_R16G16B16A16_FLOAT/*VertexElementFormat_HalfVector4*/
};
static const int dxgiSize[] = {
sizeof(float) * 1/*VertexElementFormat_Single*/,
sizeof(float) * 2/*VertexElementFormat_Vector2*/,
sizeof(float) * 3/*VertexElementFormat_Vector3*/,
sizeof(float) * 4/*VertexElementFormat_Vector4*/,
sizeof(uint32)/*VertexElementFormat_Color*/,
sizeof(uint8) * 4/*VertexElementFormat_Byte4*/,
sizeof(uint16) * 2/*VertexElementFormat_Short2*/,
sizeof(uint16) * 4/*VertexElementFormat_Short4*/,
sizeof(uint16) * 2/*VertexElementFormat_NormalizedShort2*/,
sizeof(uint16) * 4/*VertexElementFormat_NormalizedShort4*/,
sizeof(uint16) * 2/*VertexElementFormat_HalfVector2*/,
sizeof(uint16) * 4/*VertexElementFormat_HalfVector4*/
};
D3D11_INPUT_ELEMENT_DESC layout[64];
for (int elementIdx = 0; elementIdx < mVertexDef->mNumElements; elementIdx++)
{
VertexDefData* vertexDefData = &mVertexDef->mElementData[elementIdx];
if (vertexDefData->mUsage == VertexElementUsage_Position2D)
mHas2DPosition = true;
D3D11_INPUT_ELEMENT_DESC* elementDesc = &layout[elementIdx];
elementDesc->SemanticName = semanticNames[vertexDefData->mUsage];
elementDesc->SemanticIndex = vertexDefData->mUsageIndex;
elementDesc->Format = dxgiFormat[vertexDefData->mFormat];
elementDesc->InputSlot = 0;
elementDesc->AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
elementDesc->InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
elementDesc->InstanceDataStepRate = 0;
mVertexSize += dxgiSize[vertexDefData->mFormat];
}
/* =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = sizeof(layout) / sizeof(layout[0]);*/
HRESULT result = mRenderDevice->mD3DDevice->CreateInputLayout(layout, mVertexDef->mNumElements, vertexShaderBuffer->GetBufferPointer(),
vertexShaderBuffer->GetBufferSize(), &mD3DLayout);
DXCHECK(result);
if (FAILED(result))
return false;
// Create the vertex shader from the buffer.
result = mRenderDevice->mD3DDevice->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), NULL, &mD3DVertexShader);
DXCHECK(result);
if (FAILED(result))
return false;
// Create the pixel shader from the buffer.
result = mRenderDevice->mD3DDevice->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), NULL, &mD3DPixelShader);
DXCHECK(result);
if (FAILED(result))
return false;
Init();
return true;
}
void DXShader::ReinitNative()
{
ReleaseNative();
Load();
}
ShaderParam* DXShader::GetShaderParam(const StringImpl& name) ShaderParam* DXShader::GetShaderParam(const StringImpl& name)
{ {
DXShaderParamMap::iterator itr = mParamsMap.find(name); DXShaderParamMap::iterator itr = mParamsMap.find(name);
@ -249,7 +461,7 @@ DXTexture::DXTexture()
mRenderDevice = NULL; mRenderDevice = NULL;
mD3DDepthBuffer = NULL; mD3DDepthBuffer = NULL;
mD3DDepthStencilView = NULL; mD3DDepthStencilView = NULL;
mImageData = NULL; mContentBits = NULL;
} }
DXTexture::~DXTexture() DXTexture::~DXTexture()
@ -258,7 +470,7 @@ DXTexture::~DXTexture()
((DXRenderDevice*)mRenderDevice)->mTextureMap.Remove(mPath); ((DXRenderDevice*)mRenderDevice)->mTextureMap.Remove(mPath);
//OutputDebugStrF("DXTexture::~DXTexture %@\n", this); //OutputDebugStrF("DXTexture::~DXTexture %@\n", this);
delete mImageData; delete mContentBits;
if (mD3DResourceView != NULL) if (mD3DResourceView != NULL)
mD3DResourceView->Release(); mD3DResourceView->Release();
if (mD3DDepthStencilView != NULL) if (mD3DDepthStencilView != NULL)
@ -267,6 +479,8 @@ DXTexture::~DXTexture()
mD3DDepthBuffer->Release(); mD3DDepthBuffer->Release();
if (mD3DTexture != NULL) if (mD3DTexture != NULL)
mD3DTexture->Release(); mD3DTexture->Release();
if (mRenderDevice != NULL)
mRenderDevice->mTextures.Remove(this);
} }
void DXTexture::ReleaseNative() void DXTexture::ReleaseNative()
@ -297,6 +511,44 @@ void DXTexture::ReleaseNative()
void DXTexture::ReinitNative() void DXTexture::ReinitNative()
{ {
ReleaseNative();
int aWidth = 0;
int aHeight = 0;
D3D11_SUBRESOURCE_DATA resData;
resData.pSysMem = mContentBits;
resData.SysMemPitch = mWidth * 4;
resData.SysMemSlicePitch = mWidth * mHeight * 4;
// Create the target texture
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = mWidth;
desc.Height = mHeight;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.CPUAccessFlags = 0;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
//OutputDebugStrF("Creating texture\n");
auto dxRenderDevice = (DXRenderDevice*)mRenderDevice;
DXCHECK(dxRenderDevice->mD3DDevice->CreateTexture2D(&desc, (mContentBits != NULL) ? &resData : NULL, &mD3DTexture));
D3D11_SHADER_RESOURCE_VIEW_DESC srDesc;
srDesc.Format = desc.Format;
srDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = 1;
DXCHECK(dxRenderDevice->mD3DDevice->CreateShaderResourceView(mD3DTexture, &srDesc, &mD3DResourceView));
OutputDebugStrF("DXTexture::ReinitNative %p\n", this);
} }
void DXTexture::PhysSetAsTarget() void DXTexture::PhysSetAsTarget()
@ -338,12 +590,24 @@ void DXTexture::Blt(ImageData* imageData, int x, int y)
box.front = 0; box.front = 0;
box.back = 1; box.back = 1;
mRenderDevice->mD3DDeviceContext->UpdateSubresource(mD3DTexture, 0, &box, imageData->mBits, imageData->mWidth * sizeof(uint32), 0); mRenderDevice->mD3DDeviceContext->UpdateSubresource(mD3DTexture, 0, &box, imageData->mBits, imageData->mWidth * sizeof(uint32), 0);
if (mContentBits != NULL)
{
for (int yOfs = 0; yOfs < imageData->mHeight; yOfs++)
memcpy(mContentBits + x + (y + yOfs) * mWidth, imageData->mBits + yOfs * imageData->mWidth, imageData->mWidth * 4);
}
} }
void DXTexture::SetBits(int destX, int destY, int destWidth, int destHeight, int srcPitch, uint32* bits) void DXTexture::SetBits(int destX, int destY, int destWidth, int destHeight, int srcPitch, uint32* bits)
{ {
D3D11_BOX box = { (UINT)destX, (UINT)destY, (UINT)0, (UINT)(destX + destWidth), (UINT)(destY + destHeight), 1 }; D3D11_BOX box = { (UINT)destX, (UINT)destY, (UINT)0, (UINT)(destX + destWidth), (UINT)(destY + destHeight), 1 };
mRenderDevice->mD3DDeviceContext->UpdateSubresource(mD3DTexture, 0, &box, bits, srcPitch * sizeof(uint32), 0); mRenderDevice->mD3DDeviceContext->UpdateSubresource(mD3DTexture, 0, &box, bits, srcPitch * sizeof(uint32), 0);
if (mContentBits != NULL)
{
for (int y = 0; y < destHeight; y++)
memcpy(mContentBits + destX + (destY + y) * mWidth, bits + (y * srcPitch), destWidth * 4);
}
} }
void DXTexture::GetBits(int srcX, int srcY, int srcWidth, int srcHeight, int destPitch, uint32* bits) void DXTexture::GetBits(int srcX, int srcY, int srcWidth, int srcHeight, int destPitch, uint32* bits)
@ -532,20 +796,18 @@ void DXRenderDevice::PhysSetRenderState(RenderState* renderState)
{ {
HRESULT result = NULL; HRESULT result = NULL;
D3D11_BUFFER_DESC matrixBufferDesc; if (mMatrix2DBuffer == NULL)
matrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
matrixBufferDesc.ByteWidth = sizeof(float[4]);
matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
matrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
matrixBufferDesc.MiscFlags = 0;
matrixBufferDesc.StructureByteStride = 0;
static ID3D11Buffer* matrixBuffer = NULL;
if (matrixBuffer == NULL)
{ {
D3D11_BUFFER_DESC matrixBufferDesc;
matrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
matrixBufferDesc.ByteWidth = sizeof(float[4]);
matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
matrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
matrixBufferDesc.MiscFlags = 0;
matrixBufferDesc.StructureByteStride = 0;
// Create the constant buffer pointer so we can access the vertex shader constant buffer from within this class. // Create the constant buffer pointer so we can access the vertex shader constant buffer from within this class.
result = mD3DDevice->CreateBuffer(&matrixBufferDesc, NULL, &matrixBuffer); result = mD3DDevice->CreateBuffer(&matrixBufferDesc, NULL, &mMatrix2DBuffer);
if (FAILED(result)) if (FAILED(result))
{ {
return; return;
@ -554,7 +816,7 @@ void DXRenderDevice::PhysSetRenderState(RenderState* renderState)
// Lock the constant buffer so it can be written to. // Lock the constant buffer so it can be written to.
D3D11_MAPPED_SUBRESOURCE mappedResource; D3D11_MAPPED_SUBRESOURCE mappedResource;
result = mD3DDeviceContext->Map(matrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); result = mD3DDeviceContext->Map(mMatrix2DBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result)) if (FAILED(result))
{ {
return; return;
@ -568,10 +830,10 @@ void DXRenderDevice::PhysSetRenderState(RenderState* renderState)
dataPtr[3] = 0; dataPtr[3] = 0;
// Unlock the constant buffer. // Unlock the constant buffer.
mD3DDeviceContext->Unmap(matrixBuffer, 0); mD3DDeviceContext->Unmap(mMatrix2DBuffer, 0);
//float params[4] = {mCurRenderTarget->mWidth, mCurRenderTarget->mHeight, 0, 0}; //float params[4] = {mCurRenderTarget->mWidth, mCurRenderTarget->mHeight, 0, 0};
mD3DDeviceContext->VSSetConstantBuffers(0, 1, &matrixBuffer); mD3DDeviceContext->VSSetConstantBuffers(0, 1, &mMatrix2DBuffer);
} }
} }
@ -1003,7 +1265,7 @@ void DXRenderState::ReleaseNative()
void DXRenderState::ReinitNative() void DXRenderState::ReinitNative()
{ {
ReleaseNative();
} }
void DXRenderState::InvalidateRasterizerState() void DXRenderState::InvalidateRasterizerState()
@ -1264,6 +1526,8 @@ DXRenderWindow::DXRenderWindow(DXRenderDevice* renderDevice, WinBFWindow* window
mD3DRenderTargetView = NULL; mD3DRenderTargetView = NULL;
mD3DDepthBuffer = NULL; mD3DDepthBuffer = NULL;
mD3DDepthStencilView = NULL; mD3DDepthStencilView = NULL;
mRefreshRate = 0;
mFrameWaitObject = NULL;
mRenderDevice = renderDevice; mRenderDevice = renderDevice;
mDXRenderDevice = renderDevice; mDXRenderDevice = renderDevice;
@ -1275,30 +1539,31 @@ DXRenderWindow::DXRenderWindow(DXRenderDevice* renderDevice, WinBFWindow* window
ReinitNative(); ReinitNative();
} }
DXRenderWindow::~DXRenderWindow() DXRenderWindow::~DXRenderWindow()
{ {
ReleaseNative(); ReleaseNative();
} }
void DXRenderWindow::ReleaseNative() void DXRenderWindow::ReleaseNative()
{ {
if (mFrameWaitObject != NULL)
::CloseHandle(mFrameWaitObject);
mFrameWaitObject = NULL;
if (mD3DRenderTargetView != NULL) if (mD3DRenderTargetView != NULL)
{
mD3DRenderTargetView->Release(); mD3DRenderTargetView->Release();
mD3DRenderTargetView = NULL; mD3DRenderTargetView = NULL;
}
if (mD3DBackBuffer != NULL) if (mD3DBackBuffer != NULL)
{
mD3DBackBuffer->Release(); mD3DBackBuffer->Release();
mD3DBackBuffer = NULL; mD3DBackBuffer = NULL;
}
if (mDXSwapChain != NULL) if (mDXSwapChain != NULL)
{
mDXSwapChain->Release(); mDXSwapChain->Release();
mDXSwapChain = NULL; mDXSwapChain = NULL;
} if (mD3DRenderTargetView != NULL)
mD3DRenderTargetView->Release();
mD3DRenderTargetView = NULL;
if (mD3DDepthStencilView != NULL)
mD3DDepthStencilView->Release();
mD3DDepthStencilView = NULL;
} }
void DXRenderWindow::ReinitNative() void DXRenderWindow::ReinitNative()
@ -1314,8 +1579,8 @@ void DXRenderWindow::ReinitNative()
swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Windowed = mWindowed ? TRUE : FALSE; swapChainDesc.Windowed = mWindowed ? TRUE : FALSE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;// DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH /*| DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT*/;
IDXGIDevice* pDXGIDevice = NULL; IDXGIDevice* pDXGIDevice = NULL;
mDXRenderDevice->mD3DDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDXGIDevice); mDXRenderDevice->mD3DDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDXGIDevice);
@ -1324,6 +1589,14 @@ void DXRenderWindow::ReinitNative()
pDXGIDevice->Release(); pDXGIDevice->Release();
pDXGIDevice = NULL; pDXGIDevice = NULL;
// IDXGISwapChain2* swapChain2 = NULL;
// mDXSwapChain->QueryInterface(__uuidof(IDXGISwapChain2), (void**)&swapChain2);
// if (swapChain2 != NULL)
// {
// mFrameWaitObject = swapChain2->GetFrameLatencyWaitableObject();
// swapChain2->Release();
// }
DXCHECK(mDXSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mD3DBackBuffer)); DXCHECK(mDXSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mD3DBackBuffer));
DXCHECK(mDXRenderDevice->mD3DDevice->CreateRenderTargetView(mD3DBackBuffer, NULL, &mD3DRenderTargetView)); DXCHECK(mDXRenderDevice->mD3DDevice->CreateRenderTargetView(mD3DBackBuffer, NULL, &mD3DRenderTargetView));
@ -1406,7 +1679,14 @@ void DXRenderWindow::Resized()
mD3DDepthBuffer->Release(); mD3DDepthBuffer->Release();
mD3DRenderTargetView->Release(); mD3DRenderTargetView->Release();
mD3DDepthStencilView->Release(); mD3DDepthStencilView->Release();
DXCHECK(mDXSwapChain->ResizeBuffers(0, mWidth, mHeight, DXGI_FORMAT_UNKNOWN, 0));
HRESULT hr = mDXSwapChain->ResizeBuffers(0, mWidth, mHeight, DXGI_FORMAT_UNKNOWN,
DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH /*| DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT*/);
if ((hr == DXGI_ERROR_DEVICE_REMOVED) || (hr == DXGI_ERROR_DEVICE_RESET))
((DXRenderDevice*)mRenderDevice)->mNeedsReinitNative = true;
else
DXCHECK(hr);
D3D11_TEXTURE2D_DESC descDepth; D3D11_TEXTURE2D_DESC descDepth;
ZeroMemory(&descDepth, sizeof(descDepth)); ZeroMemory(&descDepth, sizeof(descDepth));
@ -1435,8 +1715,10 @@ void DXRenderWindow::Resized()
void DXRenderWindow::Present() void DXRenderWindow::Present()
{ {
mDXSwapChain->Present((mWindow->mFlags & BFWINDOW_VSYNC) ? 1 : 0, 0); HRESULT hr = mDXSwapChain->Present((mWindow->mFlags & BFWINDOW_VSYNC) ? 1 : 0, 0);
//DXCHECK();
if ((hr == DXGI_ERROR_DEVICE_REMOVED) || (hr == DXGI_ERROR_DEVICE_RESET))
((DXRenderDevice*)mRenderDevice)->mNeedsReinitNative = true;
} }
void DXRenderWindow::CopyBitsTo(uint32* dest, int width, int height) void DXRenderWindow::CopyBitsTo(uint32* dest, int width, int height)
@ -1476,21 +1758,102 @@ void DXRenderWindow::CopyBitsTo(uint32* dest, int width, int height)
texture->Release(); texture->Release();
} }
float DXRenderWindow::GetRefreshRate()
{
if (mRefreshRate == 0)
{
mRefreshRate = -1;
IDXGIOutput* output = NULL;
mDXSwapChain->GetContainingOutput(&output);
if (output != NULL)
{
DXGI_OUTPUT_DESC outputDesc;
output->GetDesc(&outputDesc);
MONITORINFOEXW info;
info.cbSize = sizeof(info);
// get the associated monitor info
if (GetMonitorInfoW(outputDesc.Monitor, &info) != 0)
{
// using the CCD get the associated path and display configuration
UINT32 requiredPaths, requiredModes;
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, &requiredModes) == ERROR_SUCCESS)
{
std::vector<DISPLAYCONFIG_PATH_INFO> paths(requiredPaths);
std::vector<DISPLAYCONFIG_MODE_INFO> modes2(requiredModes);
if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, paths.data(), &requiredModes, modes2.data(), nullptr) == ERROR_SUCCESS)
{
// iterate through all the paths until find the exact source to match
for (auto& p : paths)
{
DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName;
sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
sourceName.header.size = sizeof(sourceName);
sourceName.header.adapterId = p.sourceInfo.adapterId;
sourceName.header.id = p.sourceInfo.id;
if (DisplayConfigGetDeviceInfo(&sourceName.header) == ERROR_SUCCESS)
{
// find the matched device which is associated with current device
// there may be the possibility that display may be duplicated and windows may be one of them in such scenario
// there may be two callback because source is same target will be different
// as window is on both the display so either selecting either one is ok
if (wcscmp(info.szDevice, sourceName.viewGdiDeviceName) == 0)
{
// get the refresh rate
UINT numerator = p.targetInfo.refreshRate.Numerator;
UINT denominator = p.targetInfo.refreshRate.Denominator;
mRefreshRate = (float)numerator / (float)denominator;
break;
}
}
}
}
}
}
output->Release();
}
}
return mRefreshRate;
}
bool DXRenderWindow::WaitForVBlank()
{
IDXGIOutput* output = NULL;
mDXSwapChain->GetContainingOutput(&output);
if (output == NULL)
return false;
bool success = output->WaitForVBlank() == 0;
return success;
}
/// ///
DXRenderDevice::DXRenderDevice() DXRenderDevice::DXRenderDevice()
{ {
mD3DDevice = NULL; mD3DDevice = NULL;
mNeedsReinitNative = false;
mMatrix2DBuffer = NULL;
} }
DXRenderDevice::~DXRenderDevice() DXRenderDevice::~DXRenderDevice()
{ {
for (auto& kv : mTextureMap) for (auto window : mRenderWindowList)
kv.mValue->mRenderDevice = NULL; ((DXRenderWindow*)window)->ReleaseNative();
for (auto shader : mShaders)
shader->ReleaseNative();
for (auto renderState : mRenderStates)
renderState->ReleaseNative();
for (auto texture : mTextures)
{
texture->ReleaseNative();
texture->mRenderDevice = NULL;
}
ReleaseNative();
mD3DVertexBuffer->Release();
mD3DIndexBuffer->Release();
delete mDefaultRenderState; delete mDefaultRenderState;
} }
@ -1498,6 +1861,7 @@ bool DXRenderDevice::Init(BFApp* app)
{ {
BP_ZONE("DXRenderDevice::Init"); BP_ZONE("DXRenderDevice::Init");
mApp = app;
WinBFApp* winApp = (WinBFApp*) app; WinBFApp* winApp = (WinBFApp*) app;
D3D_FEATURE_LEVEL featureLevelArr[] = D3D_FEATURE_LEVEL featureLevelArr[] =
@ -1626,6 +1990,9 @@ void DXRenderDevice::ReleaseNative()
{ {
mD3DVertexBuffer->Release(); mD3DVertexBuffer->Release();
mD3DVertexBuffer = NULL; mD3DVertexBuffer = NULL;
if (mMatrix2DBuffer != NULL)
mMatrix2DBuffer->Release();
mMatrix2DBuffer = NULL;
mD3DIndexBuffer->Release(); mD3DIndexBuffer->Release();
mD3DIndexBuffer = NULL; mD3DIndexBuffer = NULL;
mD3DNormalBlendState->Release(); mD3DNormalBlendState->Release();
@ -1636,20 +2003,37 @@ void DXRenderDevice::ReleaseNative()
mD3DWrapSamplerState = NULL; mD3DWrapSamplerState = NULL;
mD3DDeviceContext->Release(); mD3DDeviceContext->Release();
mD3DDeviceContext = NULL; mD3DDeviceContext = NULL;
// ID3D11Debug* debug = NULL;
// mD3DDevice->QueryInterface(__uuidof(ID3D11Debug), (void**)&debug);
// if (debug != NULL)
// {
// debug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL);
// debug->Release();
// }
mD3DDevice->Release(); mD3DDevice->Release();
mD3DDevice = NULL; mD3DDevice = NULL;
} }
void DXRenderDevice::ReinitNative() void DXRenderDevice::ReinitNative()
{ {
Init(NULL); AutoCrit autoCrit(mApp->mCritSect);
if (mMatrix2DBuffer != NULL)
mMatrix2DBuffer->Release();
mMatrix2DBuffer = NULL;
Init(mApp);
for (auto window : mRenderWindowList) for (auto window : mRenderWindowList)
((DXRenderWindow*)window)->ReinitNative(); ((DXRenderWindow*)window)->ReinitNative();
for (auto kv : mRenderStates) for (auto shader : mShaders)
kv->ReinitNative(); shader->ReinitNative();
for (auto kv : mRenderStates) for (auto renderState : mRenderStates)
kv->ReinitNative(); renderState->ReinitNative();
for (auto tex : mTextures)
tex->ReinitNative();
} }
void DXRenderDevice::FrameStart() void DXRenderDevice::FrameStart()
@ -1918,6 +2302,10 @@ Texture* DXRenderDevice::LoadTexture(ImageData* imageData, int flags)
DXCHECK(mD3DDevice->CreateShaderResourceView(d3DTexture, &srDesc, &d3DShaderResourceView)); DXCHECK(mD3DDevice->CreateShaderResourceView(d3DTexture, &srDesc, &d3DShaderResourceView));
DXTexture* aTexture = new DXTexture(); DXTexture* aTexture = new DXTexture();
aTexture->mContentBits = new uint32[aWidth * aHeight];
memcpy(aTexture->mContentBits, imageData->mBits, aWidth * aHeight * 4);
aTexture->mRenderDevice = this; aTexture->mRenderDevice = this;
aTexture->mWidth = aWidth; aTexture->mWidth = aWidth;
aTexture->mHeight = aHeight; aTexture->mHeight = aHeight;
@ -1976,203 +2364,20 @@ Texture* DXRenderDevice::CreateDynTexture(int width, int height)
return aTexture; return aTexture;
} }
extern "C"
typedef HRESULT (WINAPI* Func_D3DX10CompileFromFileW)(LPCWSTR pSrcFile, CONST D3D10_SHADER_MACRO* pDefines, LPD3D10INCLUDE pInclude,
LPCSTR pFunctionName, LPCSTR pProfile, UINT Flags1, UINT Flags2, ID3D10Blob** ppShader, ID3D10Blob** ppErrorMsgs);
static Func_D3DX10CompileFromFileW gFunc_D3DX10CompileFromFileW;
static bool LoadDXShader(const StringImpl& filePath, const StringImpl& entry, const StringImpl& profile, ID3D10Blob** outBuffer)
{
HRESULT hr;
String outObj = filePath + "_" + entry + "_" + profile;
bool useCache = false;
auto srcDate = ::BfpFile_GetTime_LastWrite(filePath.c_str());
auto cacheDate = ::BfpFile_GetTime_LastWrite(outObj.c_str());
if (cacheDate >= srcDate)
useCache = true;
if (!useCache)
{
if (gFunc_D3DX10CompileFromFileW == NULL)
{
auto lib = LoadLibraryA("D3DCompiler_47.dll");
if (lib != NULL)
gFunc_D3DX10CompileFromFileW = (Func_D3DX10CompileFromFileW)::GetProcAddress(lib, "D3DCompileFromFile");
}
if (gFunc_D3DX10CompileFromFileW == NULL)
useCache = true;
}
if (!useCache)
{
if (gFunc_D3DX10CompileFromFileW == NULL)
{
auto lib = LoadLibraryA("D3DCompiler_47.dll");
if (lib != NULL)
gFunc_D3DX10CompileFromFileW = (Func_D3DX10CompileFromFileW)::GetProcAddress(lib, "D3DCompileFromFile");
}
ID3D10Blob* errorMessage = NULL;
auto dxResult = gFunc_D3DX10CompileFromFileW(UTF8Decode(filePath).c_str(), NULL, NULL, entry.c_str(), profile.c_str(),
D3D10_SHADER_DEBUG | D3D10_SHADER_ENABLE_STRICTNESS, 0, outBuffer, &errorMessage);
if (DXFAILED(dxResult))
{
if (errorMessage != NULL)
{
BF_FATAL(StrFormat("Vertex shader load failed: %s", (char*)errorMessage->GetBufferPointer()).c_str());
errorMessage->Release();
}
else
BF_FATAL("Shader load failed");
return false;
}
auto ptr = (*outBuffer)->GetBufferPointer();
int size = (int)(*outBuffer)->GetBufferSize();
FILE* fp = fopen(outObj.c_str(), "wb");
if (fp != NULL)
{
fwrite(ptr, 1, size, fp);
fclose(fp);
}
return true;
}
FILE* fp = fopen(outObj.c_str(), "rb");
if (fp == NULL)
{
BF_FATAL("Failed to load compiled shader");
return false;
}
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
fseek(fp, 0, SEEK_SET);
D3D10CreateBlob(size, outBuffer);
auto ptr = (*outBuffer)->GetBufferPointer();
fread(ptr, 1, size, fp);
fclose(fp);
return true;
}
Shader* DXRenderDevice::LoadShader(const StringImpl& fileName, VertexDefinition* vertexDefinition) Shader* DXRenderDevice::LoadShader(const StringImpl& fileName, VertexDefinition* vertexDefinition)
{ {
BP_ZONE("DXRenderDevice::LoadShader"); BP_ZONE("DXRenderDevice::LoadShader");
//HRESULT hr;
ID3D10Blob* errorMessage = NULL;
ID3D10Blob* vertexShaderBuffer = NULL;
ID3D10Blob* pixelShaderBuffer = NULL;
LoadDXShader(fileName + ".fx", "VS", "vs_4_0", &vertexShaderBuffer);
LoadDXShader(fileName + ".fx", "PS", "ps_4_0", &pixelShaderBuffer);
DXShader* dxShader = new DXShader(); DXShader* dxShader = new DXShader();
dxShader->mRenderDevice = this;
dxShader->mVertexSize = 0; dxShader->mSrcPath = fileName;
dxShader->mD3DLayout = NULL; dxShader->mVertexDef = new VertexDefinition(vertexDefinition);
if (!dxShader->Load())
static const char* semanticNames[] = {
"POSITION",
"POSITION",
"COLOR",
"TEXCOORD",
"NORMAL",
"BINORMAL",
"TANGENT",
"BLENDINDICES",
"BLENDWEIGHT",
"DEPTH",
"FOG",
"POINTSIZE",
"SAMPLE",
"TESSELLATEFACTOR"};
static const DXGI_FORMAT dxgiFormat[] = {
DXGI_FORMAT_R32_FLOAT/*VertexElementFormat_Single*/,
DXGI_FORMAT_R32G32_FLOAT/*VertexElementFormat_Vector2*/,
DXGI_FORMAT_R32G32B32_FLOAT/*VertexElementFormat_Vector3*/,
DXGI_FORMAT_R32G32B32A32_FLOAT/*VertexElementFormat_Vector4*/,
DXGI_FORMAT_R8G8B8A8_UNORM/*VertexElementFormat_Color*/,
DXGI_FORMAT_R8G8B8A8_UINT/*VertexElementFormat_Byte4*/,
DXGI_FORMAT_R16G16_UINT/*VertexElementFormat_Short2*/,
DXGI_FORMAT_R16G16B16A16_UINT/*VertexElementFormat_Short4*/,
DXGI_FORMAT_R16G16_UNORM/*VertexElementFormat_NormalizedShort2*/,
DXGI_FORMAT_R16G16B16A16_UNORM/*VertexElementFormat_NormalizedShort4*/,
DXGI_FORMAT_R16G16_FLOAT/*VertexElementFormat_HalfVector2*/,
DXGI_FORMAT_R16G16B16A16_FLOAT/*VertexElementFormat_HalfVector4*/
};
static const int dxgiSize[] = {
sizeof(float) * 1/*VertexElementFormat_Single*/,
sizeof(float) * 2/*VertexElementFormat_Vector2*/,
sizeof(float) * 3/*VertexElementFormat_Vector3*/,
sizeof(float) * 4/*VertexElementFormat_Vector4*/,
sizeof(uint32)/*VertexElementFormat_Color*/,
sizeof(uint8) * 4/*VertexElementFormat_Byte4*/,
sizeof(uint16) * 2/*VertexElementFormat_Short2*/,
sizeof(uint16) * 4/*VertexElementFormat_Short4*/,
sizeof(uint16) * 2/*VertexElementFormat_NormalizedShort2*/,
sizeof(uint16) * 4/*VertexElementFormat_NormalizedShort4*/,
sizeof(uint16) * 2/*VertexElementFormat_HalfVector2*/,
sizeof(uint16) * 4/*VertexElementFormat_HalfVector4*/
};
D3D11_INPUT_ELEMENT_DESC layout[64];
for (int elementIdx = 0; elementIdx < vertexDefinition->mNumElements; elementIdx++)
{ {
VertexDefData* vertexDefData = &vertexDefinition->mElementData[elementIdx]; delete dxShader;
return NULL;
if (vertexDefData->mUsage == VertexElementUsage_Position2D)
dxShader->mHas2DPosition = true;
D3D11_INPUT_ELEMENT_DESC* elementDesc = &layout[elementIdx];
elementDesc->SemanticName = semanticNames[vertexDefData->mUsage];
elementDesc->SemanticIndex = vertexDefData->mUsageIndex;
elementDesc->Format = dxgiFormat[vertexDefData->mFormat];
elementDesc->InputSlot = 0;
elementDesc->AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
elementDesc->InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
elementDesc->InstanceDataStepRate = 0;
dxShader->mVertexSize += dxgiSize[vertexDefData->mFormat];
} }
mShaders.Add(dxShader);
/* =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = sizeof(layout) / sizeof(layout[0]);*/
HRESULT result = mD3DDevice->CreateInputLayout(layout, vertexDefinition->mNumElements, vertexShaderBuffer->GetBufferPointer(),
vertexShaderBuffer->GetBufferSize(), &dxShader->mD3DLayout);
DXCHECK(result);
if (FAILED(result))
return NULL;
// Create the vertex shader from the buffer.
result = mD3DDevice->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), NULL, &dxShader->mD3DVertexShader);
DXCHECK(result);
if (FAILED(result))
return NULL;
// Create the pixel shader from the buffer.
result = mD3DDevice->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), NULL, &dxShader->mD3DPixelShader);
DXCHECK(result);
if (FAILED(result))
return NULL;
vertexShaderBuffer->Release();
pixelShaderBuffer->Release();
dxShader->Init();
return dxShader; return dxShader;
} }

View file

@ -63,14 +63,14 @@ public:
ID3D11RenderTargetView* mD3DRenderTargetView; ID3D11RenderTargetView* mD3DRenderTargetView;
ID3D11Texture2D* mD3DDepthBuffer; ID3D11Texture2D* mD3DDepthBuffer;
ID3D11DepthStencilView* mD3DDepthStencilView; ID3D11DepthStencilView* mD3DDepthStencilView;
ImageData* mImageData; uint32* mContentBits;
public: public:
DXTexture(); DXTexture();
~DXTexture(); ~DXTexture();
void ReleaseNative(); void ReleaseNative();
void ReinitNative(); void ReinitNative();
virtual void PhysSetAsTarget() override; virtual void PhysSetAsTarget() override;
virtual void Blt(ImageData* imageData, int x, int y) override; virtual void Blt(ImageData* imageData, int x, int y) override;
@ -96,6 +96,10 @@ typedef std::map<String, DXShaderParam*> DXShaderParamMap;
class DXShader : public Shader class DXShader : public Shader
{ {
public: public:
DXRenderDevice* mRenderDevice;
String mSrcPath;
VertexDefinition* mVertexDef;
ID3D11InputLayout* mD3DLayout; ID3D11InputLayout* mD3DLayout;
ID3D11VertexShader* mD3DVertexShader; ID3D11VertexShader* mD3DVertexShader;
ID3D11PixelShader* mD3DPixelShader; ID3D11PixelShader* mD3DPixelShader;
@ -107,6 +111,10 @@ public:
DXShader(); DXShader();
~DXShader(); ~DXShader();
void ReleaseNative();
void ReinitNative();
bool Load();
virtual ShaderParam* GetShaderParam(const StringImpl& name) override; virtual ShaderParam* GetShaderParam(const StringImpl& name) override;
}; };
@ -144,6 +152,8 @@ public:
ID3D11RenderTargetView* mD3DRenderTargetView; ID3D11RenderTargetView* mD3DRenderTargetView;
ID3D11Texture2D* mD3DDepthBuffer; ID3D11Texture2D* mD3DDepthBuffer;
ID3D11DepthStencilView* mD3DDepthStencilView; ID3D11DepthStencilView* mD3DDepthStencilView;
HANDLE mFrameWaitObject;
float mRefreshRate;
bool mResizePending; bool mResizePending;
bool mWindowed; bool mWindowed;
int mPendingWidth; int mPendingWidth;
@ -164,6 +174,8 @@ public:
virtual void Present() override; virtual void Present() override;
void CopyBitsTo(uint32* dest, int width, int height); void CopyBitsTo(uint32* dest, int width, int height);
virtual float GetRefreshRate() override;
virtual bool WaitForVBlank() override;
}; };
typedef std::vector<DXDrawBatch*> DXDrawBatchVector; typedef std::vector<DXDrawBatch*> DXDrawBatchVector;
@ -285,8 +297,9 @@ public:
ID3D11BlendState* mD3DNormalBlendState; ID3D11BlendState* mD3DNormalBlendState;
ID3D11SamplerState* mD3DDefaultSamplerState; ID3D11SamplerState* mD3DDefaultSamplerState;
ID3D11SamplerState* mD3DWrapSamplerState; ID3D11SamplerState* mD3DWrapSamplerState;
bool mHasVSync; bool mNeedsReinitNative;
ID3D11Buffer* mMatrix2DBuffer;
ID3D11Buffer* mD3DVertexBuffer; ID3D11Buffer* mD3DVertexBuffer;
ID3D11Buffer* mD3DIndexBuffer; ID3D11Buffer* mD3DIndexBuffer;
int mVtxByteIdx; int mVtxByteIdx;
@ -294,6 +307,7 @@ public:
HashSet<DXRenderState*> mRenderStates; HashSet<DXRenderState*> mRenderStates;
HashSet<DXTexture*> mTextures; HashSet<DXTexture*> mTextures;
HashSet<DXShader*> mShaders;
Dictionary<String, DXTexture*> mTextureMap; Dictionary<String, DXTexture*> mTextureMap;
Dictionary<int, ID3D11Buffer*> mBufferMap; Dictionary<int, ID3D11Buffer*> mBufferMap;

View file

@ -600,6 +600,9 @@ LRESULT WinBFWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
switch (uMsg) switch (uMsg)
{ {
case WM_DISPLAYCHANGE:
((DXRenderWindow*)mRenderWindow)->mRefreshRate = 0;
break;
case WM_SIZE: case WM_SIZE:
mRenderWindow->Resized(); mRenderWindow->Resized();
if (mMovedFunc != NULL) if (mMovedFunc != NULL)
@ -986,7 +989,6 @@ LRESULT WinBFWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
case WM_SYSKEYDOWN: case WM_SYSKEYDOWN:
case WM_KEYDOWN: case WM_KEYDOWN:
{ {
mIsMenuKeyHandled = false; mIsMenuKeyHandled = false;
int keyCode = (int) wParam; int keyCode = (int) wParam;
if (keyCode == VK_APPS) if (keyCode == VK_APPS)
@ -997,6 +999,11 @@ LRESULT WinBFWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
mIsKeyDown[keyCode] = true; mIsKeyDown[keyCode] = true;
// if ((keyCode == 192) && (mIsKeyDown[VK_MENU]))
// {
// ((DXRenderDevice*)mRenderWindow->mRenderDevice)->mNeedsReinitNative = true;
// }
for (auto kv : *menuIDMap) for (auto kv : *menuIDMap)
{ {
WinBFMenu* aMenu = kv.mValue; WinBFMenu* aMenu = kv.mValue;
@ -1275,10 +1282,71 @@ WinBFApp::WinBFApp()
mInMsgProc = false; mInMsgProc = false;
mDSoundManager = NULL; mDSoundManager = NULL;
mDInputManager = NULL; mDInputManager = NULL;
mVSyncThreadId = 0;
mClosing = false;
mVSyncActive = false;
mVSyncThread = BfpThread_Create(VSyncThreadProcThunk, (void*)this, 128 * 1024, BfpThreadCreateFlag_StackSizeReserve, &mVSyncThreadId);
BfpThread_SetPriority(mVSyncThread, BfpThreadPriority_High, NULL);
}
void BFP_CALLTYPE WinBFApp::VSyncThreadProcThunk(void* ptr)
{
((WinBFApp*)ptr)->VSyncThreadProc();
}
void WinBFApp::VSyncThreadProc()
{
while (!mClosing)
{
bool didWait = false;
IDXGIOutput* output = NULL;
//
{
AutoCrit autoCrit(mCritSect);
if ((mRenderDevice != NULL) && (!mRenderDevice->mRenderWindowList.IsEmpty()))
{
auto renderWindow = (DXRenderWindow*)mRenderDevice->mRenderWindowList[0];
renderWindow->mDXSwapChain->GetContainingOutput(&output);
}
}
if (output != NULL)
{
DWORD start = GetTickCount();
bool success = output->WaitForVBlank() == 0;
int elapsed = (int)(GetTickCount() - start);
if (elapsed >= 20)
{
NOP;
}
if (success)
{
didWait = true;
mVSyncActive = true;
mVSyncEvent.Set();
}
output->Release();
}
if (!didWait)
{
mVSyncActive = false;
BfpThread_Sleep(20);
}
}
} }
WinBFApp::~WinBFApp() WinBFApp::~WinBFApp()
{ {
mClosing = true;
BfpThread_WaitFor(mVSyncThread, -1);
BfpThread_Release(mVSyncThread);
delete mRenderDevice; delete mRenderDevice;
delete mDSoundManager; delete mDSoundManager;
delete mDInputManager; delete mDInputManager;
@ -1288,6 +1356,8 @@ void WinBFApp::Init()
{ {
BP_ZONE("WinBFApp::Init"); BP_ZONE("WinBFApp::Init");
AutoCrit autoCrit(mCritSect);
mRunning = true; mRunning = true;
mInMsgProc = false; mInMsgProc = false;
@ -1311,6 +1381,19 @@ void WinBFApp::Run()
} }
} }
void WinBFApp::Process()
{
BFApp::Process();
auto dxRenderDevice = (DXRenderDevice*)mRenderDevice;
if (dxRenderDevice->mNeedsReinitNative)
{
dxRenderDevice->mNeedsReinitNative = false;
dxRenderDevice->ReinitNative();
mForceNextDraw = true;
}
}
void WinBFApp::Draw() void WinBFApp::Draw()
{ {
mRenderDevice->FrameStart(); mRenderDevice->FrameStart();
@ -1392,6 +1475,8 @@ void WinBFApp::GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fro
BFWindow* WinBFApp::CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags) BFWindow* WinBFApp::CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags)
{ {
AutoCrit autoCrit(mCritSect);
BFWindow* aWindow = new WinBFWindow(parent, title, x, y, width, height, windowFlags); BFWindow* aWindow = new WinBFWindow(parent, title, x, y, width, height, windowFlags);
mWindowList.push_back(aWindow); mWindowList.push_back(aWindow);
@ -2025,6 +2110,13 @@ BFSoundManager* WinBFApp::GetSoundManager()
return mDSoundManager; return mDSoundManager;
} }
intptr WinBFApp::GetCriticalThreadId(int idx)
{
if (idx == 0)
return mVSyncThreadId;
return 0;
}
void WinBFWindow::ModalsRemoved() void WinBFWindow::ModalsRemoved()
{ {
::EnableWindow(mHWnd, TRUE); ::EnableWindow(mHWnd, TRUE);

View file

@ -98,8 +98,14 @@ public:
StringToUIntMap mClipboardFormatMap; StringToUIntMap mClipboardFormatMap;
DSoundManager* mDSoundManager; DSoundManager* mDSoundManager;
DInputManager* mDInputManager; DInputManager* mDInputManager;
BfpThreadId mVSyncThreadId;
BfpThread* mVSyncThread;
volatile bool mClosing;
protected: protected:
void VSyncThreadProc();
static void BFP_CALLTYPE VSyncThreadProcThunk(void* ptr);
virtual void Draw() override; virtual void Draw() override;
virtual void PhysSetCursor() override; virtual void PhysSetCursor() override;
@ -111,6 +117,7 @@ public:
virtual void Init() override; virtual void Init() override;
virtual void Run() override; virtual void Run() override;
virtual void Process() override;
virtual void GetDesktopResolution(int& width, int& height) override; virtual void GetDesktopResolution(int& width, int& height) override;
virtual void GetWorkspaceRect(int& x, int& y, int& width, int& height) override; virtual void GetWorkspaceRect(int& x, int& y, int& width, int& height) override;
@ -129,6 +136,8 @@ public:
virtual BFSysBitmap* LoadSysBitmap(const WCHAR* fileName) override; virtual BFSysBitmap* LoadSysBitmap(const WCHAR* fileName) override;
virtual BFSoundManager* GetSoundManager() override; virtual BFSoundManager* GetSoundManager() override;
virtual intptr GetCriticalThreadId(int idx) override;
}; };
NS_BF_END; NS_BF_END;

View file

@ -11767,7 +11767,6 @@ namespace IDE
public override void Init() public override void Init()
{ {
scope AutoBeefPerf("IDEApp.Init"); scope AutoBeefPerf("IDEApp.Init");
//int zag = 123; //int zag = 123;
if (mVerbosity == .Default) if (mVerbosity == .Default)
@ -14203,7 +14202,7 @@ namespace IDE
//mDebugger.InitiateHotResolve(.ActiveMethods | .Allocations); //mDebugger.InitiateHotResolve(.ActiveMethods | .Allocations);
} }
public override void Draw() public override void Draw(bool forceDraw)
{ {
scope AutoBeefPerf("IDEApp.Draw"); scope AutoBeefPerf("IDEApp.Draw");
#if CLI #if CLI
@ -14213,7 +14212,7 @@ namespace IDE
if (mBfResolveSystem != null) if (mBfResolveSystem != null)
{ {
mBfResolveSystem.PerfZoneStart("IDEApp.Draw"); mBfResolveSystem.PerfZoneStart("IDEApp.Draw");
base.Draw(); base.Draw(forceDraw);
mBfResolveSystem.PerfZoneEnd(); mBfResolveSystem.PerfZoneEnd();
if (mBfResolveSystem.mIsTiming) if (mBfResolveSystem.mIsTiming)
{ {
@ -14222,7 +14221,7 @@ namespace IDE
} }
} }
else else
base.Draw(); base.Draw(forceDraw);
} }
public void DrawSquiggle(Graphics g, float x, float y, float width) public void DrawSquiggle(Graphics g, float x, float y, float width)

View file

@ -3,11 +3,15 @@ using Beefy.gfx;
using System; using System;
using Beefy.events; using Beefy.events;
using Beefy.widgets; using Beefy.widgets;
using System.Collections;
using System.Diagnostics;
namespace IDE.ui namespace IDE.ui
{ {
class AboutDialog : IDEDialog class AboutDialog : IDEDialog
{ {
static AboutDialog gAboutDialog;
const int cWidth = 320; const int cWidth = 320;
const int cHeight = 240; const int cHeight = 240;
const int cRandSize = 3777; const int cRandSize = 3777;
@ -21,6 +25,14 @@ namespace IDE.ui
uint8[cRandSize] mRand; uint8[cRandSize] mRand;
int mRandIdx; int mRandIdx;
Stopwatch mStopwatch = new .()..Start() ~ delete _;
struct Entry
{
public double mUpdateCntF;
public float mTimeMS;
}
List<Entry> mEntries = new .() ~ delete _;
struct CColor struct CColor
{ {
public uint8 r; public uint8 r;
@ -70,6 +82,22 @@ namespace IDE.ui
Color colorOut = Color.ToNative(Color.Lerp(mainColors[(int)colorPos], mainColors[(int)colorPos + 1], colorPos - (int)colorPos)); Color colorOut = Color.ToNative(Color.Lerp(mainColors[(int)colorPos], mainColors[(int)colorPos + 1], colorPos - (int)colorPos));
mPalette[i] = colorOut; mPalette[i] = colorOut;
} }
/*mWindowFlags |= .Resizable;
mWindowFlags &= ~.Modal;*/
gAboutDialog = this;
}
~this()
{
gAboutDialog = null;
}
public override void AddedToParent()
{
base.AddedToParent();
mWidgetWindow.mWantsUpdateF = true;
} }
public override void CalcSize() public override void CalcSize()
@ -140,12 +168,12 @@ namespace IDE.ui
mImage.SetBits(0, 0, cWidth, cHeight, cWidth, newBits); mImage.SetBits(0, 0, cWidth, cHeight, cWidth, newBits);
float ang = Math.Min(mUpdateCnt * 0.006f, Math.PI_f / 2); float ang = Math.Min((float)(mUpdateCntF * 0.006f), Math.PI_f / 2);
g.SetFont(mBigFont); g.SetFont(mBigFont);
g.DrawString("Beef IDE", 0, GS!(20) + (1.0f - Math.Sin(ang))*GS!(300), .Centered, mWidth); g.DrawString("Beef IDE", 0, GS!(20) + (1.0f - Math.Sin(ang))*GS!(300), .Centered, mWidth);
float angMed = Math.Min(mUpdateCnt * 0.0055f, Math.PI_f / 2); float angMed = Math.Min((float)(mUpdateCntF * 0.0055f), Math.PI_f / 2);
float alpha = Math.Clamp(mUpdateCnt * 0.007f - 1.3f, 0, 1.0f); float alpha = Math.Clamp((float)(mUpdateCntF * 0.007f) - 1.3f, 0, 1.0f);
using (g.PushColor(Color.Get(alpha))) using (g.PushColor(Color.Get(alpha)))
{ {
@ -164,6 +192,33 @@ namespace IDE.ui
} }
g.DrawQuad(mImage, 0, 0, 0.0f, 0.0f, mWidth, mHeight, 1.0f, 1.0f); g.DrawQuad(mImage, 0, 0, 0.0f, 0.0f, mWidth, mHeight, 1.0f, 1.0f);
/*if (gAboutDialog == this)
{
/*Entry entry;
entry.mTimeMS = mStopwatch.ElapsedMicroseconds / 1000.0f;
entry.mUpdateCntF = mUpdateCntF;*/
mEntries.Add(Entry() {mTimeMS = mStopwatch.ElapsedMicroseconds / 1000.0f, mUpdateCntF = mUpdateCntF});
if (mEntries.Count == 100)
{
float prevTime = 0;
for (var entry in mEntries)
{
Debug.WriteLine($"Entry Time:{entry.mTimeMS - prevTime:0.00} UpdateCntF:{entry.mUpdateCntF:0.00}");
prevTime = entry.mTimeMS;
if (@entry.Index == 20)
break;
}
mEntries.Clear();
}
}
using (g.PushColor(0xFFFFFFFF))
g.FillRect(Math.Cos((float)(mUpdateCntF * 0.2f)) * 600 + mWidth / 2, 0, 8, mHeight);*/
} }
public override void Update() public override void Update()
@ -177,6 +232,12 @@ namespace IDE.ui
DoFire(); DoFire();
} }
public override void UpdateF(float updatePct)
{
base.UpdateF(updatePct);
MarkDirty();
}
public override void KeyDown(KeyCode keyCode, bool isRepeat) public override void KeyDown(KeyCode keyCode, bool isRepeat)
{ {
base.KeyDown(keyCode, isRepeat); base.KeyDown(keyCode, isRepeat);

View file

@ -6508,7 +6508,7 @@ namespace IDE.ui
} }
} }
public void UpdateCollapse() public void UpdateCollapse(float updatePct)
{ {
MarkDirty(); MarkDirty();
@ -6564,9 +6564,12 @@ namespace IDE.ui
{ {
if (emitEmbed.mIsOpen) if (emitEmbed.mIsOpen)
{ {
emitEmbed.mOpenPct = Math.Min(1.0f, emitEmbed.mOpenPct + 0.1f); emitEmbed.mOpenPct = Math.Min(1.0f, emitEmbed.mOpenPct + 0.1f * updatePct);
if (emitEmbed.mOpenPct != 1.0f) if (emitEmbed.mOpenPct != 1.0f)
{
mCollapseNeedsUpdate = true; mCollapseNeedsUpdate = true;
mWidgetWindow.mTempWantsUpdateF = true;
}
if (emitEmbed.mView == null) if (emitEmbed.mView == null)
{ {
@ -6577,7 +6580,7 @@ namespace IDE.ui
} }
else else
{ {
emitEmbed.mOpenPct = Math.Max(0.0f, emitEmbed.mOpenPct - 0.1f); emitEmbed.mOpenPct = Math.Max(0.0f, emitEmbed.mOpenPct - 0.1f * updatePct);
if (emitEmbed.mOpenPct == 0.0f) if (emitEmbed.mOpenPct == 0.0f)
{ {
if (emitEmbed.mView != null) if (emitEmbed.mView != null)
@ -6587,7 +6590,10 @@ namespace IDE.ui
} }
} }
else else
{
mCollapseNeedsUpdate = true; mCollapseNeedsUpdate = true;
mWidgetWindow.mTempWantsUpdateF = true;
}
} }
} }
} }
@ -6664,13 +6670,14 @@ namespace IDE.ui
var entry = mOrderedCollapseEntries[animIdx]; var entry = mOrderedCollapseEntries[animIdx];
if ((entry.mIsOpen) && (entry.mOpenPct < 1.0f)) if ((entry.mIsOpen) && (entry.mOpenPct < 1.0f))
{ {
entry.mOpenPct = Math.Min(entry.mOpenPct + animSpeed, 1.0f); entry.mOpenPct = Math.Min(entry.mOpenPct + animSpeed * updatePct, 1.0f);
mWidgetWindow.mTempWantsUpdateF = true;
} }
if ((!entry.mIsOpen) && (entry.mOpenPct > 0)) if ((!entry.mIsOpen) && (entry.mOpenPct > 0))
{ {
entry.mOpenPct = Math.Max(entry.mOpenPct - animSpeed, 0.0f); entry.mOpenPct = Math.Max(entry.mOpenPct - animSpeed * updatePct, 0.0f);
mWidgetWindow.mTempWantsUpdateF = true;
if (entry.mOpenPct == 0.0f) if (entry.mOpenPct == 0.0f)
FinishCollapseClose(animIdx, entry); FinishCollapseClose(animIdx, entry);
} }

View file

@ -639,6 +639,7 @@ namespace IDE.ui
mNavigationBar = new NavigationBar(this); mNavigationBar = new NavigationBar(this);
AddWidget(mNavigationBar); AddWidget(mNavigationBar);
} }
mAlwaysUpdateF = true;
} }
public ~this() public ~this()
{ {
@ -6811,13 +6812,19 @@ namespace IDE.ui
UpdateQueuedEmitShowData(); UpdateQueuedEmitShowData();
if (ewc.mCollapseNeedsUpdate)
ewc.UpdateCollapse();
// Process after mQueuedCollapseData so mCharIdSpan is still valid // Process after mQueuedCollapseData so mCharIdSpan is still valid
ProcessDeferredResolveResults(0); ProcessDeferredResolveResults(0);
} }
public override void UpdateF(float updatePct)
{
base.UpdateF(updatePct);
var ewc = (SourceEditWidgetContent)mEditWidget.Content;
if (ewc.mCollapseNeedsUpdate)
ewc.UpdateCollapse(updatePct);
}
public void UpdateQueuedEmitShowData() public void UpdateQueuedEmitShowData()
{ {
var compiler = ResolveCompiler; var compiler = ResolveCompiler;