2016年3月9日水曜日

Code alignment Visual Studio拡張

ふと思い立って検索したところ,Code alignmentというVisual Studioの拡張機能を見つけました.
名前の通り,コードの整列をしてくれる拡張機能です.なお,Notepad++にも対応しているようです.

例えば,こんなコードがあったとします.
DXGI_SWAP_CHAIN_DESC SwapChainDesc{};
SwapChainDesc.BufferDesc.Width = Width;
SwapChainDesc.BufferDesc.Height = Height;
SwapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
SwapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
SwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
SwapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
SwapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
SwapChainDesc.SampleDesc.Count = 1;
SwapChainDesc.SampleDesc.Quality = 0;
SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapChainDesc.BufferCount = 1;
SwapChainDesc.OutputWindow = hWnd;
SwapChainDesc.Windowed = TRUE;
SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
SwapChainDesc.Flags = 0;

Ctrl+Shift+;でダイアログを表示し,そろえるための文字を指定します.
例えば,"="を指定すると,次のようになります.

SwapChainDesc.BufferDesc.Width                   = Width;
SwapChainDesc.BufferDesc.Height                  = Height;
SwapChainDesc.BufferDesc.RefreshRate.Numerator   = 60;
SwapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
SwapChainDesc.BufferDesc.Format                  = DXGI_FORMAT_R8G8B8A8_UNORM;
SwapChainDesc.BufferDesc.ScanlineOrdering        = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
SwapChainDesc.BufferDesc.Scaling                 = DXGI_MODE_SCALING_UNSPECIFIED;
SwapChainDesc.SampleDesc.Count                   = 1;
SwapChainDesc.SampleDesc.Quality                 = 0;
SwapChainDesc.BufferUsage                        = DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapChainDesc.BufferCount                        = 1;
SwapChainDesc.OutputWindow                       = hWnd;
SwapChainDesc.Windowed                           = TRUE;
SwapChainDesc.SwapEffect                         = DXGI_SWAP_EFFECT_DISCARD;
SwapChainDesc.Flags                              = 0;

ブログの幅の関係で汚く見えるかもしれませんが,Visual Studio上で見る分にはスッキリして見えます.

また,よく使うパターンについてはショートカットが用意されています.
Tools(ツール) > Options(オプション) > Environment(環境) > Keyboard(キーボード)でEdit.Alignあたりまでを検索ボックスに入力すると,ショートカットが確認でき,ショートカットキーを割り当てることができます.

例えば,Edit.AlignByEqual(=で整列),Edit.AlignByEqualEqual(==で整列)などがあるようです.

2016年1月29日金曜日

TortoiseSVNのインストール,およびメニューの日本語化手順

バージョン管理というと,最近の流行りはGitなのですが,まだまだSubversionを使う機会もあります.

Windows環境でSubversionを使う場合,いくつかソフトウェアがありますが,ここではTortoiseSVN(トータスエスブイエヌ)を紹介します.以下の手順は,Windows 10 64bit環境での手順になります.

ダウンロード

まず,TortoiseSVNのウェブサイトにアクセスします.次のような画面が表示されるので,画面上のDownloadタブをクリックし,インストーラーなどをダウンロードします.


ここでは,64bit OSという前提なので,次の図のように右側の64-bit版インストーラをダウンロードします.


合わせて,日本語化のための言語パックをダウンロードしておきます.言語パックは,TortoiseSVNのインストーラより下の方に,国別に用意されています.ここでも,64bit版を選ぶようにします.


適切にダウンロードできていれば,次の図のように2つのファイルがダウンロードされているはずです.


インストール

TortoiseSVNのインストーラを起動すると,次のような画面が表示されます.まずは,Nextを選んで先に進みましょう.


EULA(End User License Agreement),つまりライセンスへの同意が求められるので,問題が無ければNextを押して次へ進みます.


次の図のように,デフォルトではコマンドラインツールをインストールしないようになっています.しかし,コマンドラインツールは有った方が便利なので,×印が付いている部分をクリックし,"Will be installed on local hard drive"を選びましょう.これでコマンドラインツールもインストールされます.


設定ができたら,管理者権限でインストールを開始します.


インストールが終わると,次のような画面が表示されるので,Show Changelog(変更履歴の表示)のチェックを外しておいて,変更履歴が表示されないようにしてから,Finishを選んでインストールを終了します.


言語パックのインストール

このままでも使えなくはないのですが,メニューなどが日本語になっている方が良いでしょう.ダウンロードした言語パックのインストーラを起動します.特に選択肢などは無いので,そのまま「次へ」を選んで,「完了」を選びます.



言語パックをインストールしたら,適当な場所で右クリックをし,TortoiseSVNからSettingsを選びます.

設定画面が開くので,GeneralにあるLanguageを日本語に変更し,適用します.
これで,メニューが日本語化されます.

2016年1月1日金曜日

ChromeでWebGL 2.0を有効にする方法

ChromeでWebGL 2.0を実行できる環境を用意するための手順.
なお,開発版のChromeを利用する必要があるため,以下の手順を試す場合,自己責任でお願いいたします.
また,Windows 10での動作確認のため,その他のOSでの動作確認はしていません.

Chrome Canaryのインストール

公式サイトから,Chromeの開発版であるChrome Canaryをダウンロードし,インストールします.

ショートカットの編集

デスクトップにショートカットができると思うので,右クリックをして,プロパティを表示させます.このリンク先の部分の最後に,"--enable-unsafe-es3-apis"を追加します.


このショートカットからChrome Canaryを起動すれば,WebGL 2.0が利用できるようになっています.

var c = document.getElementById('canvas-id');
var gl = c.getContext('webgl2');

このように,canvas要素のgetContextメソッドに'webgl2'を渡せば,WebGL 2.0のレンダリングコンテキストが取得できます.

2015年9月25日金曜日

DXGIFactoryの生成または取得方法

生成または取得する方法がいくつかあるのでまとめておきます.

#include <Windows.h>
#include <tchar.h>
#include <wrl/client.h>
#include <d3d11_3.h>
#include <dxgi1_4.h>

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

using namespace Microsoft::WRL;
using namespace std;

int WINAPI wWinMain(
    HINSTANCE hInstance,
    HINSTANCE,
    LPWSTR lpCmdLine,
    int nCmdShow
)
{
    HRESULT hr = S_OK;

    // CreateDXGIFactoryによるDXGIFactoryの生成
    {
        ComPtr<idxgifactory> pFactory;
        hr = CreateDXGIFactory(
            IID_PPV_ARGS(pFactory.GetAddressOf())
        );
        if(FAILED(hr)) { return 0; }

        // インターフェースがサポートされていない,と失敗する
        // ComPtr<idxgifactory1> pFactory1;
        // hr = pFactory.As(&pFactory1);
        // if(FAILED(hr)) { return 0; }
    }

    // CreateDXGIFactory1によるDXGIFactory1の生成 (Windows 7以降)
    {
        ComPtr<idxgifactory1> pFactory1;
        hr = CreateDXGIFactory1(
            IID_PPV_ARGS(pFactory1.GetAddressOf())
        );
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory> pFactory;
        hr = pFactory1.As(&pFactory);
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory3> pFactory3;
        hr = pFactory1.As(&pFactory3);
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory4> pFactory4;
        hr = pFactory1.As(&pFactory4);
        if(FAILED(hr)) { return 0; }
    }

    // CreateDXGIFactory2によるDXGIFactory2の生成 (Windows 8.1以降)
    {
        ComPtr<idxgifactory2> pFactory2;
        ULONG creationFlag = 0;
#ifdef _DEBUG
        creationFlag |= DXGI_CREATE_FACTORY_DEBUG;
#endif

        hr = CreateDXGIFactory2(
            creationFlag,
            IID_PPV_ARGS(pFactory2.GetAddressOf())
        );
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory> pFactory;
        hr = pFactory2.As(&pFactory);
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory1> pFactory1;
        hr = pFactory2.As(&pFactory1);
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory3> pFactory3;
        hr = pFactory2.As(&pFactory3);
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory4> pFactory4;
        hr = pFactory2.As(&pFactory4);
        if(FAILED(hr)) { return 0; }
    }

    // D3D機能レベルの一覧を用意
    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_12_1,
        D3D_FEATURE_LEVEL_12_0,
        D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_3,
        D3D_FEATURE_LEVEL_9_2,
        D3D_FEATURE_LEVEL_9_1,
    };
    D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_9_1;
    UINT deviceCreationFlag = 0;

    // D3D11デバイスおよびイメディエイトコンテキストの生成
    ComPtr<id3d11device> pDevice;
    ComPtr<id3d11devicecontext> pImmediateContext;
    hr = D3D11CreateDevice(
        nullptr,
        D3D_DRIVER_TYPE_HARDWARE,
        nullptr,
        deviceCreationFlag,
        featureLevels,
        _countof(featureLevels),
        D3D11_SDK_VERSION,
        pDevice.GetAddressOf(),
        &featureLevel,
        pImmediateContext.GetAddressOf()
    );
    if(FAILED(hr)) { return 0; }

    ComPtr<idxgidevice> pDXGIDevice;
    hr = pDevice.As(&pDXGIDevice);
    if(FAILED(hr)) { return 0; }

    // D3D11DeviceからDXGIDeviceを取得し,
    // DXGIDeviceからDXGIAdapterを取得し,
    // DXGIAdapterの親であるDXGIFactoryを取得する.
    // そこからIDXGIFactory1,2,3,4を取得する.
    {
        ComPtr<idxgiadapter> pDXGIAdapter;
        hr = pDXGIDevice->GetAdapter(
            pDXGIAdapter.GetAddressOf()
        );
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory> pFactory;
        hr = pDXGIAdapter->GetParent(
            IID_PPV_ARGS(pFactory.GetAddressOf())
        );
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory1> pFactory1;
        hr = pFactory.As(&pFactory1);
        if(FAILED(hr)) { return 0; }なn

        ComPtr<idxgifactory2> pFactory2;
        hr = pFactory.As(&pFactory2);
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory3> pFactory3;
        hr = pFactory.As(&pFactory3);
        if(FAILED(hr)) { return 0; }

        ComPtr<idxgifactory4> pFactory4;
        hr = pFactory.As(&pFactory4);
        if(FAILED(hr)) { return 0; }
    }

    return 0;
}

CreateDXGIFactoryでDXGIFactoryを生成した場合,以降のIDXGIFactory1,2,3,4のインターフェースをサポートしたオブジェクトにはならないようです.

ところで,D3D11DeviceからDXGIDeviceを取得できるって,どこかに関係の説明があるんでしょうか?
MSDNにサンプルがあったのでこうできるというのは分かったんですが,その関係性が書いてあるドキュメントが見つけられないんですよね.

2015/09/26 追記

IDXGIDeviceのドキュメントが2つあって,
こちらには情報が載っていなくて,
こちらには載っていました.
何なんだろう.

IDXGIAdapter,IDXGIAdapter1,IDXGIAdapter2,IDXGIAdapter3のインターフェース

IDXGIAdapter

メソッド名説明
CheckInterfaceSupport Checks whether the system supports a device interface for a graphics component.
EnumOutputs Enumerate adapter (video card) outputs.
GetDesc Gets a DXGI 1.0 description of an adapter (or video card).

IDXGIAdapter1

メソッド名説明
GetDesc1 Gets a DXGI 1.1 description of an adapter (or video card).

IDXGIAdapter2

メソッド名説明
GetDesc2 Gets a DXGI 1.2 description of an adapter or video card. This description includes information about the granularity at which the GPU can be preempted from performing its current task.

IDXGIAdapter3

メソッド名説明
QueryVideoMemoryInfo This method informs the process of the current budget and process usage.
RegisterHardwareContentProtectionTeardownStatusEvent Registers to receive notification of hardware content protection teardown events.
RegisterVideoMemoryBudgetChangeNotificationEvent This method establishes a correlation between a CPU synchronization object and the budget change event.
SetVideoMemoryReservation This method sends the minimum required physical memory for an application, to the OS.
UnregisterHardwareContentProtectionTeardownStatus Unregisters an event to stop it from receiving notification of hardware content protection teardown events.
UnregisterVideoMemoryBudgetChangeNotification This method stops notifying a CPU synchronization object whenever a budget change occurs. An application may switch back to polling the information regularly.

IDXGIFactory,IDXGIFactory1,IDXGIFactory2,IDXGIFactory3,IDXGIFactory4のインターフェース

IDXGIFactory

メソッド名 説明
CreateSoftwareAdapter Create an adapter interface that represents a software adapter.
CreateSwapChain Creates a swap chain.
Note Starting with Direct3D 11.1, we recommend not to use CreateSwapChain anymore to create a swap chain. Instead, use CreateSwapChainForHwnd, CreateSwapChainForCoreWindow, or CreateSwapChainForComposition depending on how you want to create the swap chain.
EnumAdapters Enumerates the adapters (video cards).
GetWindowAssociation Get the window through which the user controls the transition to and from full screen.
MakeWindowAssociation Allows DXGI to monitor an application's message queue for the alt-enter key sequence (which causes the application to switch from windowed to full screen or vice versa).

IDXGIFactory1

メソッド名 説明
EnumAdapters1 Enumerates both adapters (video cards) with or without outputs.
IsCurrent Informs an application of the possible need to re-enumerate adapters.

IDXGIFactory2

メソッド名 説明
CreateSwapChainForComposition Creates a swap chain that you can use to send Direct3D content into the DirectComposition API or the Windows.UI.Xaml framework to compose in a window.
CreateSwapChainForCoreWindow Creates a swap chain that is associated with the CoreWindow object for the output window for the swap chain.
CreateSwapChainForHwnd Creates a swap chain that is associated with an HWND handle to the output window for the swap chain.
GetSharedResourceAdapterLuid Identifies the adapter on which a shared resource object was created.
IsWindowedStereoEnabled Determines whether to use stereo mode.
RegisterOcclusionStatusEvent Registers to receive notification of changes in occlusion status by using event signaling.
RegisterOcclusionStatusWindow Registers an application window to receive notification messages of changes of occlusion status.
RegisterStereoStatusEvent Registers to receive notification of changes in stereo status by using event signaling.
RegisterStereoStatusWindow Registers an application window to receive notification messages of changes of stereo status.
UnregisterOcclusionStatus Unregisters a window or an event to stop it from receiving notification when occlusion status changes.
UnregisterStereoStatus Unregisters a window or an event to stop it from receiving notification when stereo status changes.

IDXGIFactory3

メソッド名 説明
GetCreationFlags DXGIオブジェクトが生成された際のフラグを取得する.

IDXGIFactory4

メソッド名 説明
EnumAdapterByLuid 指定されたLUIDのIDXGIAdapterを出力する.
EnumWarpAdapter Provides an adapter which can be provided to D3D12CreateDevice to use the WARP renderer.

2015年9月24日木曜日

Googleによる新しい圧縮アルゴリズム Brotliを試してみた.

Google、新しい圧縮アルゴリズム「Brotli」公開 (マイナビニュース)

google/brotli (GitHub)

GitHubでコードが公開されていたので,さっそく試してみました.

このコードは,Windows 10上のVisual Studio 2015 Communityで試しています.

  • main.cpp
  • dec (brotliのdecフォルダをコピー)
  • enc (brotliのencフォルダをコピー)

decとencをコピーした上で,プロジェクトに全てのファイルを組み込みます.
この際に,decとencには一部同名のファイルがあるため,オブジェクトファイルが被らないように,
出力フォルダを分けておきます.

後は,次のようなコードで圧縮と解凍ができます.


// main.cpp
#include <iostream>
#include <string>
#include <memory>
#include <cstdio>
#include <cstdlib>
#include <enc/streams.h>
#include <enc/encode.h>
#include <dec/streams.h>
#include <dec/decode.h>

int main(int argc, char * argv[])
{
    FILE * fout = fopen("main.cpp.brotli", "wb");
    if(!fout) { return -1; }

    FILE * fin = fopen("main.cpp", "rb");
    if(!fin) { return -1; }

    fseek(fin, 0, SEEK_END);
    auto size = ftell(fin);
    fseek(fin, 0, SEEK_SET);

    {
        brotli::BrotliFileOut bfout(fout);
        brotli::BrotliFileIn bfin(fin, size);

        // 圧縮時の設定ができる
        brotli::BrotliParams params;

        // true of falseが返る
        if(brotli::BrotliCompress(params, &bfin, &bfout))
        {
            std::cout << "圧縮に成功しました." << std::endl;
        }
        else
        {
            std::cerr << "圧縮に失敗しました." << std::endl;
            return -1;
        }
    }

    fclose(fout);
    fclose(fin);

    fin = fopen("main.cpp.brotli", "rb");
    fseek(fin, 0, SEEK_END);
    auto compressed_size = ftell(fin);
    fseek(fin, 0, SEEK_SET);
    std::string buffer;

    {
        std::unique_ptr<char[]> buffer(new char[size + 1]);
        buffer[size] = '\0';

        // メモリ出力用の構造体
        BrotliMemOutput output;

        // 解凍関数呼び出し
        auto result = BrotliDecompress(
            BrotliFileInput(fin),
            BrotliInitMemOutput(
                reinterpret_cast<uint8_t *>(buffer.get()),
                size,
                &output
            )
        );

        switch(result)
        {
        case BROTLI_RESULT_ERROR:
            std::cerr << "何らかのエラーが発生しました." << std::endl;
            return -1;
        case BROTLI_RESULT_NEEDS_MORE_INPUT:
            std::cerr << "解凍に必要な入力が不足しています." << std::endl;
            return -1;
        case BROTLI_RESULT_NEEDS_MORE_OUTPUT:
            std::cerr << "解凍先のバッファが不足しています." << std::endl;
            return -1;
        case BROTLI_RESULT_SUCCESS:
            std::cout << "解凍に成功しました." << std::endl;
            break;
        default:
            std::cerr << "未知のエラーが発生しました." << std::endl;
            return -1;
        }

        std::cout << buffer.get() << std::endl;
    }

    fclose(fin);

    return system("pause");
}

軽く触ってみた感じで,圧縮と解凍でAPIに対称性が無い感じがする(片方は名前空間に入っていて,もう片方は入っていない,だったり,入出力用のストリームの構造であったり)ので,
そのうちAPIは変更されるんじゃないかなぁ,という気がします.

結果はこんな感じです.
圧縮方法 結果サイズ (バイト)
無圧縮 2,487
brotli 728
zip 1,054

BrotliParamsに設定する値がデフォルトでは一番圧縮率が高くなる(その分処理が重い)になっているので,
その辺変更すると多少変わるかもしれませんが,デフォルトだと単なるzip圧縮よりも圧縮されていますね.