// Link a shared DirectX texture to an OpenGL texture // and create a GLDX interop object handle // // IN pSharedTexture Pointer to shared the DirectX texture // IN dxShareHandle Handle of the DirectX texture to be shared // IN glTextureID ID of the OpenGL texture that is to be linked to the shared DirectX texture // Returns Handle to the GL/DirectX interop object (the shared texture) // HANDLE spoutGLDXinterop::LinkGLDXtextures ( void* pDXdevice, void* pSharedTexture, HANDLE dxShareHandle, GLuint glTexture) { HANDLE hInteropObject; // Prepare the DirectX device for interoperability with OpenGL // The return value is a handle to a GL/DirectX interop device. if(!m_hInteropDevice) m_hInteropDevice = wglDXOpenDeviceNV(pDXdevice); if (m_hInteropDevice == NULL) return false; // prepare shared resource // wglDXSetResourceShareHandle does not need to be called for DirectX // version 10 and 11 resources. Calling this function for DirectX 10 // and 11 resources is not an error but has no effect. if (!wglDXSetResourceShareHandleNV(pSharedTexture, dxShareHandle)) return NULL; // Prepare the DirectX texture for use by OpenGL // register for interop and associate the opengl texture with the dx texture hInteropObject = wglDXRegisterObjectNV( m_hInteropDevice, pSharedTexture, // DX texture glTexture, // OpenGL texture GL_TEXTURE_2D, // Must be TEXTURE_2D WGL_ACCESS_READ_WRITE_NV); // We will write and the receiver will read return hInteropObject; }
EXTERN_C_ENTER JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_WGLNVDXInterop_nwglDXSetResourceShareHandleNV(JNIEnv *__env, jclass clazz, jlong dxObjectAddress, jlong shareHandleAddress, jlong __functionAddress) { void *dxObject = (void *)(intptr_t)dxObjectAddress; HANDLE shareHandle = (HANDLE)(intptr_t)shareHandleAddress; wglDXSetResourceShareHandleNVPROC wglDXSetResourceShareHandleNV = (wglDXSetResourceShareHandleNVPROC)(intptr_t)__functionAddress; UNUSED_PARAMS(__env, clazz) return (jint)wglDXSetResourceShareHandleNV(dxObject, shareHandle); }
bool D3DPresentEngine::createSharedTexture(int w, int h, int textureID) { _w = w; _h = h; if (gl_handleD3D == NULL ) gl_handleD3D = wglDXOpenDeviceNV(m_pDevice); if (!gl_handleD3D) { printf("ofxWMFVideoplayer : openning the shared device failed\nCreate SharedTexture Failed"); return false; } gl_name=textureID; HANDLE sharedHandle = NULL; //We need to create a shared handle for the ressource, otherwise the extension fails on ATI/Intel cards HRESULT hr = m_pDevice->CreateTexture(w,h,1,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,&d3d_shared_texture,&sharedHandle); if (FAILED(hr)) { printf("ofxWMFVideoplayer : Error creating D3DTexture\n"); return false; } if (!sharedHandle) { printf("ofxWMFVideoplayer : Error creating D3D sahred handle\n"); return false; } wglDXSetResourceShareHandleNV(d3d_shared_texture,sharedHandle); d3d_shared_texture->GetSurfaceLevel(0,&d3d_shared_surface); gl_handle = wglDXRegisterObjectNV(gl_handleD3D, d3d_shared_texture, gl_name, GL_TEXTURE_RECTANGLE, WGL_ACCESS_READ_ONLY_NV); if (!gl_handle) { printf("ofxWMFVideoplayer : openning the shared texture failed\nCreate SharedTexture Failed"); return false; } return true; }
bool RenderManagerD3D11OpenGL::RegisterRenderBuffersInternal( const std::vector<RenderBuffer>& buffers, bool appWillNotOverwriteBeforeNewPresent) { // Make sure we're doing okay. if (!doingOkay()) { std::cerr << "RenderManagerD3D11OpenGL::RegisterRenderBuffers(): " "Display not opened." << std::endl; return false; } // Make sure we don't have more eyes than buffers. We can have fewer // because the client may have consolidated a number of eyes onto // one buffer. size_t numEyes = GetNumEyes(); if (buffers.size() > numEyes) { std::cerr << "RenderManagerD3D11OpenGL::RegisterRenderBuffers: " "Wrong number of buffers: " << buffers.size() << ", need " << numEyes << std::endl; return false; } // Delete any previously-registered buffers. for (size_t i = 0; i < m_oglToD3D.size(); i++) { wglDXUnregisterObjectNV(m_glD3DHandle, m_oglToD3D[i].glColorHandle); m_oglToD3D[i].D3DrenderTargetView->Release(); m_oglToD3D[i].D3DTexture->Release(); } m_oglToD3D.clear(); // Allocate D3D buffers to be used and tie them to the OpenGL buffers. for (size_t i = 0; i < buffers.size(); i++) { // If we have already mapped this buffer, we go ahead and skip it, // so that we don't tie the same OpenGL buffer to multiple D3D // buffers. It is not an error to map the same buffer twice. bool found = false; for (size_t j = 0; j < i; j++) { if (buffers[i].OpenGL->colorBufferName == buffers[j].OpenGL->colorBufferName) { found = true; } } if (found) { continue; } // Figure out how large the buffer should be by binding this texture // and querying the size of the 0th mipmap level. GLint width = 0, height = 0; glBindTexture(GL_TEXTURE_2D, buffers[i].OpenGL->colorBufferName); const GLint mipLevel = 0; glGetTexLevelParameteriv(GL_TEXTURE_2D, mipLevel, GL_TEXTURE_WIDTH, &width); glGetTexLevelParameteriv(GL_TEXTURE_2D, mipLevel, GL_TEXTURE_HEIGHT, &height); if ((width == 0) || (height == 0)) { std::cerr << "RenderManagerD3D11OpenGL::RegisterRenderBuffers: " "Zero-sized buffer for buffer: " << i << std::endl; return false; } // Initialize a new render target texture description. // Make it a shared texture so that we can use it with OpenGL // Interop. D3D11_TEXTURE2D_DESC textureDesc = {}; textureDesc.Width = width; textureDesc.Height = height; textureDesc.MipLevels = 1; textureDesc.ArraySize = 1; // textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; textureDesc.SampleDesc.Count = 1; textureDesc.SampleDesc.Quality = 0; textureDesc.Usage = D3D11_USAGE_DEFAULT; // We need it to be both a render target and a shader resource textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; textureDesc.CPUAccessFlags = 0; textureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; // Create a new render target texture to use. ID3D11Texture2D* D3DTexture = nullptr; HRESULT hr = m_D3D11Renderer->m_D3D11device->CreateTexture2D( &textureDesc, NULL, &D3DTexture); if (FAILED(hr)) { std::cerr << "RenderManagerD3D11OpenGL::RegisterRenderBuffers: " "Can't create texture" << std::endl; return false; } // Fill in the resource view for your render texture buffer here D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc = {}; // This must match what was created in the texture to be rendered // @todo Figure this out by introspection on the texture? // renderTargetViewDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; renderTargetViewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; renderTargetViewDesc.Texture2D.MipSlice = 0; // Create the render target view. ID3D11RenderTargetView* renderTargetView; //< Pointer to our render target view hr = m_D3D11Renderer->m_D3D11device->CreateRenderTargetView( D3DTexture, &renderTargetViewDesc, &renderTargetView); if (FAILED(hr)) { std::cerr << "RenderManagerD3D11OpenGL::RegisterRenderBuffers: " "Could not create render target" << std::endl; return false; } // Create a share handle for the texture, to enable it to be shared // between multiple devices. Then register the share handle with // interop. // https://msdn.microsoft.com/en-us/library/windows/desktop/ff476531(v=vs.85).aspx // https://www.opengl.org/registry/specs/NV/DX_interop.txt IDXGIResource* pOtherResource = nullptr; hr = D3DTexture->QueryInterface(__uuidof(IDXGIResource), (void**)&pOtherResource); HANDLE sharedHandle; hr = pOtherResource->GetSharedHandle(&sharedHandle); if (FAILED(hr)) { std::cerr << "RenderManagerD3D11OpenGL::RegisterRenderBuffers: " "Could not get shared handle" << std::endl; return false; } if (wglDXSetResourceShareHandleNV(D3DTexture, sharedHandle) != TRUE) { std::cerr << "RenderManagerD3D11OpenGL::RegisterRenderBuffers()" ": Could not share resource" << std::endl; return false; } // Prepare the things we need for wrapping Direct3D // objects. Information on how to do this comes from // the DX_interop2.txt file from opengl.org and from the // secondstory/ofDxSharedTextureExample project on Github. // Bind the OpenGL texture to the D3D texture for rendering HANDLE glColorHandle = wglDXRegisterObjectNV( m_glD3DHandle, D3DTexture, buffers[i].OpenGL->colorBufferName, GL_TEXTURE_2D, WGL_ACCESS_WRITE_DISCARD_NV); if (glColorHandle == nullptr) { std::cerr << "RenderManagerD3D11OpenGL::RegisterRenderBuffers: " "Can't get Color buffer handle" << " (error " << GetLastError() << ")"; switch (GetLastError()) { case ERROR_INVALID_HANDLE: std::cerr << " (Invalid handle)" << std::endl; break; case ERROR_INVALID_DATA: std::cerr << " (Invalid data)" << std::endl; break; case ERROR_OPEN_FAILED: std::cerr << " (Could not open Direct3D resource)" << std::endl; break; default: std::cerr << " (Unexpected error code)" << std::endl; } return false; } // New object to fill in OglToD3DTexture map; map.OpenGLTexture = buffers[i].OpenGL->colorBufferName; map.glColorHandle = glColorHandle; map.D3DTexture = D3DTexture; map.D3DrenderTargetView = renderTargetView; m_oglToD3D.push_back(map); // Lock the render target for OpenGL access if (!wglDXLockObjectsNV(m_glD3DHandle, 1, &map.glColorHandle)) { std::cerr << "RenderManagerD3D11OpenGL::RegisterRenderBuffers: " "Can't lock Color buffer" << std::endl; return false; } } // We're done -- call the base-class function to notify that we've // registered our buffers return RenderManager::RegisterRenderBuffersInternal(buffers, appWillNotOverwriteBeforeNewPresent); }