#include #include #pragma comment (lib, "d3d11") #include "msangle.hpp" using namespace msangle; int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { if (!_msangle_loaded) return -1; int width = 800; int height = 600; // setup wndclass WNDCLASSEXW wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wcex.lpfnWndProc = [](HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT CALLBACK { switch (message) { case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(0)); wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = 0; wcex.lpszClassName = L"ANGLE_WINDOW"; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(0)); if (!RegisterClassExW(&wcex)) return FALSE; // setup window HWND hWnd = CreateWindowW(wcex.lpszClassName, L"msangletest", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, width, height, nullptr, nullptr, hInstance, nullptr); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // setup d3d11 D3D_FEATURE_LEVEL feature_levels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0 }; D3D_FEATURE_LEVEL* ftret = 0; ID3D11Device* dx_device; ID3D11DeviceContext* dx_ctx; D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, D3D11_CREATE_DEVICE_BGRA_SUPPORT, feature_levels, ARRAYSIZE(feature_levels), D3D11_SDK_VERSION, &dx_device, ftret, &dx_ctx); IDXGIDevice* dxgi_device = nullptr; dx_device->QueryInterface(IID_PPV_ARGS(&dxgi_device)); IDXGIAdapter* dxgi_adapter = nullptr; dxgi_device->GetParent(IID_PPV_ARGS(&dxgi_adapter)); dxgi_device->Release(); IDXGIFactory* dxgi_factory = nullptr; dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory)); dxgi_adapter->Release(); // setup d3d11 swapchain DXGI_SWAP_CHAIN_DESC swapchain_desc{}; swapchain_desc.BufferCount = 2; // note, when using >1 buffers you must save and restore RTV/DSV on present swapchain_desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; swapchain_desc.BufferDesc.Width = width; swapchain_desc.BufferDesc.Height = height; swapchain_desc.BufferDesc.RefreshRate.Numerator = 0; swapchain_desc.BufferDesc.RefreshRate.Denominator = 0; swapchain_desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; swapchain_desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapchain_desc.Flags = NULL; swapchain_desc.OutputWindow = hWnd; swapchain_desc.SampleDesc.Count = 1; swapchain_desc.SampleDesc.Quality = 0; swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapchain_desc.Windowed = true; IDXGISwapChain* dx_swapchain; dxgi_factory->CreateSwapChain(dx_device, &swapchain_desc, &dx_swapchain); dxgi_factory->Release(); // get swapchain surface as texture to render with angle (pbuffer) ID3D11Texture2D* dxgi_surface = nullptr; dx_swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&dxgi_surface); // setup angle auto egl_device = eglCreateDeviceANGLE(EGL_D3D11_DEVICE_ANGLE, dx_device, NULL); auto egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, egl_device, NULL); if (!eglInitialize(egl_display, NULL, NULL)) return FALSE; if (!eglBindAPI(EGL_OPENGL_ES_API)) return FALSE; EGLint attributes[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 1, EGL_SAMPLE_BUFFERS, 0, EGL_SAMPLES, 0, //CANNOT MSAA ON PBUFFER EGL_NONE }; // setup egl config EGLConfig egl_config = NULL; EGLint num_configs = 0; if (!eglChooseConfig(egl_display, attributes, &egl_config, 1, &num_configs)) return false; // setup egl context EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_TRUE, EGL_NONE }; auto egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, attrs); // setup pbuffer from d3d11 texture (the swapchain backbuffer) EGLint pbuffer_attributes[] = { EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, EGL_NONE, }; auto egl_backbuffer = eglCreatePbufferFromClientBuffer(egl_display, EGL_D3D_TEXTURE_ANGLE, dxgi_surface, egl_config, pbuffer_attributes); if (!egl_backbuffer) { return false; } // set pbuffer as current eglMakeCurrent(egl_display, egl_backbuffer, egl_backbuffer, egl_context); const GLubyte* ext = glGetString(GL_EXTENSIONS); printf("%s", ext); const char* vs = "attribute vec2 pos; void main() { gl_Position = vec4(pos, 0, 1); }"; GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex_shader, 1, &vs, nullptr); glCompileShader(vertex_shader); // fragment shader draws in red const char* fs = "void main() { gl_FragColor = vec4(1, 1, 1, 1); }"; GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment_shader, 1, &fs, nullptr); glCompileShader(fragment_shader); // combine fragment and vertex shader GLuint program = glCreateProgram(); glAttachShader(program, vertex_shader); glAttachShader(program, fragment_shader); glLinkProgram(program); glUseProgram(program); static float vertices[] = { 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f }; MSG msg; bool quit = false; // message loop while (!quit) { // dispatch events while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) quit = true; TranslateMessage(&msg); DispatchMessage(&msg); } // draw with GL { glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, width, height); vertices[2] += 0.005f; if (vertices[2] > 1.0f) vertices[2] = -0.5f; glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)vertices); glEnableVertexAttribArray(0); glDrawArrays(GL_TRIANGLES, 0, 3); } // present (vsync) (RTV/DSV saved and restored only when texture has several buffers) { ID3D11RenderTargetView* rtvs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { 0 }; ID3D11DepthStencilView* dsv = NULL; dx_ctx->OMGetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, rtvs, &dsv); dx_swapchain->Present(1, 0); // Present releases rendertargets. reattach them for next frame dx_ctx->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, rtvs, dsv); for (int i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) if (rtvs[i]) rtvs[i]->Release(); else break; if (dsv) dsv->Release(); } } // dispose eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(egl_display, egl_backbuffer); eglTerminate(egl_display); eglReleaseDeviceANGLE(egl_device); dx_ctx->Flush(); dxgi_surface->Release(); dx_device->Release(); dx_ctx->Release(); dx_swapchain->Release(); return 0; }