Commit 0db0d6c8 by apatrick@chromium.org

Replaces swap chain lazily when the swap interval is changed.

It does not appear to be possible to pass a presentation interval to Present() or change it after creating the swap chain, short of calling Reset(). I decided to try fixing it by replacing the swap chain under the same conditions as a window resize. I tested it with a modified version of the simple vertex shader sample, passing various values to eglSwapInterval. My reading of the EGL spec might be wrong but I believe the interval state should be associated with the surface bound to the current context, rather than the display. Review URL: http://codereview.appspot.com/2036044 git-svn-id: https://angleproject.googlecode.com/svn/trunk@408 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 6a20d108
...@@ -41,7 +41,6 @@ Display::Display(HDC deviceContext) : mDc(deviceContext) ...@@ -41,7 +41,6 @@ Display::Display(HDC deviceContext) : mDc(deviceContext)
mMinSwapInterval = 1; mMinSwapInterval = 1;
mMaxSwapInterval = 1; mMaxSwapInterval = 1;
setSwapInterval(1);
} }
Display::~Display() Display::~Display()
...@@ -452,33 +451,14 @@ bool Display::hasExistingWindowSurface(HWND window) ...@@ -452,33 +451,14 @@ bool Display::hasExistingWindowSurface(HWND window)
return false; return false;
} }
void Display::setSwapInterval(GLint interval) EGLint Display::getMinSwapInterval()
{ {
mSwapInterval = interval; return mMinSwapInterval;
mSwapInterval = std::max(mSwapInterval, mMinSwapInterval);
mSwapInterval = std::min(mSwapInterval, mMaxSwapInterval);
mPresentInterval = convertInterval(mSwapInterval);
}
DWORD Display::getPresentInterval()
{
return mPresentInterval;
} }
DWORD Display::convertInterval(GLint interval) EGLint Display::getMaxSwapInterval()
{ {
switch(interval) return mMaxSwapInterval;
{
case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
case 1: return D3DPRESENT_INTERVAL_ONE;
case 2: return D3DPRESENT_INTERVAL_TWO;
case 3: return D3DPRESENT_INTERVAL_THREE;
case 4: return D3DPRESENT_INTERVAL_FOUR;
default: UNREACHABLE();
}
return D3DPRESENT_INTERVAL_DEFAULT;
} }
IDirect3DDevice9 *Display::getDevice() IDirect3DDevice9 *Display::getDevice()
...@@ -587,7 +567,7 @@ D3DPRESENT_PARAMETERS Display::getPresentParameters() ...@@ -587,7 +567,7 @@ D3DPRESENT_PARAMETERS Display::getPresentParameters()
presentParameters.hDeviceWindow = mDeviceWindow; presentParameters.hDeviceWindow = mDeviceWindow;
presentParameters.MultiSampleQuality = 0; presentParameters.MultiSampleQuality = 0;
presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
presentParameters.PresentationInterval = convertInterval(mMinSwapInterval); presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
presentParameters.Windowed = TRUE; presentParameters.Windowed = TRUE;
......
...@@ -54,9 +54,8 @@ class Display ...@@ -54,9 +54,8 @@ class Display
bool isValidSurface(egl::Surface *surface); bool isValidSurface(egl::Surface *surface);
bool hasExistingWindowSurface(HWND window); bool hasExistingWindowSurface(HWND window);
void setSwapInterval(GLint interval); EGLint getMinSwapInterval();
DWORD getPresentInterval(); EGLint getMaxSwapInterval();
static DWORD convertInterval(GLint interval);
virtual IDirect3DDevice9 *getDevice(); virtual IDirect3DDevice9 *getDevice();
virtual D3DCAPS9 getDeviceCaps(); virtual D3DCAPS9 getDeviceCaps();
...@@ -84,11 +83,9 @@ class Display ...@@ -84,11 +83,9 @@ class Display
HWND mDeviceWindow; HWND mDeviceWindow;
bool mSceneStarted; bool mSceneStarted;
GLint mSwapInterval;
EGLint mMaxSwapInterval; EGLint mMaxSwapInterval;
EGLint mMinSwapInterval; EGLint mMinSwapInterval;
DWORD mPresentInterval;
typedef std::set<Surface*> SurfaceSet; typedef std::set<Surface*> SurfaceSet;
SurfaceSet mSurfaceSet; SurfaceSet mSurfaceSet;
......
...@@ -31,6 +31,8 @@ Surface::Surface(Display *display, const Config *config, HWND window) ...@@ -31,6 +31,8 @@ Surface::Surface(Display *display, const Config *config, HWND window)
mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
mRenderBuffer = EGL_BACK_BUFFER; mRenderBuffer = EGL_BACK_BUFFER;
mSwapBehavior = EGL_BUFFER_PRESERVED; mSwapBehavior = EGL_BUFFER_PRESERVED;
mSwapInterval = -1;
setSwapInterval(1);
resetSwapChain(); resetSwapChain();
} }
...@@ -99,7 +101,7 @@ void Surface::resetSwapChain() ...@@ -99,7 +101,7 @@ void Surface::resetSwapChain()
presentParameters.hDeviceWindow = getWindowHandle(); presentParameters.hDeviceWindow = getWindowHandle();
presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented
presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented
presentParameters.PresentationInterval = Display::convertInterval(mConfig->mMinSwapInterval); presentParameters.PresentationInterval = mPresentInterval;
presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD; presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
presentParameters.Windowed = TRUE; presentParameters.Windowed = TRUE;
...@@ -190,6 +192,8 @@ void Surface::resetSwapChain() ...@@ -190,6 +192,8 @@ void Surface::resetSwapChain()
mRenderTarget = renderTarget; mRenderTarget = renderTarget;
mFlipTexture = flipTexture; mFlipTexture = flipTexture;
mPresentIntervalDirty = false;
// The flip state block recorded mFlipTexture so it is now invalid. // The flip state block recorded mFlipTexture so it is now invalid.
releaseRecordedState(device); releaseRecordedState(device);
} }
...@@ -322,7 +326,7 @@ void Surface::releaseRecordedState(IDirect3DDevice9 *device) ...@@ -322,7 +326,7 @@ void Surface::releaseRecordedState(IDirect3DDevice9 *device)
} }
} }
bool Surface::checkForWindowResize() bool Surface::checkForOutOfDateSwapChain()
{ {
RECT client; RECT client;
if (!GetClientRect(getWindowHandle(), &client)) if (!GetClientRect(getWindowHandle(), &client))
...@@ -331,7 +335,7 @@ bool Surface::checkForWindowResize() ...@@ -331,7 +335,7 @@ bool Surface::checkForWindowResize()
return false; return false;
} }
if (getWidth() != client.right - client.left || getHeight() != client.bottom - client.top) if (getWidth() != client.right - client.left || getHeight() != client.bottom - client.top || mPresentIntervalDirty)
{ {
resetSwapChain(); resetSwapChain();
...@@ -346,6 +350,22 @@ bool Surface::checkForWindowResize() ...@@ -346,6 +350,22 @@ bool Surface::checkForWindowResize()
return false; return false;
} }
DWORD Surface::convertInterval(EGLint interval)
{
switch(interval)
{
case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
case 1: return D3DPRESENT_INTERVAL_ONE;
case 2: return D3DPRESENT_INTERVAL_TWO;
case 3: return D3DPRESENT_INTERVAL_THREE;
case 4: return D3DPRESENT_INTERVAL_FOUR;
default: UNREACHABLE();
}
return D3DPRESENT_INTERVAL_DEFAULT;
}
bool Surface::swap() bool Surface::swap()
{ {
if (mSwapChain) if (mSwapChain)
...@@ -359,7 +379,7 @@ bool Surface::swap() ...@@ -359,7 +379,7 @@ bool Surface::swap()
EGLint oldWidth = mWidth; EGLint oldWidth = mWidth;
EGLint oldHeight = mHeight; EGLint oldHeight = mHeight;
checkForWindowResize(); checkForOutOfDateSwapChain();
IDirect3DDevice9 *device = mDisplay->getDevice(); IDirect3DDevice9 *device = mDisplay->getDevice();
...@@ -392,7 +412,7 @@ bool Surface::swap() ...@@ -392,7 +412,7 @@ bool Surface::swap()
restoreState(device); restoreState(device);
mDisplay->endScene(); mDisplay->endScene();
HRESULT result = mSwapChain->Present(NULL, NULL, NULL, NULL, mDisplay->getPresentInterval()); HRESULT result = mSwapChain->Present(NULL, NULL, NULL, NULL, 0);
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
{ {
...@@ -440,4 +460,19 @@ IDirect3DSurface9 *Surface::getDepthStencil() ...@@ -440,4 +460,19 @@ IDirect3DSurface9 *Surface::getDepthStencil()
return mDepthStencil; return mDepthStencil;
} }
void Surface::setSwapInterval(EGLint interval)
{
if (mSwapInterval == interval)
{
return;
}
mSwapInterval = interval;
mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval());
mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval());
mPresentInterval = convertInterval(mSwapInterval);
mPresentIntervalDirty = true;
}
} }
...@@ -41,6 +41,8 @@ class Surface ...@@ -41,6 +41,8 @@ class Surface
virtual IDirect3DSurface9 *getRenderTarget(); virtual IDirect3DSurface9 *getRenderTarget();
virtual IDirect3DSurface9 *getDepthStencil(); virtual IDirect3DSurface9 *getDepthStencil();
void setSwapInterval(EGLint interval);
private: private:
DISALLOW_COPY_AND_ASSIGN(Surface); DISALLOW_COPY_AND_ASSIGN(Surface);
...@@ -51,7 +53,9 @@ class Surface ...@@ -51,7 +53,9 @@ class Surface
IDirect3DSurface9 *mDepthStencil; IDirect3DSurface9 *mDepthStencil;
IDirect3DTexture9 *mFlipTexture; IDirect3DTexture9 *mFlipTexture;
bool checkForWindowResize(); bool checkForOutOfDateSwapChain();
static DWORD convertInterval(EGLint interval);
void applyFlipState(IDirect3DDevice9 *device); void applyFlipState(IDirect3DDevice9 *device);
void restoreState(IDirect3DDevice9 *device); void restoreState(IDirect3DDevice9 *device);
...@@ -79,6 +83,9 @@ class Surface ...@@ -79,6 +83,9 @@ class Surface
// EGLenum textureTarget; // Type of texture: 2D or no texture // EGLenum textureTarget; // Type of texture: 2D or no texture
// EGLenum vgAlphaFormat; // Alpha format for OpenVG // EGLenum vgAlphaFormat; // Alpha format for OpenVG
// EGLenum vgColorSpace; // Color space for OpenVG // EGLenum vgColorSpace; // Color space for OpenVG
EGLint mSwapInterval;
DWORD mPresentInterval;
bool mPresentIntervalDirty;
}; };
} }
......
...@@ -746,7 +746,14 @@ EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval) ...@@ -746,7 +746,14 @@ EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval)
return EGL_FALSE; return EGL_FALSE;
} }
display->setSwapInterval(interval); egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
if (draw_surface == NULL)
{
return error(EGL_BAD_SURFACE, EGL_FALSE);
}
draw_surface->setSwapInterval(interval);
return success(EGL_TRUE); return success(EGL_TRUE);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment