Raspberrypi 4でOpenGLES(ウィンドウの表示)

開発環境

環境構築

ライブラリのインストール

sudo apt install libgles2-mesa-dev libegl1-mesa-dev xorg-dev

ソースコード

main.cpp

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <iostream>
#include <unistd.h>

bool InitEGL(Display* xDisplay, Window& xWin, EGLDisplay& display, EGLContext &context, EGLSurface& surface) {
    display = eglGetDisplay(static_cast<EGLNativeDisplayType>(xDisplay));
    if (display == EGL_NO_DISPLAY) {
        std::cout << "Failed to get Display" << std::endl;
        return false;
    }

    if (!eglInitialize(display, nullptr, nullptr)) {
        std::cout << "Failed to init EGL" << std::endl;
        return false;
    }

    EGLint attr[] = {EGL_BUFFER_SIZE, 16, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE};
    EGLConfig config = nullptr;
    EGLint numConfigs = 0;
    if (!eglChooseConfig(display, attr, &config, 1, &numConfigs)) {
        std::cout << "Failed to choose Config" << std::endl;
        return false;
    }

    if (numConfigs != 1) {
        std::cout << "Error numConfigs" << std::endl;
        return false;
    }

    surface = eglCreateWindowSurface(display, config, xWin, nullptr);
    if (surface == EGL_NO_SURFACE) {
        std::cout << "Failed to create WindowSurface" << std::endl;
        return false;
    }

    EGLint ctxattr[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
    context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctxattr);
    if (context == EGL_NO_CONTEXT) {
        std::cout << "Failed to create context" << std::endl;
        return false;
    }

    eglMakeCurrent(display, surface, surface, context);

    return true;
}

void MainLoop(Display* xDisplay, EGLDisplay display, EGLSurface surface) {
    while (true) {
        XPending(xDisplay);
        glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        eglSwapBuffers(display, surface);

    }
}

int main(int argc, char*argv[]) {
    Display* xDisplay = XOpenDisplay(nullptr);
    if (xDisplay == nullptr) {
        std::cout << "Failed to open display" << std::endl;
        return -1;
    }

    Window xWindow = XCreateSimpleWindow(xDisplay, DefaultRootWindow(xDisplay), 100, 100, 640, 480, 1, BlackPixel(xDisplay, 0), WhitePixel(xDisplay, 0));

    XMapWindow(xDisplay, xWindow);

    EGLDisplay display = nullptr;
    EGLContext context = nullptr;
    EGLSurface surface = nullptr;

    if (!InitEGL(xDisplay, xWindow, display, context, surface)) {
        return -1;
    }

    MainLoop(xDisplay, display, surface);


    eglDestroyContext(display, context);
    eglDestroySurface(display, surface);
    eglTerminate(display);

    XDestroyWindow(xDisplay, xWindow);
    XCloseDisplay(xDisplay);
    
    return 0;
}

Makefile

CC      = g++
CFLAGS  = -Wall -Weffc++
TARGET = program

OBJS    = $(SRCS:.cpp=.o)

INCDIR =
LIBS =  -L/usr/lib -lX11 -lEGL -lGL

SRCS = main.cpp

$(TARGET): $(OBJS)
    $(CC) -o $(TARGET) $(OBJS) $(LIBS)

$(OBJS): $(SRCS)
    $(CC) $(CFLAGS) $(INCDIR) -c $(SRCS)

all:
    clean $(OBJS) $(TARGET)

clean: $(TARGET)
    rm $(OBJS)

参考資料

www.mztn.org

qiita.com

WSLでOpenGL

環境構築

WSLのインストール

コマンドプロンプトを管理者として実行しする. 下のコマンドを実行し,Ubuntuをインストール.(ディストリビューションUbuntuにしとく)

wsl --install -d Ubuntu

インストールが終わったら,ユーザ名とパスワードを求められるので,適当に入力. 以下のコマンドを入力して,いろいろインストール.

sudo apt update
sudo apt upgrade
sudo apt install gnome-text-editor -y
sudo apt intall g++

Xmingのインストール

ダウンロードページのDownloadからダウンロード.ダウンロードが終わったら,ファイルを実行する.全てデフォルトでインストール.
インストールが終わったらXLaunchというアプリが追加されているので実行.基本デフォルトで進めてよいが,Extra settingのDisable access controlにチェックを入れる.
wslのシェルで以下のコマンドを実行.

sudo apt-get install x11-apps
echo "export DISPLAY=localhost:0.0" >> ~/.bashrc
exec bash

ライブラリのインストール

sudo apt-get install freeglut3 freeglut3-dev

サンプルプログラム

#include <GL/glut.h>
 
void display(void) { }
 
int main(int argc, char *argv[])
{
  glutInit(&argc, argv);
  glutCreateWindow(argv[0]);
  glutDisplayFunc(display);
  glutMainLoop();
  return 0;
}

コンパイル,実行

g++ -Wall -Weffc++ -o glut_main main.cpp -lglut -lGLU -lGL
./glut_main

参考資料

rin-ka.net

www.webcyou.com

learn.microsoft.com

npmを使用したweb開発環境構築(for Windows)

はじめに

Three.jsを使用した開発をするため,web開発環境の構築を行う.
web開発初心者なので,できるだけ簡単な方法でやりたい.

環境

Windows10 Home

開発環境構築

Node.jsのインストール

公式サイトからNode.jsをダウンロード.推奨版でいいと思われる. nodejs.org
ダウンロードが終わったら実行.実行したら下の画面が表示されるのでNextをクリック.


その後もNextを押して進めていく.下の画面が表示されたら,チェックを外してNextを押し,インストールを進めていく.

インストールが終わったらPCを再起動する.再起動が終わったら,コマンドプロンプトを起動し,以下のコマンドを実行.

node

以下の文字列が表示されたら成功.vの後の数字は自分が入れたバージョンになる.

Welcome to Node.js v18.16.0.

npmコマンドの使い方

www.webdesignleaves.com

www.tohoho-web.com

プロジェクトフォルダの初期化

コマンドプロンプトでプロジェクトのディレクトリに移動し,

npm init

を実行.すると,色々聞かれるのでEnterを押して進める.

his utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (project2)
version: (1.0.0)
description:
entry point: (main.js)
test command:
git repository:
keywords:
author:
license: (ISC)

最後に

Is this OK? (yes)

と聞かれるので,yesと入力し,Enter. package.jsonが生成される.

また,

npm init -y

とすることで,質問をすべてスキップすることができる.

qiita.com

webpackのインストール

webpackとwebpackをCLIから利用するためのツールをインストール.

npm install --save-dev webpack webpack-cli

プロジェクトのディレクトリで以下のコマンドを実行し,srcフォルダを作成し,その中にindex.jsというファイルを作成する.このindex.jsにコードを記述する.

mkdir src
cd ./src
type nul > index.js

プロジェクトフォルダに戻り,バンドルを実行.

cd ../
npx webpack --watch

成功すると,プロジェクトフォルダにdistというフォルダが作成され,その中にmain.jsが作成される.

htmlでjavascriptソースコードを呼び出す

distディレクトリの中にindex.htmlを作成し,以下を記述.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8"/>
        <title>title</title>
        <script src="./main.js"></script>
    </head>
    <body>
        
    </body>
</html>

htmlのプレビュー

visual studio code拡張機能で,Live Serverと検索し,インストール.
index.htmlを右クリックし,Open with Live Serverを選択すると,ブラウザの画面が表示され,実行結果を表示することができる.

おまけ(本題)

Three.jsのインストール

今回は,npmを使用したThree.jsのインストールを行う. プロジェクトフォルダの初期化が終わった後,

npm install three --save

これで,カレントディレクトリにnode_modulesとpackage-lock.jsonが生成される.

立方体の表示

index.jsに以下のコードを記述

import * as THREE from "three"
window.addEventListener('DOMContentLoaded', init);

function init() {
    const width = 960;
    const height = 540;

    // レンダラーを作成
    const renderer = new THREE.WebGLRenderer({
        canvas: document.querySelector('#myCanvas')
    });
    renderer.setSize(width, height);
    renderer.setPixelRatio(window.devicePixelRatio);

    // シーンを作成
    const scene = new THREE.Scene();

    // カメラを作成
    const camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
    // カメラの初期座標を設定(X座標:0, Y座標:0, Z座標:0)
    camera.position.set(0, 0, 1000);

    // 箱を作成
    const geometry = new THREE.BoxGeometry(500, 500, 500);
    const material = new THREE.MeshStandardMaterial({color: 0x0000FF});
    const box = new THREE.Mesh(geometry, material);
    scene.add(box);

    // 平行光源
    const light = new THREE.DirectionalLight(0xFFFFFF);
    light.intensity = 2; // 光の強さを倍に
    light.position.set(1, 1, 1); // ライトの方向
    // シーンに追加
    scene.add(light);

    // レンダリング
    renderer.render(scene, camera);
}

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8"/>
        <title>title</title>
        <script src="./main.js"></script>
    </head>
    <body>
        <canvas id="myCanvas"></canvas>
    </body>
</html>

このような画像がレンダリングされれば成功.

ics.media

DirectX11 マルチスクリーン3

続き

モニターの数を取得してスワップチェインの生成,デプスステンシルバッファの生成をできるようになったので書きます.

変数の宣言

std::vector<IDXGISwapChain*> _pSwapChains;
std::vector<ID3D11Texture2D*> _pRenderTargets;
std::vector<ID3D11RenderTargetView*> _pRenderTargetViews;
std::vector<ID3D11DepthStencilState*> _pDepthStencilStates;
std::vector<ID3D11Texture2D*> _pDepthStencilTextures;
std::vector<ID3D11DepthStencilView*> _pDepthStencilViews;

uint32_t _monitorNum;

初期化

スワップチェインとデプスステンシルバッファの生成をモニターの数繰り返す

bool DxManager::Init(SCREEN* monitorInfo, uint32_t monitorNum) {
    _monitorNum = monitorNum;

    if (!CreateFactory()) {
        return false;
    }

    if (!CreateDevice()) {
        return false;
    }
    _pSwapChains.resize(monitorNum);
    _pRenderTargets.resize(monitorNum);
    _pRenderTargetViews.resize(monitorNum);
    _pDepthStencilStates.resize(monitorNum);
    _pDepthStencilTextures.resize(monitorNum);
    _pDepthStencilViews.resize(monitorNum);

    for (uint32_t i = 0; i < _monitorNum; i++) {
        if (!CreateSwapChain(monitorInfo[i], i)) {
            return false;
        }
        
        if (!CreateDepthStencilBuffer(monitorInfo[i], i)) {
            return false;
        }
    }
    return true;
}

ソースコード

DxManager.cpp

#include "DxManager.h"

DxManager* dx;

DxManager::DxManager() {
    _monitorNum = 0;
}
bool DxManager::Init(SCREEN* monitorInfo, uint32_t monitorNum) {
    _monitorNum = monitorNum;

    if (!CreateFactory()) {
        return false;
    }

    if (!CreateDevice()) {
        return false;
    }
    _pSwapChains.resize(monitorNum);
    _pRenderTargets.resize(monitorNum);
    _pRenderTargetViews.resize(monitorNum);
    _pDepthStencilStates.resize(monitorNum);
    _pDepthStencilTextures.resize(monitorNum);
    _pDepthStencilViews.resize(monitorNum);

    for (uint32_t i = 0; i < _monitorNum; i++) {
        if (!CreateSwapChain(monitorInfo[i], i)) {
            return false;
        }
        
        if (!CreateDepthStencilBuffer(monitorInfo[i], i)) {
            return false;
        }
    }

    if (!CreateBlendState()) {
        return false;
    }

    return true;
}

bool DxManager::CreateFactory() {
    ComPtr<IDXGIOutput> pOutput;
    DXGI_ADAPTER_DESC adapterDesc = {};
    size_t stringLength;
    uint32_t numModes = 0;
    uint32_t GPUMaxMem = 0;
    uint32_t GPUNum = 0;

    HRESULT hResult = S_OK;
    //DXGIファクトリーの作成
    hResult = CreateDXGIFactory(IID_PPV_ARGS(_pFactory.GetAddressOf()));
    if (FAILED(hResult)) {
        return false;
    }

    //GPUを列挙
    for (uint32_t i = 0; i < 100; i++) {
        IDXGIAdapter* adapter;
        hResult = _pFactory->EnumAdapters(i, &adapter);
        if (FAILED(hResult)) {
            break;
        }

        //GPUの情報を取得
        hResult = adapter->GetDesc(&adapterDesc);
        if (FAILED(hResult)) {
            return false;
        }

        char videoCardDesc[128];
        int error = wcstombs_s(&stringLength, videoCardDesc, 128, adapterDesc.Description, 128);
        if (error != 0) {
            break;
        }

        uint32_t videoCardMemory = (uint32_t)(adapterDesc.DedicatedVideoMemory / 1028 / 1024);
        std::cout << "ビデオカード名: " << videoCardDesc << std::endl;
        std::cout << "ビデオメモリ: " << videoCardMemory << std::endl;   

        hResult = adapter->EnumOutputs(0, pOutput.GetAddressOf());
        if (FAILED(hResult)) {
            continue;
        }

        hResult = pOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, nullptr);
        if (FAILED(hResult)) {
            continue;
        }

        //一番メモリが多いGPUを探す
        if (videoCardMemory > GPUMaxMem) {
            GPUMaxMem = videoCardMemory;
            GPUNum = i;
        }
    
    }

    //GPUを選ぶやでー
    hResult = _pFactory->EnumAdapters(GPUNum, _pAdapter.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }
    
    return true;
}

bool DxManager::CreateDevice() {
    HRESULT hResult = S_OK;
    UINT cdev_flags = 0;

    //デバッグレイヤーを有効にするやでー
#ifdef _DEBUG
    cdev_flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    D3D_FEATURE_LEVEL featureLevels[] = {
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_11_1,
    };

    hResult = D3D11CreateDevice(
        _pAdapter.Get(),
        D3D_DRIVER_TYPE_UNKNOWN,
        nullptr,
        cdev_flags,
        featureLevels,
        4,
        D3D11_SDK_VERSION,
        _pDevice.GetAddressOf(),
        &_featurelevel,
        _pDeviceContext.GetAddressOf()
    );
    if (FAILED(hResult)) {
        return false;
    }

    return true;
}

bool DxManager::CreateSwapChain(SCREEN monitor, uint32_t index) {
    HRESULT hResult = S_OK;
    DXGI_MODE_DESC modeDesc = {};
    modeDesc.Width = monitor.Width;
    modeDesc.Height = monitor.Height;
    modeDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
    modeDesc.RefreshRate.Numerator = 60;
    modeDesc.RefreshRate.Denominator = 1;
    modeDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
    modeDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;

    DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
    swapChainDesc.BufferCount = 2;
    swapChainDesc.BufferDesc = modeDesc;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.OutputWindow = monitor.Hwnd;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.Windowed = true;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

    hResult = _pFactory->CreateSwapChain(_pDevice.Get(), &swapChainDesc, &_pSwapChains[index]);
    if (FAILED(hResult)) {
        return false;
    }

    _pAdapter->Release();
    _pFactory->Release();
    

    hResult = _pSwapChains[index]->GetBuffer(0, IID_PPV_ARGS(&_pRenderTargets[index]));
    if (FAILED(hResult)) {
        return false;
    }

    hResult = _pDevice->CreateRenderTargetView(_pRenderTargets[index], nullptr, &_pRenderTargetViews[index]);
    if (FAILED(hResult)) {
        return false;
    }

    _viewport.Width = static_cast<float>(monitor.Width);
    _viewport.Height = static_cast<float>(monitor.Height);
    _viewport.MinDepth = 0.0f;
    _viewport.MaxDepth = 1.0f;
    _viewport.TopLeftX = 0;
    _viewport.TopLeftY = 0;
    
    

    return true;
}

bool DxManager::CreateDepthStencilBuffer(SCREEN monitor, uint32_t index) {
    D3D11_DEPTH_STENCIL_DESC desc = {};
    desc.DepthEnable = true;
    desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    desc.DepthFunc = D3D11_COMPARISON_LESS;
    desc.StencilEnable = false;
    desc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
    desc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
    desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;

    HRESULT hResult = _pDevice->CreateDepthStencilState(&desc, &_pDepthStencilStates[index]);
    if (FAILED(hResult)) {
        return false;
    }

    D3D11_TEXTURE2D_DESC Tex2Desc = {};
    Tex2Desc.Format = DXGI_FORMAT_R24G8_TYPELESS;
    Tex2Desc.Width = monitor.Width;
    Tex2Desc.Height = monitor.Height;
    Tex2Desc.ArraySize = 1;
    Tex2Desc.MipLevels = 1;
    Tex2Desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    Tex2Desc.Usage = D3D11_USAGE_DEFAULT;
    Tex2Desc.CPUAccessFlags = 0;
    Tex2Desc.SampleDesc.Count = 1;
    Tex2Desc.SampleDesc.Quality = 0;
    Tex2Desc.MiscFlags = 0;

    hResult = _pDevice->CreateTexture2D(&Tex2Desc, nullptr, &_pDepthStencilTextures[index]);
    if (FAILED(hResult)) {
        return false;
    }

    D3D11_DEPTH_STENCIL_VIEW_DESC DSVDesc = {};
    DSVDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    DSVDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    DSVDesc.Texture2D.MipSlice = 0;
    DSVDesc.Flags = 0;

    hResult = _pDevice->CreateDepthStencilView(_pDepthStencilTextures[index], &DSVDesc, &_pDepthStencilViews[index]);
    if (FAILED(hResult)) {
        return false;
    }


    return true;
}

bool DxManager::CreateBlendState() {
    D3D11_RENDER_TARGET_BLEND_DESC descRTBS = {};
    descRTBS.BlendEnable = true;
    descRTBS.SrcBlend = D3D11_BLEND_SRC_ALPHA;
    descRTBS.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
    descRTBS.BlendOp = D3D11_BLEND_OP_ADD;
    descRTBS.SrcBlendAlpha = D3D11_BLEND_ONE;
    descRTBS.DestBlendAlpha = D3D11_BLEND_ZERO;
    descRTBS.BlendOpAlpha = D3D11_BLEND_OP_ADD;
    descRTBS.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

    D3D11_BLEND_DESC descBS = {};
    descBS.AlphaToCoverageEnable = true;
    descBS.IndependentBlendEnable = true;
    for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) {
        descBS.RenderTarget[i] = descRTBS;
    }

    HRESULT hResult = _pDevice->CreateBlendState(&descBS, _pBlendState.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }
    return true;
}


void DxManager::BeginRender() {
    for (uint32_t i = 0; i < _monitorNum; i++){
        _pDeviceContext->OMSetRenderTargets(1, &_pRenderTargetViews[i], _pDepthStencilViews[i]);
        _pDeviceContext->RSSetViewports(1, &_viewport);

        float clearColor[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
        _pDeviceContext->ClearRenderTargetView(_pRenderTargetViews[i], clearColor);
        _pDeviceContext->ClearDepthStencilView(_pDepthStencilViews[i], D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
    }
}

void DxManager::EndRender() {
    for (uint32_t i = 0; i < _monitorNum; i++) {
        _pSwapChains[i]->Present(1, 0);
    }
}

DxManager.h

#pragma once

#include <iostream>
#include <cstdint>
#include <vector>
#include <d3d11.h>
#include <dxgi.h>
#include <Windows.h>
#include <windef.h>
#include <wrl/client.h>

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

using Microsoft::WRL::ComPtr;

struct SCREEN {
    int32_t X;
    int32_t Y;
    int32_t Width;
    int32_t Height;
    HWND Hwnd;
};

class DxManager {
private:
    D3D_FEATURE_LEVEL _featurelevel;
    ComPtr<IDXGIFactory> _pFactory = nullptr;
    ComPtr<IDXGIAdapter> _pAdapter = nullptr;

    ComPtr<ID3D11Device> _pDevice = nullptr;
    ComPtr<ID3D11DeviceContext> _pDeviceContext = nullptr;
    std::vector<IDXGISwapChain*> _pSwapChains;
    std::vector<ID3D11Texture2D*> _pRenderTargets;
    std::vector<ID3D11RenderTargetView*> _pRenderTargetViews;
    std::vector<ID3D11DepthStencilState*> _pDepthStencilStates;
    std::vector<ID3D11Texture2D*> _pDepthStencilTextures;
    std::vector<ID3D11DepthStencilView*> _pDepthStencilViews;
    ComPtr<ID3D11BlendState> _pBlendState;

    D3D11_VIEWPORT _viewport;

    uint32_t _monitorNum;

public:
    DxManager();
    bool Init(SCREEN* monitorInfo, uint32_t monitorNum);

    void BeginRender();
    void EndRender();

private:
    bool CreateFactory();
    bool CreateDevice();
    bool CreateSwapChain(SCREEN montor, uint32_t index);
    bool CreateDepthStencilBuffer(SCREEN monitor, uint32_t index);
    bool CreateBlendState();
};

extern DxManager* dx;

DirectX11 マルチスクリーン2

画面の初期化

スワップチェインとレンダーターゲットをモニターの数だけ生成する.できればモニターの数を自動で取得して初期化をしたかったが,めんどくさそうだったのでやめた.

モニターの情報を保持する構造体を作成

struct SCREEN {
    int32_t X;
    int32_t Y;
    int32_t Width;
    int32_t Height;
    HWND Hwnd;
};

スワップチェインの生成

const uint32_t MONITOR_NUM = 4;
IDXGISwapChain* _pSwapChains[4];
ID3D11Texture2D* _pRenderTargets[4];
ID3D11RenderTargetView* _pRenderTargetViews[4];
bool DxManager::CreateSwapChain(SCREEN monitor, uint32_t index) {
    HRESULT hResult = S_OK;
    DXGI_MODE_DESC modeDesc = {};
    modeDesc.Width = monitor.Width;
    modeDesc.Height = monitor.Height;
    modeDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
    modeDesc.RefreshRate.Numerator = 60;
    modeDesc.RefreshRate.Denominator = 1;
    modeDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
    modeDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;

    DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
    swapChainDesc.BufferCount = 2;
    swapChainDesc.BufferDesc = modeDesc;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.OutputWindow = monitor.Hwnd;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.Windowed = true;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

    hResult = _pFactory->CreateSwapChain(_pDevice.Get(), &swapChainDesc, &_pSwapChains[index]);
    if (FAILED(hResult)) {
        return false;
    }

    _pAdapter->Release();
    _pFactory->Release();
    

    hResult = _pSwapChains[index]->GetBuffer(0, IID_PPV_ARGS(&_pRenderTargets[index]));
    if (FAILED(hResult)) {
        return false;
    }

    hResult = _pDevice->CreateRenderTargetView(_pRenderTargets[index], nullptr, &_pRenderTargetViews[index]);
    if (FAILED(hResult)) {
        return false;
    }

    _viewport.Width = static_cast<float>(monitor.Width);
    _viewport.Height = static_cast<float>(monitor.Height);
    _viewport.MinDepth = 0.0f;
    _viewport.MaxDepth = 1.0f;
    _viewport.TopLeftX = 0;
    _viewport.TopLeftY = 0;
    
    

    return true;
}

レンダリング

void DxManager::BeginRender() {
    for (uint32_t i = 0; i < MONITOR_NUM; i++){
        _pDeviceContext->OMSetRenderTargets(1, &_pRenderTargetViews[i], nullptr);
        _pDeviceContext->RSSetViewports(1, &_viewport);

        float clearColor[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
        _pDeviceContext->ClearRenderTargetView(_pRenderTargetViews[i], clearColor);
    }
}

void DxManager::EndRender() {
    for (uint32_t i = 0; i < MONITOR_NUM; i++) {
        _pSwapChains[i]->Present(1, 0);
    }
}

DirectX11 マルチスクリーン1

はじめに

現在このような環境でモニターを配置している.これに対応できるようにウィンドウを表示したい.

フルスクリーンでウィンドウの表示

方法① Win32APIで愚直にフルスクリーン

ameblo.jp

これを参考にフルスクリーン表示をしてみる

SetMenu(_hwnd, NULL);
SetWindowLong(_hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
MoveWindow(
        _hwnd,
        GetSystemMetrics(SM_XVIRTUALSCREEN),
        GetSystemMetrics(SM_YVIRTUALSCREEN),
        GetSystemMetrics(SM_CXVIRTUALSCREEN),
        GetSystemMetrics(SM_CYVIRTUALSCREEN),
        TRUE
    );

結果

全画面をそのままキャプチャした.赤いところが表示されている部分. それっぽくできてそう?
横と縦を表示してみると

x: 5888 y: 2520

と表示された.
これだとDirectX11でレンダリングするときに不都合がありそう...なので,別の方法を考えてみる.

方法② 複数ウィンドウを作成して最大化

App.h

#pragma once

#include <Windows.h>
#include <cstdint>
#include <string>
#include <iostream>
#include <vector>


class App {
public:
    App();
    void Run();


private:
    HINSTANCE RegisterWindowClass();
    HWND InitWindow(HINSTANCE hInstance, std::wstring className);
    bool InitApp();
    void MainLoop();

    static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
    static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

    

private:
    const std::wstring WindowClassName = L"MainWindow";

    uint32_t _width;
    uint32_t _height;

    std::vector<MONITORINFO> _monitorInfo;
    std::vector<HWND> _windowHandles;
};

extern App* appPtr;

App.cpp

#include "App.h"

App* appPtr;

App::App() {
    _width = 1080;
    _height = 720;
    appPtr = this;
}

void App::Run() {
    if (!InitApp()) {
        return;
    }

    MainLoop();
}

//初期化
bool App::InitApp() {

    EnumDisplayMonitors(nullptr, nullptr, MonitorEnumProc, 0);
    

    HINSTANCE hInstance = RegisterWindowClass();
    if (hInstance == nullptr) {
        return false;
    }

    for (uint32_t i = 0; i < _monitorInfo.size(); i++) {
        HWND hwnd = InitWindow(hInstance, WindowClassName);
        if (!hwnd) {
            std::cout << "Failed to create window" << std::endl;
            return false;
        }

        int32_t x = _monitorInfo[i].rcMonitor.left;
        int32_t y = _monitorInfo[i].rcMonitor.top;
        int32_t width = _monitorInfo[i].rcMonitor.right - x;
        int32_t height = _monitorInfo[i].rcMonitor.bottom - y;
        SetWindowPos(hwnd, nullptr, x, y, width, height, SWP_NOZORDER);
        _windowHandles.push_back(hwnd);

    }

    return true;
}

HINSTANCE App::RegisterWindowClass() {
    HINSTANCE hInstance = GetModuleHandle(nullptr);

    //ウィンドウの設定
    WNDCLASSEX wc = {};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;     //水平方向と垂直方向のサイズ変更で再描画
    wc.lpfnWndProc = WndProc;   //ウィンドウプロシージャの登録
    wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);    //アイコン
    wc.hCursor = LoadCursor(hInstance, IDC_ARROW);      //マウスカーソル
    wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); //背景色は黒
    wc.hInstance = hInstance;  //インスタンスハンドル
    wc.lpszMenuName = nullptr;  //メニュー
    wc.lpszClassName = WindowClassName.c_str();      //ウィンドウクラスの名前
    wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);      //小さいアイコン

    RegisterClassEx(&wc);    //ウィンドウクラスの登録

    return hInstance;
}

HWND App::InitWindow(HINSTANCE hInstance, std::wstring className) {
    HWND hwnd = CreateWindowEx(
        0,
        className.c_str(),
        L"Title",
        WS_OVERLAPPEDWINDOW,
        0, 0,
        _width, _height,
        nullptr, nullptr,
        hInstance,
        nullptr
    );

    ShowWindow(hwnd, SW_SHOWMAXIMIZED);
    UpdateWindow(hwnd);

    return hwnd;
}

//メインループ
void App::MainLoop() {
    MSG msg = {};
    while (WM_QUIT != msg.message)
    {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE == true))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {

            for (uint32_t i = 0; i < _windowHandles.size(); i++) {
                UpdateWindow(_windowHandles[i]);
            }
        }
    }
}

BOOL CALLBACK App::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
    MONITORINFOEX monitorInfo;
    monitorInfo.cbSize = sizeof(monitorInfo);
    GetMonitorInfo(hMonitor, &monitorInfo);
    
    appPtr->_monitorInfo.push_back(monitorInfo);

    return true;
}

//ウィンドウプロシージャ
LRESULT CALLBACK App::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        break;
    }

    return DefWindowProc(hwnd, msg, wParam, lParam);
}

結果

できたっぽい
とりあえずこれで進めていくことにする
次は画面の初期化をしたいなぁ

参考資料

learn.microsoft.com

https://araramistudio.jimdo.com/2017/05/17/c-%E3%81%A7%E7%94%BB%E9%9D%A2%E3%81%AE%E8%A7%A3%E5%83%8F%E5%BA%A6%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B/

s-kita.hatenablog.com

DirectX11 初期化

はじめに

DirectX11を使用して画面の初期化を行う.

環境

ウィンドウの作成

hashimoto128.hatenablog.com

GPUを列挙して選択

bool DxManager::CreateFactory() {
    ComPtr<IDXGIOutput> pOutput;
    DXGI_ADAPTER_DESC adapterDesc = {};
    size_t stringLength;
    uint32_t numModes = 0;
    uint32_t GPUMaxMem = 0;
    uint32_t GPUNum = 0;

    HRESULT hResult = S_OK;
    //DXGIファクトリーの作成
    hResult = CreateDXGIFactory(IID_PPV_ARGS(_pFactory.GetAddressOf()));
    if (FAILED(hResult)) {
        return false;
    }

    //GPUを列挙
    for (uint32_t i = 0; i < 100; i++) {
        IDXGIAdapter* adapter;
        hResult = _pFactory->EnumAdapters(i, &adapter);
        if (FAILED(hResult)) {
            break;
        }

        //GPUの情報を取得
        hResult = adapter->GetDesc(&adapterDesc);
        if (FAILED(hResult)) {
            return false;
        }

        char videoCardDesc[128];
        int error = wcstombs_s(&stringLength, videoCardDesc, 128, adapterDesc.Description, 128);
        if (error != 0) {
            break;
        }

        uint32_t videoCardMemory = (uint32_t)(adapterDesc.DedicatedVideoMemory / 1028 / 1024);
        std::cout << "ビデオカード名: " << videoCardDesc << std::endl;
        std::cout << "ビデオメモリ: " << videoCardMemory << std::endl;   

        hResult = adapter->EnumOutputs(0, pOutput.GetAddressOf());
        if (FAILED(hResult)) {
            continue;
        }

        hResult = pOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, nullptr);
        if (FAILED(hResult)) {
            continue;
        }

        //一番メモリが多いGPUを探す
        if (videoCardMemory > GPUMaxMem) {
            GPUMaxMem = videoCardMemory;
            GPUNum = i;
        }
    
    }

    //GPUを選ぶやでー
    hResult = _pFactory->EnumAdapters(GPUNum, _pAdapter.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }
    
    return true;
}

バイススワップチェインの作成

bool DxManager::CreateDeviceAndSwapChain() {
    HRESULT hResult = S_OK;
    UINT cdev_flags = 0;

    //デバッグレイヤーを有効にするやでー
#ifdef _DEBUG
    cdev_flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    DXGI_MODE_DESC modeDesc = {};
    modeDesc.Width = _width;
    modeDesc.Height = _height;
    modeDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
    modeDesc.RefreshRate.Numerator = 60;
    modeDesc.RefreshRate.Denominator = 1;
    modeDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
    modeDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;

    DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
    swapChainDesc.BufferCount = 2;
    swapChainDesc.BufferDesc = modeDesc;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.OutputWindow = _hwnd;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.Windowed = true;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

    D3D_FEATURE_LEVEL featureLevels[] = {
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_11_1,
    };


    hResult = D3D11CreateDeviceAndSwapChain(
        _pAdapter.Get(),
        D3D_DRIVER_TYPE_UNKNOWN,
        nullptr,
        cdev_flags,
        featureLevels, 4,
        D3D11_SDK_VERSION,
        &swapChainDesc,
        _pSwapChain.GetAddressOf(),
        _pDevice.GetAddressOf(),
        &_featurelevel,
        _pDeviceContext.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    _pAdapter->Release();
    _pFactory->Release();

    hResult = _pSwapChain->GetBuffer(0, IID_PPV_ARGS(_pRenderTarget.GetAddressOf()));
    if (FAILED(hResult)) {
        return false;
    }

    hResult = _pDevice->CreateRenderTargetView(_pRenderTarget.Get(), nullptr, _pRenderTargetView.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    _viewport.Width = static_cast<float>(_width);
    _viewport.Height = static_cast<float>(_height);
    _viewport.MinDepth = 0.0f;
    _viewport.MaxDepth = 1.0f;
    _viewport.TopLeftX = 0;
    _viewport.TopLeftY = 0;

    return true;
}

デプスステンシルバッファの作成

bool DxManager::CreateDepthStencilBuffer() {
    D3D11_DEPTH_STENCIL_DESC desc = {};
    desc.DepthEnable = true;
    desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    desc.DepthFunc = D3D11_COMPARISON_LESS;
    desc.StencilEnable = false;
    desc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
    desc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
    desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;

    HRESULT hResult = _pDevice->CreateDepthStencilState(&desc, _pDepthStencilState.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    D3D11_TEXTURE2D_DESC Tex2Desc = {};
    Tex2Desc.Format = DXGI_FORMAT_R24G8_TYPELESS;
    Tex2Desc.Width = _width;
    Tex2Desc.Height = _height;
    Tex2Desc.ArraySize = 1;
    Tex2Desc.MipLevels = 1;
    Tex2Desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    Tex2Desc.Usage = D3D11_USAGE_DEFAULT;
    Tex2Desc.CPUAccessFlags = 0;
    Tex2Desc.SampleDesc.Count = 1;
    Tex2Desc.SampleDesc.Quality = 0;
    Tex2Desc.MiscFlags = 0;

    hResult = _pDevice->CreateTexture2D(&Tex2Desc, nullptr, _pDepthStencilTex.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    D3D11_DEPTH_STENCIL_VIEW_DESC DSVDesc = {};
    DSVDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    DSVDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    DSVDesc.Texture2D.MipSlice = 0;
    DSVDesc.Flags = 0;

    hResult = _pDevice->CreateDepthStencilView(_pDepthStencilTex.Get(), &DSVDesc, _pDepthStencilView.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }


    return true;
}

ブレンドステートの作成

bool DxManager::CreateBlendState() {
    D3D11_RENDER_TARGET_BLEND_DESC descRTBS = {};
    descRTBS.BlendEnable = true;
    descRTBS.SrcBlend = D3D11_BLEND_SRC_ALPHA;
    descRTBS.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
    descRTBS.BlendOp = D3D11_BLEND_OP_ADD;
    descRTBS.SrcBlendAlpha = D3D11_BLEND_ONE;
    descRTBS.DestBlendAlpha = D3D11_BLEND_ZERO;
    descRTBS.BlendOpAlpha = D3D11_BLEND_OP_ADD;
    descRTBS.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

    D3D11_BLEND_DESC descBS = {};
    descBS.AlphaToCoverageEnable = true;
    descBS.IndependentBlendEnable = true;
    for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) {
        descBS.RenderTarget[i] = descRTBS;
    }

    HRESULT hResult = _pDevice->CreateBlendState(&descBS, _pBlendState.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }
    return true;
}

画面の初期化

void DxManager::BeginRender() {
    _pDeviceContext->OMSetRenderTargets(1, _pRenderTargetView.GetAddressOf(), _pDepthStencilView.Get());
    _pDeviceContext->RSSetViewports(1, &_viewport);

    float clearColor[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
    _pDeviceContext->ClearRenderTargetView(_pRenderTargetView.Get(), clearColor);
    _pDeviceContext->ClearDepthStencilView(_pDepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
}

void DxManager::EndRender() {
    _pSwapChain->Present(1, 0);
}

ソースコード

main.cpp

#include "App.h"

int main() {
    App app = App();
    app.Run();
}

App.h

#pragma once

#include <Windows.h>
#include <cstdint>
#include <string>
#include <iostream>

#include "DxManager.h"



class App {
public:
    App();
    void Run();

private:
    bool InitApp();
    bool InitWindow();
    void MainLoop();

    static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

private:
    const std::wstring WindowClassName = L"MainWindow";

    uint32_t _width;
    uint32_t _height;

    HWND _hwnd;
    HINSTANCE _hInstance;
};

App.cpp

#include "App.h"

App::App() {
    _width = 1080;
    _height = 720;
    _hwnd = nullptr;
    _hInstance = nullptr;
}

void App::Run() {
    if (!InitApp()) {
        return;
    }

    MainLoop();
}

//初期化
bool App::InitApp() {

    dx = new DxManager();

    if (!InitWindow()) {
        return false;
    }

    if (!dx->Init(_width, _height, _hwnd)) {
        return false;
    }

    return true;
}

//ウィンドウの初期化
bool App::InitWindow() {
    _hInstance = GetModuleHandle(nullptr);
    if (_hInstance == nullptr) {
        return false;
    }

    //ウィンドウの設定
    WNDCLASSEX wc = {};
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;     //水平方向と垂直方向のサイズ変更で再描画
    wc.lpfnWndProc = WndProc;   //ウィンドウプロシージャの登録
    wc.hIcon = LoadIcon(_hInstance, IDI_APPLICATION);    //アイコン
    wc.hCursor = LoadCursor(_hInstance, IDC_ARROW);      //マウスカーソル
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //背景色は黒
    wc.hInstance = _hInstance;  //インスタンスハンドル
    wc.lpszMenuName = nullptr;  //メニュー
    wc.lpszClassName = WindowClassName.c_str();      //ウィンドウクラスの名前
    wc.hIconSm = LoadIcon(_hInstance, IDI_APPLICATION);      //小さいアイコン

    RegisterClassEx(&wc);    //ウィンドウクラスの登録

    _hwnd = CreateWindowEx(
        0,                  
        WindowClassName.c_str(),
        L"Title",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        _width, _height,
        nullptr, nullptr,
        _hInstance,
        nullptr
    );

    ShowWindow(_hwnd, SW_SHOWNORMAL);
    UpdateWindow(_hwnd);

    SetFocus(_hwnd);

    return true;
}

//メインループ
void App::MainLoop() {
    MSG msg = {};
    while (WM_QUIT != msg.message)
    {
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE == true))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            dx->BeginRender();

            dx->EndRender();
            UpdateWindow(_hwnd);
        }
    }
}

//ウィンドウプロシージャ
LRESULT CALLBACK App::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        break;
    }

    return DefWindowProc(hwnd, msg, wParam, lParam);
}

DxManager.h

#pragma once

#include <iostream>
#include <cstdint>
#include <d3d11.h>
#include <dxgi.h>
#include <Windows.h>
#include <windef.h>
#include <wrl/client.h>

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

using Microsoft::WRL::ComPtr;

class DxManager
{
private:
    D3D_FEATURE_LEVEL _featurelevel;
    ComPtr<IDXGIFactory> _pFactory = nullptr;
    ComPtr<IDXGIAdapter> _pAdapter = nullptr;

    ComPtr<ID3D11Device> _pDevice = nullptr;
    ComPtr<ID3D11DeviceContext> _pDeviceContext = nullptr;
    ComPtr<IDXGISwapChain> _pSwapChain = nullptr;
    ComPtr<ID3D11Texture2D> _pRenderTarget = nullptr;
    ComPtr<ID3D11RenderTargetView> _pRenderTargetView = nullptr;
    ComPtr<ID3D11DepthStencilState> _pDepthStencilState = nullptr;
    ComPtr<ID3D11Texture2D> _pDepthStencilTex = nullptr;
    ComPtr<ID3D11DepthStencilView> _pDepthStencilView = nullptr;
    ComPtr<ID3D11BlendState> _pBlendState;

    D3D11_VIEWPORT _viewport;

    uint32_t _width;
    uint32_t _height;
    HWND _hwnd;

public:
    bool Init(uint32_t width, uint32_t height, HWND hwnd);

    void BeginRender();
    void EndRender();

private:
    bool CreateFactory();
    bool CreateDeviceAndSwapChain();
    bool CreateDepthStencilBuffer();
    bool CreateBlendState();
};

DxManager.cpp

#include "DxManager.h"

bool DxManager::Init(uint32_t width, uint32_t height, HWND hwnd) {
    _width = width;
    _height = height;
    _hwnd = hwnd;

    if (!CreateFactory()) {
        return false;
    }

    if (!CreateDeviceAndSwapChain()) {
        return false;
    }

    if (!CreateDepthStencilBuffer()) {
        return false;
    }

    if (!CreateBlendState()) {
        return false;
    }


    return true;
}

bool DxManager::CreateFactory() {
    ComPtr<IDXGIOutput> pOutput;
    DXGI_ADAPTER_DESC adapterDesc = {};
    size_t stringLength;
    uint32_t numModes = 0;
    uint32_t GPUMaxMem = 0;
    uint32_t GPUNum = 0;

    HRESULT hResult = S_OK;
    //DXGIファクトリーの作成
    hResult = CreateDXGIFactory(IID_PPV_ARGS(_pFactory.GetAddressOf()));
    if (FAILED(hResult)) {
        return false;
    }

    //GPUを列挙
    for (uint32_t i = 0; i < 100; i++) {
        IDXGIAdapter* adapter;
        hResult = _pFactory->EnumAdapters(i, &adapter);
        if (FAILED(hResult)) {
            break;
        }

        //GPUの情報を取得
        hResult = adapter->GetDesc(&adapterDesc);
        if (FAILED(hResult)) {
            return false;
        }

        char videoCardDesc[128];
        int error = wcstombs_s(&stringLength, videoCardDesc, 128, adapterDesc.Description, 128);
        if (error != 0) {
            break;
        }

        uint32_t videoCardMemory = (uint32_t)(adapterDesc.DedicatedVideoMemory / 1028 / 1024);
        std::cout << "ビデオカード名: " << videoCardDesc << std::endl;
        std::cout << "ビデオメモリ: " << videoCardMemory << std::endl;   

        hResult = adapter->EnumOutputs(0, pOutput.GetAddressOf());
        if (FAILED(hResult)) {
            continue;
        }

        hResult = pOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, nullptr);
        if (FAILED(hResult)) {
            continue;
        }

        //一番メモリが多いGPUを探す
        if (videoCardMemory > GPUMaxMem) {
            GPUMaxMem = videoCardMemory;
            GPUNum = i;
        }
    
    }

    //GPUを選ぶやでー
    hResult = _pFactory->EnumAdapters(GPUNum, _pAdapter.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }
    
    return true;
}

bool DxManager::CreateDeviceAndSwapChain() {
    HRESULT hResult = S_OK;
    UINT cdev_flags = 0;

    //デバッグレイヤーを有効にするやでー
#ifdef _DEBUG
    cdev_flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

    DXGI_MODE_DESC modeDesc = {};
    modeDesc.Width = _width;
    modeDesc.Height = _height;
    modeDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
    modeDesc.RefreshRate.Numerator = 60;
    modeDesc.RefreshRate.Denominator = 1;
    modeDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
    modeDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;

    DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
    swapChainDesc.BufferCount = 2;
    swapChainDesc.BufferDesc = modeDesc;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.OutputWindow = _hwnd;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.Windowed = true;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

    D3D_FEATURE_LEVEL featureLevels[] = {
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_11_1,
    };


    hResult = D3D11CreateDeviceAndSwapChain(
        _pAdapter.Get(),
        D3D_DRIVER_TYPE_UNKNOWN,
        nullptr,
        cdev_flags,
        featureLevels, 4,
        D3D11_SDK_VERSION,
        &swapChainDesc,
        _pSwapChain.GetAddressOf(),
        _pDevice.GetAddressOf(),
        &_featurelevel,
        _pDeviceContext.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    _pAdapter->Release();
    _pFactory->Release();

    hResult = _pSwapChain->GetBuffer(0, IID_PPV_ARGS(_pRenderTarget.GetAddressOf()));
    if (FAILED(hResult)) {
        return false;
    }

    hResult = _pDevice->CreateRenderTargetView(_pRenderTarget.Get(), nullptr, _pRenderTargetView.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    _viewport.Width = static_cast<float>(_width);
    _viewport.Height = static_cast<float>(_height);
    _viewport.MinDepth = 0.0f;
    _viewport.MaxDepth = 1.0f;
    _viewport.TopLeftX = 0;
    _viewport.TopLeftY = 0;


    return true;

}

bool DxManager::CreateDepthStencilBuffer() {
    D3D11_DEPTH_STENCIL_DESC desc = {};
    desc.DepthEnable = true;
    desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    desc.DepthFunc = D3D11_COMPARISON_LESS;
    desc.StencilEnable = false;
    desc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
    desc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
    desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;

    HRESULT hResult = _pDevice->CreateDepthStencilState(&desc, _pDepthStencilState.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    D3D11_TEXTURE2D_DESC Tex2Desc = {};
    Tex2Desc.Format = DXGI_FORMAT_R24G8_TYPELESS;
    Tex2Desc.Width = _width;
    Tex2Desc.Height = _height;
    Tex2Desc.ArraySize = 1;
    Tex2Desc.MipLevels = 1;
    Tex2Desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    Tex2Desc.Usage = D3D11_USAGE_DEFAULT;
    Tex2Desc.CPUAccessFlags = 0;
    Tex2Desc.SampleDesc.Count = 1;
    Tex2Desc.SampleDesc.Quality = 0;
    Tex2Desc.MiscFlags = 0;

    hResult = _pDevice->CreateTexture2D(&Tex2Desc, nullptr, _pDepthStencilTex.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    D3D11_DEPTH_STENCIL_VIEW_DESC DSVDesc = {};
    DSVDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    DSVDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    DSVDesc.Texture2D.MipSlice = 0;
    DSVDesc.Flags = 0;

    hResult = _pDevice->CreateDepthStencilView(_pDepthStencilTex.Get(), &DSVDesc, _pDepthStencilView.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }


    return true;
}

bool DxManager::CreateBlendState() {
    D3D11_RENDER_TARGET_BLEND_DESC descRTBS = {};
    descRTBS.BlendEnable = true;
    descRTBS.SrcBlend = D3D11_BLEND_SRC_ALPHA;
    descRTBS.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
    descRTBS.BlendOp = D3D11_BLEND_OP_ADD;
    descRTBS.SrcBlendAlpha = D3D11_BLEND_ONE;
    descRTBS.DestBlendAlpha = D3D11_BLEND_ZERO;
    descRTBS.BlendOpAlpha = D3D11_BLEND_OP_ADD;
    descRTBS.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

    D3D11_BLEND_DESC descBS = {};
    descBS.AlphaToCoverageEnable = true;
    descBS.IndependentBlendEnable = true;
    for (uint32_t i = 0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) {
        descBS.RenderTarget[i] = descRTBS;
    }

    HRESULT hResult = _pDevice->CreateBlendState(&descBS, _pBlendState.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }
    return true;
}


void DxManager::BeginRender() {
    _pDeviceContext->OMSetRenderTargets(1, _pRenderTargetView.GetAddressOf(), _pDepthStencilView.Get());
    _pDeviceContext->RSSetViewports(1, &_viewport);

    float clearColor[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
    _pDeviceContext->ClearRenderTargetView(_pRenderTargetView.Get(), clearColor);
    _pDeviceContext->ClearDepthStencilView(_pDepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
}

void DxManager::EndRender() {
    _pSwapChain->Present(1, 0);
}

おまけ(デバイススワップチェインを別に作成)

bool DxManager::CreateSwapChain() {
    HRESULT hResult = S_OK;

    DXGI_MODE_DESC modeDesc = {};
    modeDesc.Width = _width;
    modeDesc.Height = _height;
    modeDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
    modeDesc.RefreshRate.Numerator = 60;
    modeDesc.RefreshRate.Denominator = 1;
    modeDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
    modeDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;

    DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
    swapChainDesc.BufferCount = 2;
    swapChainDesc.BufferDesc = modeDesc;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.OutputWindow = _hwnd;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.Windowed = true;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

    hResult = _pFactory->CreateSwapChain(_pDevice.Get(), &swapChainDesc, _pSwapChain.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    _pAdapter->Release();
    _pFactory->Release();

    hResult = _pSwapChain->GetBuffer(0, IID_PPV_ARGS(_pRenderTarget.GetAddressOf()));
    if (FAILED(hResult)) {
        return false;
    }

    hResult = _pDevice->CreateRenderTargetView(_pRenderTarget.Get(), nullptr, _pRenderTargetView.GetAddressOf());
    if (FAILED(hResult)) {
        return false;
    }

    _viewport.Width = static_cast<float>(_width);
    _viewport.Height = static_cast<float>(_height);
    _viewport.MinDepth = 0.0f;
    _viewport.MaxDepth = 1.0f;
    _viewport.TopLeftX = 0;
    _viewport.TopLeftY = 0;

    return true;
}