1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-05-31 11:15:31 +03:00
occt/src/D3DHost/D3DHost_FrameBuffer.cxx
Pasukhin Dmitry 1f386af59f
Coding - Update method guards for consistency #333
Apply new regex replacement with method's guards in .cxx
Update GH workflow with style checking
2025-02-03 11:16:00 +00:00

452 lines
16 KiB
C++

// Created on: 2015-06-10
// Created by: Kirill Gavrilov
// Copyright (c) 2015 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <d3d9.h>
#include <D3DHost_FrameBuffer.hxx>
#include <OpenGl_GlCore20.hxx>
#include <OpenGl_ArbFBO.hxx>
#include <OpenGl_Context.hxx>
#include <OpenGl_Texture.hxx>
#include <Standard_ProgramError.hxx>
IMPLEMENT_STANDARD_RTTIEXT(D3DHost_FrameBuffer, OpenGl_FrameBuffer)
//=================================================================================================
D3DHost_FrameBuffer::D3DHost_FrameBuffer()
: myD3dSurf(NULL),
myD3dSurfShare(NULL),
myGlD3dDevice(NULL),
myGlD3dSurf(NULL),
myLockCount(0),
myD3dFallback(Standard_False),
myIsSRGBReady(Standard_False)
{
//
}
//=================================================================================================
D3DHost_FrameBuffer::~D3DHost_FrameBuffer()
{
Release(NULL);
}
//=================================================================================================
void D3DHost_FrameBuffer::Release(OpenGl_Context* theCtx)
{
if (myGlD3dDevice != NULL)
{
const OpenGl_GlFunctions* aFuncs =
(theCtx != NULL && theCtx->IsValid()) ? theCtx->Functions() : NULL;
if (myGlD3dSurf != NULL)
{
if (aFuncs != NULL)
{
aFuncs->wglDXUnregisterObjectNV(myGlD3dDevice, myGlD3dSurf);
}
myGlD3dSurf = NULL;
}
if (aFuncs != NULL)
{
aFuncs->wglDXCloseDeviceNV(myGlD3dDevice);
}
myGlD3dDevice = NULL;
}
if (myD3dSurf != NULL)
{
myD3dSurf->Release();
myD3dSurf = NULL;
myD3dSurfShare = NULL;
}
OpenGl_FrameBuffer::Release(theCtx);
}
//=================================================================================================
Standard_Boolean D3DHost_FrameBuffer::Init(const Handle(OpenGl_Context)& theCtx,
IDirect3DDevice9* theD3DDevice,
const Standard_Boolean theIsD3dEx,
const Standard_Integer theSizeX,
const Standard_Integer theSizeY)
{
if (InitD3dInterop(theCtx, theD3DDevice, theIsD3dEx, theSizeX, theSizeY, GL_DEPTH24_STENCIL8))
{
return Standard_True;
}
return InitD3dFallback(theCtx, theD3DDevice, theIsD3dEx, theSizeX, theSizeY, GL_DEPTH24_STENCIL8);
}
//=================================================================================================
Standard_Boolean D3DHost_FrameBuffer::InitD3dFallback(const Handle(OpenGl_Context)& theCtx,
IDirect3DDevice9* theD3DDevice,
const Standard_Boolean theIsD3dEx,
const Standard_Integer theSizeX,
const Standard_Integer theSizeY,
const Standard_Integer theDepthFormat)
{
const Standard_Boolean isGlInit = OpenGl_FrameBuffer::Init(theCtx,
Graphic3d_Vec2i(theSizeX, theSizeY),
GL_RGBA8,
theDepthFormat,
0);
myD3dFallback = Standard_True;
const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
if (theD3DDevice->CreateRenderTarget(aSizeX,
aSizeY,
D3DFMT_X8R8G8B8,
D3DMULTISAMPLE_NONE,
0,
theIsD3dEx ? TRUE : FALSE,
&myD3dSurf,
theIsD3dEx ? &myD3dSurfShare : NULL)
!= D3D_OK)
{
Release(theCtx.operator->());
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
TCollection_AsciiString(
"D3DHost_FrameBuffer, could not create D3DFMT_X8R8G8B8 render target ")
+ aSizeX + "x" + aSizeY);
return Standard_False;
}
return isGlInit;
}
//=================================================================================================
Standard_Boolean D3DHost_FrameBuffer::InitD3dInterop(const Handle(OpenGl_Context)& theCtx,
IDirect3DDevice9* theD3DDevice,
const Standard_Boolean theIsD3dEx,
const Standard_Integer theSizeX,
const Standard_Integer theSizeY,
const Standard_Integer theDepthFormat)
{
Release(theCtx.operator->());
myDepthFormat = theDepthFormat;
myVPSizeX = theSizeX;
myVPSizeY = theSizeY;
myInitVPSizeX = theSizeX;
myInitVPSizeY = theSizeY;
const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
if (aFuncs->wglDXOpenDeviceNV == NULL)
{
Release(theCtx.operator->());
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer, WGL_NV_DX_interop is unavailable!");
return Standard_False;
}
// Render target surface should be lockable on
// Windows XP and non-lockable on Windows Vista or higher
if (theD3DDevice->CreateRenderTarget(aSizeX,
aSizeY,
D3DFMT_X8R8G8B8,
D3DMULTISAMPLE_NONE,
0,
theIsD3dEx ? TRUE : FALSE,
&myD3dSurf,
theIsD3dEx ? &myD3dSurfShare : NULL)
!= D3D_OK)
{
Release(theCtx.operator->());
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
TCollection_AsciiString(
"D3DHost_FrameBuffer, could not create D3DFMT_X8R8G8B8 render target ")
+ aSizeX + "x" + aSizeY);
return Standard_False;
}
myGlD3dDevice = aFuncs->wglDXOpenDeviceNV(theD3DDevice);
if (myGlD3dDevice == NULL)
{
Release(theCtx.operator->());
theCtx->PushMessage(
GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer, could not create the GL <-> DirectX Interop using wglDXOpenDeviceNV()");
return Standard_False;
}
if (!registerD3dBuffer(theCtx))
{
Release(theCtx.operator->());
return Standard_False;
}
myIsOwnBuffer = true;
myIsOwnDepth = true;
theCtx->arbFBO->glGenFramebuffers(1, &myGlFBufferId);
const OpenGl_TextureFormat aDepthFormat =
OpenGl_TextureFormat::FindSizedFormat(theCtx, myDepthFormat);
if (aDepthFormat.IsValid()
&& !myDepthStencilTexture->Init(theCtx,
aDepthFormat,
Graphic3d_Vec2i(aSizeX, aSizeY),
Graphic3d_TypeOfTexture_2D))
{
Release(theCtx.get());
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
TCollection_AsciiString(
"D3DHost_FrameBuffer, could not initialize GL_DEPTH24_STENCIL8 texture ")
+ aSizeX + "x" + aSizeY);
return Standard_False;
}
myD3dFallback = Standard_False;
return Standard_True;
}
//=================================================================================================
Standard_Boolean D3DHost_FrameBuffer::registerD3dBuffer(const Handle(OpenGl_Context)& theCtx)
{
const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
if (myGlD3dSurf != NULL)
{
if (!aFuncs->wglDXUnregisterObjectNV(myGlD3dDevice, myGlD3dSurf))
{
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer, can not unregister color buffer");
return Standard_False;
}
myGlD3dSurf = NULL;
}
if (!aFuncs->wglDXSetResourceShareHandleNV(myD3dSurf, myD3dSurfShare))
{
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer, wglDXSetResourceShareHandleNV() has failed");
return Standard_False;
}
myIsOwnColor = true;
myColorTextures(0)->Release(theCtx.operator->());
myColorTextures(0)->Create(theCtx);
myGlD3dSurf = aFuncs->wglDXRegisterObjectNV(myGlD3dDevice,
myD3dSurf,
myColorTextures(0)->TextureId(),
GL_TEXTURE_2D,
WGL_ACCESS_WRITE_DISCARD_NV);
theCtx->ResetErrors(true);
if (myGlD3dSurf == NULL)
{
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer, can not register color buffer");
return Standard_False;
}
return Standard_True;
}
//=================================================================================================
void D3DHost_FrameBuffer::BindBuffer(const Handle(OpenGl_Context)& theCtx)
{
Standard_ProgramError_Raise_if(
myLockCount < 1,
"D3DHost_FrameBuffer::BindBuffer(), resource should be locked beforehand!");
if (theCtx->arbFBO == NULL)
{
return;
}
OpenGl_FrameBuffer::BindBuffer(theCtx);
theCtx->SetFrameBufferSRGB(true, myIsSRGBReady);
if (myD3dFallback)
{
return;
}
theCtx->arbFBO->glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
myColorTextures(0)->GetTarget(),
myColorTextures(0)->TextureId(),
0);
const OpenGl_TextureFormat aDepthFormat =
OpenGl_TextureFormat::FindSizedFormat(theCtx, myDepthFormat);
if (myDepthStencilTexture->IsValid())
{
theCtx->arbFBO->glFramebufferTexture2D(GL_FRAMEBUFFER,
aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL
? GL_DEPTH_STENCIL_ATTACHMENT
: GL_DEPTH_ATTACHMENT,
myDepthStencilTexture->GetTarget(),
myDepthStencilTexture->TextureId(),
0);
}
if (theCtx->arbFBO->glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
if (myDepthStencilTexture->IsValid())
{
theCtx->arbFBO->glFramebufferTexture2D(GL_FRAMEBUFFER,
aDepthFormat.PixelFormat() == GL_DEPTH_STENCIL
? GL_DEPTH_STENCIL_ATTACHMENT
: GL_DEPTH_ATTACHMENT,
myDepthStencilTexture->GetTarget(),
0,
0);
}
if (theCtx->arbFBO->glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer, OpenGL FBO is incomplete!");
Release(theCtx.operator->());
}
else
{
myDepthFormat = 0;
myDepthStencilTexture->Release(theCtx.get());
theCtx->PushMessage(
GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_PORTABILITY,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer, OpenGL FBO is created without Depth+Stencil attachments!");
}
}
}
//=================================================================================================
void D3DHost_FrameBuffer::LockSurface(const Handle(OpenGl_Context)& theCtx)
{
if (++myLockCount > 1)
{
return;
}
if (myGlD3dSurf == NULL)
{
return;
}
const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
if (!aFuncs->wglDXLockObjectsNV(myGlD3dDevice, 1, &myGlD3dSurf))
{
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer::LockSurface(), lock failed!");
}
}
//=================================================================================================
void D3DHost_FrameBuffer::UnlockSurface(const Handle(OpenGl_Context)& theCtx)
{
if (--myLockCount != 0)
{
return;
}
if (myD3dFallback)
{
if (myD3dSurf == NULL)
{
return;
}
D3DLOCKED_RECT aLockedRect;
if (myD3dSurf->LockRect(&aLockedRect, NULL, 0) != 0)
{
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer::UnlockSurface(), lock failed!");
return;
}
Image_PixMap anImg;
if (anImg.InitWrapper(Image_Format_BGRA,
(Standard_Byte*)aLockedRect.pBits,
myInitVPSizeX,
myInitVPSizeY,
aLockedRect.Pitch))
{
anImg.SetTopDown(!IsValid()); // flip in software if OpenGL FBO is unavailable
myLockCount = 1;
if (!BufferDump(theCtx, this, anImg, Graphic3d_BT_RGBA))
{
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer::UnlockSurface(), buffer dump failed!");
}
myLockCount = 0;
}
else
{
theCtx->PushMessage(GL_DEBUG_SOURCE_APPLICATION,
GL_DEBUG_TYPE_ERROR,
0,
GL_DEBUG_SEVERITY_HIGH,
"D3DHost_FrameBuffer::UnlockSurface(), buffer dump failed!");
}
myD3dSurf->UnlockRect();
return;
}
if (myGlD3dSurf == NULL)
{
return;
}
const OpenGl_GlFunctions* aFuncs = theCtx->Functions();
aFuncs->wglDXUnlockObjectsNV(myGlD3dDevice, 1, &myGlD3dSurf);
}