D3D11 render
OutputManager.h
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #ifndef _OUTPUTMANAGER_H_ #define _OUTPUTMANAGER_H_ #pragma comment(lib, "D3D11") #include <atlbase.h> #include <DirectXMath.h> #include <dxgi1_2.h> #include <dcomp.h> #include <wrl.h> #include <new> #include <windows.h> #include <assert.h> #include <wincodec.h> #include <d3d11_1.h> #define NUMVERTICES 6 #define BPP 4 #define OCCLUSION_STATUS_MSG WM_USER extern HRESULT SystemTransitionsExpectedErrors[]; extern HRESULT CreateDuplicationExpectedErrors[]; extern HRESULT FrameInfoExpectedErrors[]; extern HRESULT AcquireFrameExpectedError[]; extern HRESULT EnumOutputsExpectedErrors[]; typedef _Return_type_success_(return == DUPL_RETURN_SUCCESS) enum { DUPL_RETURN_SUCCESS = 0, DUPL_RETURN_ERROR_EXPECTED = 1, DUPL_RETURN_ERROR_UNEXPECTED = 2 }DUPL_RETURN; _Post_satisfies_(return != DUPL_RETURN_SUCCESS) DUPL_RETURN ProcessFailure(_In_opt_ ID3D11Device* Device, _In_ LPCWSTR Str, _In_ LPCWSTR Title, HRESULT hr, _In_opt_z_ HRESULT* ExpectedErrors = nullptr); void DisplayMsg(_In_ LPCWSTR Str, _In_ LPCWSTR Title, HRESULT hr); // // Handles the task of drawing into a window. // Has the functionality to draw the mouse given a mouse shape buffer and position // class OUTPUTMANAGER { public: OUTPUTMANAGER(); ~OUTPUTMANAGER(); DUPL_RETURN CreateAccessibleSurf(RECT* DeskBounds, DXGI_FORMAT Format); void CleanRefs(); HANDLE GetSharedHandle(); void WindowResize(); bool InitD3D11Video(HWND Window, int width, int height); bool PresentVideoFrame(int width, int height); // Vars ID3D11Device* m_Device; ID3D11Texture2D* m_SharedSurf; ID3D11Texture2D* m_AccessibleSurf; ID3D11DeviceContext* m_DeviceContext; IDXGISwapChain1* m_SwapChain; private: // Methods DUPL_RETURN CreateSharedSurf(RECT* DeskBounds); DUPL_RETURN ResizeSwapChain(); bool CreateVideoProcessor(int width, int height, bool reset); void RenderD3D11Texture(int width, int height); ID3D10Multithread* p_mt = nullptr; ID3D11VideoDevice* d3d11_video_device_ = nullptr; ID3D11VideoContext* d3d11_video_context_ = nullptr; CComPtr<ID3D11VideoProcessor> video_processor_; CComPtr<ID3D11VideoProcessorEnumerator> video_processor_enum_; // Vars IDXGIFactory2* m_Factory; HWND m_WindowHandle; bool m_NeedsResize; }; #endif
OutputManager.cpp
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include "OutputManager.h" #include <iostream> #include <array> #include <cstdio> using namespace DirectX; float red = 0.0f; // Below are lists of errors expect from Dxgi API calls when a transition event like mode change, PnpStop, PnpStart // desktop switch, TDR or session disconnect/reconnect. In all these cases we want the application to clean up the threads that process // the desktop updates and attempt to recreate them. // If we get an error that is not on the appropriate list then we exit the application // These are the errors we expect from general Dxgi API due to a transition HRESULT SystemTransitionsExpectedErrors[] = { DXGI_ERROR_DEVICE_REMOVED, DXGI_ERROR_ACCESS_LOST, static_cast<HRESULT>(WAIT_ABANDONED), S_OK // Terminate list with zero valued HRESULT }; // These are the errors we expect from IDXGIOutput1::DuplicateOutput due to a transition HRESULT CreateDuplicationExpectedErrors[] = { DXGI_ERROR_DEVICE_REMOVED, static_cast<HRESULT>(E_ACCESSDENIED), DXGI_ERROR_UNSUPPORTED, DXGI_ERROR_SESSION_DISCONNECTED, S_OK // Terminate list with zero valued HRESULT }; // These are the errors we expect from IDXGIOutputDuplication methods due to a transition HRESULT FrameInfoExpectedErrors[] = { DXGI_ERROR_DEVICE_REMOVED, DXGI_ERROR_ACCESS_LOST, S_OK // Terminate list with zero valued HRESULT }; // These are the errors we expect from IDXGIAdapter::EnumOutputs methods due to outputs becoming stale during a transition HRESULT EnumOutputsExpectedErrors[] = { DXGI_ERROR_NOT_FOUND, S_OK // Terminate list with zero valued HRESULT }; // // Constructor NULLs out all pointers & sets appropriate var vals // OUTPUTMANAGER::OUTPUTMANAGER() : m_SwapChain(nullptr), m_Device(nullptr), m_Factory(nullptr), m_DeviceContext(nullptr), m_SharedSurf(nullptr), m_WindowHandle(nullptr), m_NeedsResize(false) { } // // Destructor which calls CleanRefs to release all references and memory. // OUTPUTMANAGER::~OUTPUTMANAGER() { CleanRefs(); } // // Indicates that window has been resized. // void OUTPUTMANAGER::WindowResize() { m_NeedsResize = true; } DUPL_RETURN OUTPUTMANAGER::CreateAccessibleSurf(_In_ RECT* DeskBounds, _In_ DXGI_FORMAT Format) { D3D11_TEXTURE2D_DESC desc; desc.Width = DeskBounds->right - DeskBounds->left; desc.Height = DeskBounds->bottom - DeskBounds->top; desc.Format = Format; desc.ArraySize = 1; desc.BindFlags = 0; desc.MiscFlags = 0; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.MipLevels = 1; desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ; desc.Usage = D3D11_USAGE_STAGING; HRESULT hr = OUTPUTMANAGER::m_Device->CreateTexture2D(&desc, NULL, &m_AccessibleSurf); if (FAILED(hr)) { MessageBoxW(nullptr, L"Creating cpu accessable texture failed.", L"Error", MB_OK); return DUPL_RETURN_ERROR_UNEXPECTED; } if (m_AccessibleSurf == nullptr) { MessageBoxW(nullptr, L"Creating cpu accessable texture failed.", L"Error", MB_OK); return DUPL_RETURN_ERROR_UNEXPECTED; } return DUPL_RETURN_SUCCESS; } // // Recreate shared texture // DUPL_RETURN OUTPUTMANAGER::CreateSharedSurf(_In_ RECT* DeskBounds) { HRESULT hr; // Create shared texture for threads to draw into D3D11_TEXTURE2D_DESC DeskTexD; RtlZeroMemory(&DeskTexD, sizeof(D3D11_TEXTURE2D_DESC)); DeskTexD.Width = DeskBounds->right - DeskBounds->left; DeskTexD.Height = DeskBounds->bottom - DeskBounds->top; DeskTexD.MipLevels = 1; DeskTexD.ArraySize = 1; DeskTexD.Format = DXGI_FORMAT_B8G8R8A8_UNORM; DeskTexD.SampleDesc.Count = 1; DeskTexD.Usage = D3D11_USAGE_DEFAULT; DeskTexD.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; DeskTexD.CPUAccessFlags = 0; hr = m_Device->CreateTexture2D(&DeskTexD, nullptr, &m_SharedSurf); if (FAILED(hr)) { return ProcessFailure(m_Device, L"Failed to create shared texture", L"Error", hr, SystemTransitionsExpectedErrors); } return CreateAccessibleSurf(DeskBounds, DeskTexD.Format); } // // Returns shared handle // HANDLE OUTPUTMANAGER::GetSharedHandle() { HANDLE Hnd = nullptr; // QI IDXGIResource interface to synchronized shared surface. IDXGIResource* DXGIResource = nullptr; HRESULT hr = m_SharedSurf->QueryInterface(__uuidof(IDXGIResource), reinterpret_cast<void**>(&DXGIResource)); if (SUCCEEDED(hr)) { // Obtain handle to IDXGIResource object. DXGIResource->GetSharedHandle(&Hnd); DXGIResource->Release(); DXGIResource = nullptr; } return Hnd; } // // Resize swapchain // DUPL_RETURN OUTPUTMANAGER::ResizeSwapChain() { RECT WindowRect; GetClientRect(m_WindowHandle, &WindowRect); UINT Width = WindowRect.right - WindowRect.left; UINT Height = WindowRect.bottom - WindowRect.top; // Resize swapchain DXGI_SWAP_CHAIN_DESC SwapChainDesc; m_SwapChain->GetDesc(&SwapChainDesc); HRESULT hr = m_SwapChain->ResizeBuffers(SwapChainDesc.BufferCount, Width, Height, SwapChainDesc.BufferDesc.Format, SwapChainDesc.Flags); if (FAILED(hr)) { return ProcessFailure(m_Device, L"Failed to resize swapchain buffers in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors); } DUPL_RETURN Ret = DUPL_RETURN_SUCCESS; return Ret; } // // Releases all references // void OUTPUTMANAGER::CleanRefs() { if (m_DeviceContext) { m_DeviceContext->Release(); m_DeviceContext = nullptr; } if (m_Device) { m_Device->Release(); m_Device = nullptr; } if (m_SwapChain) { m_SwapChain->Release(); m_SwapChain = nullptr; } if (m_SharedSurf) { m_SharedSurf->Release(); m_SharedSurf = nullptr; } if (m_AccessibleSurf) { m_AccessibleSurf->Release(); m_AccessibleSurf = nullptr; } if (m_Factory) { m_Factory->Release(); m_Factory = nullptr; } } bool OUTPUTMANAGER::InitD3D11Video(HWND Window, int width, int height) { HRESULT hr = S_OK; UINT creation_flags = 0; m_WindowHandle = Window; D3D_FEATURE_LEVEL feature_levels_in[] = { D3D_FEATURE_LEVEL_9_1, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1 }; D3D_FEATURE_LEVEL feature_levels_out; hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, creation_flags, feature_levels_in, sizeof(feature_levels_in) / sizeof(D3D_FEATURE_LEVEL), D3D11_SDK_VERSION, &m_Device, &feature_levels_out, &m_DeviceContext); if (FAILED(hr)) { return false; } // Get video device if (!d3d11_video_device_) { hr = m_Device->QueryInterface(__uuidof(ID3D11VideoDevice), (void**)&d3d11_video_device_); if (FAILED(hr)) { return false; } } if (!d3d11_video_context_) { hr = m_DeviceContext->QueryInterface(__uuidof(ID3D11VideoContext), (void**)&d3d11_video_context_); if (FAILED(hr)) { return false; } } // SwapChain RECT WindowRect; GetClientRect(m_WindowHandle, &WindowRect); UINT window_width_ = WindowRect.right - WindowRect.left; UINT window_height_ = WindowRect.bottom - WindowRect.top; DXGI_SWAP_CHAIN_DESC1 desc; ZeroMemory(&desc, sizeof(DXGI_SWAP_CHAIN_DESC1)); desc.BufferCount = 2; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; desc.Height = window_height_; desc.Width = window_width_; desc.Scaling = DXGI_SCALING_STRETCH; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; desc.Stereo = false; desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; CComPtr<IDXGIDevice2> dxgi_device; hr = m_Device->QueryInterface(__uuidof(IDXGIDevice1), (void**)&dxgi_device); if (FAILED(hr)) { return false; } Microsoft::WRL::ComPtr<IDXGIAdapter> adapter = nullptr; Microsoft::WRL::ComPtr<IDXGIFactory2> factory = nullptr; hr = dxgi_device->GetAdapter(&adapter); if (FAILED(hr)) { return false; } hr = adapter->GetParent(IID_PPV_ARGS(&factory)); if (FAILED(hr)) { return false; } hr = factory->CreateSwapChainForHwnd(m_Device, m_WindowHandle, &desc, nullptr, nullptr, &m_SwapChain); if (FAILED(hr)) { std::string message = std::system_category().message(hr); return false; } // Create shared texture RECT video = { 0 }; video.right = width; video.bottom = height; DUPL_RETURN Return = CreateSharedSurf(&video); if (Return != DUPL_RETURN_SUCCESS) { return Return; } return true; } bool OUTPUTMANAGER::PresentVideoFrame(int width, int height) { if (!CreateVideoProcessor(width, height, false)) { return false; } RenderD3D11Texture(width, height); } bool OUTPUTMANAGER::CreateVideoProcessor(int width, int height, bool reset) { HRESULT hr = S_OK; if (width < 0 || height < 0) return false; D3D11_VIDEO_PROCESSOR_CONTENT_DESC content_desc; ZeroMemory(&content_desc, sizeof(content_desc)); if (video_processor_.p && video_processor_enum_.p) { hr = video_processor_enum_->GetVideoProcessorContentDesc(&content_desc); if (FAILED(hr)) return false; if (content_desc.InputWidth != (unsigned int)width || content_desc.InputHeight != (unsigned int)height || content_desc.OutputWidth != width || content_desc.OutputHeight != height || reset) { video_processor_enum_.Release(); video_processor_.Release(); } else { return true; } } ZeroMemory(&content_desc, sizeof(content_desc)); content_desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; content_desc.InputFrameRate.Numerator = 30; content_desc.InputFrameRate.Denominator = 1; content_desc.InputWidth = width; content_desc.InputHeight = height; content_desc.OutputWidth = width; content_desc.OutputHeight = height; content_desc.OutputFrameRate.Numerator = 30; content_desc.OutputFrameRate.Denominator = 1; content_desc.Usage = D3D11_VIDEO_USAGE_OPTIMAL_SPEED; hr = d3d11_video_device_->CreateVideoProcessorEnumerator(&content_desc, &video_processor_enum_); if (FAILED(hr)) return false; hr = d3d11_video_device_->CreateVideoProcessor(video_processor_enum_, 0, &video_processor_); if (FAILED(hr)) return false; return true; } void OUTPUTMANAGER::RenderD3D11Texture(int width, int height) { HRESULT hr = S_OK; if (m_SwapChain == nullptr) { return; } Microsoft::WRL::ComPtr<ID3D11Texture2D> dxgi_back_buffer; hr = m_SwapChain->GetBuffer(0, IID_PPV_ARGS(&dxgi_back_buffer)); if (FAILED(hr)) { std::string message = std::system_category().message(hr); return; } D3D11_TEXTURE2D_DESC back_buffer_desc; dxgi_back_buffer->GetDesc(&back_buffer_desc); D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC output_view_desc; ZeroMemory(&output_view_desc, sizeof(output_view_desc)); output_view_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D; output_view_desc.Texture2D.MipSlice = 0; Microsoft::WRL::ComPtr<ID3D11VideoProcessorOutputView> output_view; hr = d3d11_video_device_->CreateVideoProcessorOutputView( dxgi_back_buffer.Get(), video_processor_enum_, &output_view_desc, (ID3D11VideoProcessorOutputView**)&output_view); if (FAILED(hr)) { return; } D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC input_view_desc; ZeroMemory(&input_view_desc, sizeof(input_view_desc)); input_view_desc.FourCC = 0; input_view_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; input_view_desc.Texture2D.MipSlice = 0; input_view_desc.Texture2D.ArraySlice = 0; Microsoft::WRL::ComPtr<ID3D11VideoProcessorInputView> input_view; hr = d3d11_video_device_->CreateVideoProcessorInputView( m_SharedSurf, video_processor_enum_, &input_view_desc, (ID3D11VideoProcessorInputView**)&input_view); if (FAILED(hr)) { return; } D3D11_VIDEO_PROCESSOR_STREAM stream_data; ZeroMemory(&stream_data, sizeof(stream_data)); stream_data.Enable = TRUE; stream_data.OutputIndex = 0; stream_data.InputFrameOrField = 0; stream_data.PastFrames = 0; stream_data.FutureFrames = 0; stream_data.ppPastSurfaces = nullptr; stream_data.ppFutureSurfaces = nullptr; stream_data.pInputSurface = input_view.Get(); stream_data.ppPastSurfacesRight = nullptr; stream_data.ppFutureSurfacesRight = nullptr; stream_data.pInputSurfaceRight = nullptr; RECT rect = { 0 }; rect.right = width; rect.bottom = height; d3d11_video_context_->VideoProcessorSetStreamSourceRect(video_processor_, 0, true, &rect); D3D11_VIDEO_COLOR color; color.RGBA = { 0.f, 0.5f, 1.0f, 1.0f }; d3d11_video_context_->VideoProcessorSetOutputBackgroundColor(video_processor_, FALSE, &color); RECT WindowRect; GetClientRect(m_WindowHandle, &WindowRect); WindowRect.left += 10; WindowRect.top += 10; WindowRect.right -= 50; WindowRect.bottom -= 50; d3d11_video_context_->VideoProcessorSetStreamDestRect(video_processor_, 0, true, &WindowRect); d3d11_video_context_->VideoProcessorSetStreamFrameFormat( video_processor_, 0, D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE); hr = d3d11_video_context_->VideoProcessorBlt( video_processor_, output_view.Get(), 0, 1, &stream_data); if (FAILED(hr)) { return; } hr = m_SwapChain->Present(1, 0); if (FAILED(hr)) { return; } } _Post_satisfies_(return != DUPL_RETURN_SUCCESS) DUPL_RETURN ProcessFailure(_In_opt_ ID3D11Device* Device, _In_ LPCWSTR Str, _In_ LPCWSTR Title, HRESULT hr, _In_opt_z_ HRESULT* ExpectedErrors) { HRESULT TranslatedHr; // On an error check if the DX device is lost if (Device) { HRESULT DeviceRemovedReason = Device->GetDeviceRemovedReason(); switch (DeviceRemovedReason) { case DXGI_ERROR_DEVICE_REMOVED: case DXGI_ERROR_DEVICE_RESET: case static_cast<HRESULT>(E_OUTOFMEMORY) : { // Our device has been stopped due to an external event on the GPU so map them all to // device removed and continue processing the condition TranslatedHr = DXGI_ERROR_DEVICE_REMOVED; break; } case S_OK: { // Device is not removed so use original error TranslatedHr = hr; break; } default: { // Device is removed but not a error we want to remap TranslatedHr = DeviceRemovedReason; } } } else { TranslatedHr = hr; } // Check if this error was expected or not if (ExpectedErrors) { HRESULT* CurrentResult = ExpectedErrors; while (*CurrentResult != S_OK) { if (*(CurrentResult++) == TranslatedHr) { return DUPL_RETURN_ERROR_EXPECTED; } } } // Error was not expected so display the message box DisplayMsg(Str, Title, TranslatedHr); return DUPL_RETURN_ERROR_UNEXPECTED; } // // Displays a message // void DisplayMsg(_In_ LPCWSTR Str, _In_ LPCWSTR Title, HRESULT hr) { if (SUCCEEDED(hr)) { MessageBoxW(nullptr, Str, Title, MB_OK); return; } const UINT StringLen = (UINT)(wcslen(Str) + sizeof(" with HRESULT 0x########.")); wchar_t* OutStr = new wchar_t[StringLen]; if (!OutStr) { return; } INT LenWritten = swprintf_s(OutStr, StringLen, L"%s with 0x%X.", Str, hr); if (LenWritten != -1) { MessageBoxW(nullptr, OutStr, Title, MB_OK); } delete[] OutStr; }
D3D11RGBRendering.cpp
// D3D11RGBRendering.cpp : Defines the entry point for the application. // #include <stdio.h> #include "D3D11RGBRendering.h" #include "OutputManager.h" #define MAX_LOADSTRING 100 char buf[1024]; UINT pitch = 0, bmpHeight = 768, bmpWidth = 1366; enum RGB { RGB32, RGB24 }; RGB rgb = RGB32; //Change it accordingly // // Globals // OUTPUTMANAGER OutMgr; // Global Variables: HINSTANCE hInst; // current instance WCHAR szTitle[MAX_LOADSTRING]; // The title bar text WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name // Forward declarations of functions included in this code module: LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void WriteBitmap32ToTexture(BYTE *bitmap, RECT DeskBounds); void WriteBitmap24ToTexture(BYTE *bitmap, RECT DeskBounds); BYTE* ReadBitmapFromFile(); // // Program entry point // int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ INT nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); INT SingleOutput = -1; // Window HWND WindowHandle = nullptr; // Load simple cursor HCURSOR Cursor = nullptr; Cursor = LoadCursor(nullptr, IDC_ARROW); if (!Cursor) { ProcessFailure(nullptr, L"Cursor load failed", L"Error", E_UNEXPECTED); return 0; } // Register class WNDCLASSEXW Wc; Wc.cbSize = sizeof(WNDCLASSEXW); Wc.style = CS_HREDRAW | CS_VREDRAW; Wc.lpfnWndProc = WndProc; Wc.cbClsExtra = 0; Wc.cbWndExtra = 0; Wc.hInstance = hInstance; Wc.hIcon = nullptr; Wc.hCursor = Cursor; Wc.hbrBackground = nullptr; Wc.lpszMenuName = nullptr; Wc.lpszClassName = L"ddasample"; Wc.hIconSm = nullptr; if (!RegisterClassExW(&Wc)) { ProcessFailure(nullptr, L"Window class registration failed", L"Error", E_UNEXPECTED); return 0; } // Create window RECT WindowRect = { 0, 0, 1400, 800 }; AdjustWindowRect(&WindowRect, WS_OVERLAPPEDWINDOW, FALSE); WindowHandle = CreateWindowW(L"ddasample", L"DXGI desktop duplication sample", WS_OVERLAPPEDWINDOW, 0, 0, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, nullptr, nullptr, hInstance, nullptr); if (!WindowHandle) { ProcessFailure(nullptr, L"Window creation failed", L"Error", E_FAIL); return 0; } DestroyCursor(Cursor); ShowWindow(WindowHandle, nCmdShow); UpdateWindow(WindowHandle); RECT DeskBounds; UINT OutputCount; // Message loop (attempts to update screen when no other messages to process) MSG msg = { 0 }; bool FirstTime = true; bool Occluded = true; while (WM_QUIT != msg.message) { DUPL_RETURN Ret = DUPL_RETURN_SUCCESS; if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { if (msg.message == OCCLUSION_STATUS_MSG) { // Present may not be occluded now so try again Occluded = false; } else { // Process window messages TranslateMessage(&msg); DispatchMessage(&msg); } } else if (FirstTime) { // First time through the loop so nothing to clean up FirstTime = false; BYTE* bitmap = ReadBitmapFromFile(); OutMgr.InitD3D11Video(WindowHandle, bmpWidth, bmpHeight); // We start off in occluded state and we should immediate get a occlusion status window message Occluded = false; } else { // Nothing else to do, so try to present to write out to window if not occluded if (!Occluded) { BYTE *bitmap = ReadBitmapFromFile(); DeskBounds = { 0, 0, (LONG)bmpWidth, (LONG)bmpHeight }; (rgb == RGB32) ? WriteBitmap32ToTexture(bitmap, DeskBounds) : WriteBitmap24ToTexture(bitmap, DeskBounds); free(bitmap); //Ret = OutMgr.UpdateApplicationWindow(&Occluded); OutMgr.PresentVideoFrame(bmpWidth, bmpHeight); //d3d11->DrawFrame(bitmap); //free(bitmap); } } } if (msg.message == WM_QUIT) { OutMgr.CleanRefs(); // For a WM_QUIT message we should return the wParam value return static_cast<INT>(msg.wParam); } return 0; } BYTE* ReadBitmapFromFile() { FILE *file = nullptr; sprintf_s(buf, (rgb == RGB32) ? "input\\rgb32.bmp" : "input\\rgb24.bmp"); fopen_s(&file, buf, "rb"); BITMAPFILEHEADER *bITMAPFILEHEADER = (BITMAPFILEHEADER*)malloc(sizeof(BITMAPFILEHEADER)); BITMAPINFOHEADER *bITMAPINFOHEADER = (BITMAPINFOHEADER*)malloc(sizeof(BITMAPINFOHEADER)); int readBytes = fread(bITMAPFILEHEADER, sizeof(BITMAPFILEHEADER), 1, file); readBytes = fread(bITMAPINFOHEADER, sizeof(BITMAPINFOHEADER), 1, file); size_t bitmapSize = bITMAPFILEHEADER->bfSize - sizeof(BITMAPFILEHEADER) - sizeof(BITMAPINFOHEADER); BYTE *bitmap = (BYTE*)malloc(bitmapSize); pitch = bitmapSize / bITMAPINFOHEADER->biHeight; bmpHeight = bITMAPINFOHEADER->biHeight; bmpWidth = bITMAPINFOHEADER->biWidth; readBytes = fread(bitmap, bitmapSize, 1, file); //memset(bitmap, 128, bitmapSize); fclose(file); return bitmap; } void WriteBitmap32ToTexture(BYTE *bitmap, RECT DeskBounds) { // Copy image into CPU access texture OutMgr.m_DeviceContext->CopyResource(OutMgr.m_AccessibleSurf, OutMgr.m_SharedSurf); // Copy from CPU access texture to bitmap buffer D3D11_MAPPED_SUBRESOURCE resource; UINT subresource = D3D11CalcSubresource(0, 0, 0); OutMgr.m_DeviceContext->Map(OutMgr.m_AccessibleSurf, subresource, D3D11_MAP_WRITE, 0, &resource); UINT dist = 0, height = DeskBounds.bottom - DeskBounds.top, sdist = 0; BYTE* dptr = reinterpret_cast<BYTE*>(resource.pData); dptr += resource.RowPitch*(height - 1); int minPitch = min(pitch, resource.RowPitch); //memcpy_s(dptr, resource.RowPitch*height, bitmap, resource.RowPitch*height); for (size_t h = 0; h < height; ++h) { dist = resource.RowPitch *h; sdist = pitch * h; memcpy_s(dptr - dist, resource.RowPitch, bitmap + sdist, minPitch); } OutMgr.m_DeviceContext->Unmap(OutMgr.m_AccessibleSurf, subresource); OutMgr.m_DeviceContext->CopyResource(OutMgr.m_SharedSurf, OutMgr.m_AccessibleSurf); } void WriteBitmap24ToTexture(BYTE *bitmap, RECT DeskBounds) { // Copy image into CPU access texture OutMgr.m_DeviceContext->CopyResource(OutMgr.m_AccessibleSurf, OutMgr.m_SharedSurf); // Copy from CPU access texture to bitmap buffer D3D11_MAPPED_SUBRESOURCE resource; UINT subresource = D3D11CalcSubresource(0, 0, 0); OutMgr.m_DeviceContext->Map(OutMgr.m_AccessibleSurf, subresource, D3D11_MAP_WRITE, 0, &resource); int dist = 0, height = DeskBounds.bottom - DeskBounds.top, sdist = 0; BYTE* dptr = reinterpret_cast<BYTE*>(resource.pData); dptr += resource.RowPitch*(height - 1); for (size_t h = 0; h < bmpHeight; ++h) { dist = resource.RowPitch *h; sdist = pitch * h; for (size_t w = 0; w < bmpWidth; w++) { dptr[-dist + w * 4] = bitmap[sdist + w * 3]; dptr[-dist + w * 4 + 1] = bitmap[sdist + w * 3 + 1]; dptr[-dist + w * 4 + 2] = bitmap[sdist + w * 3 + 2]; } } OutMgr.m_DeviceContext->Unmap(OutMgr.m_AccessibleSurf, subresource); OutMgr.m_DeviceContext->CopyResource(OutMgr.m_SharedSurf, OutMgr.m_AccessibleSurf); } // // Window message processor // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: { PostQuitMessage(0); break; } case WM_SIZE: { // Tell output manager that window size has changed OutMgr.WindowResize(); break; } default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
本文作者:GreyWang
本文链接:https://www.cnblogs.com/GreyWang/p/17184754.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
Windows
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步