これから行う描画処理はメモリの中の話とはいえ、絵を描くキャンバスにあたるものが必要です。
とりあえず幅と高さは決めてしまいましょう。
const uint32_t screenWidth = 640;
const uint32_t screenHeight = 480;
Vulkanにおいて画像は vk::Image
というオブジェクトで表されます。これはvk::Device
の createImage
メソッドで作成できます。
vk::ImageCreateInfo imgCreateInfo;
imgCreateInfo.imageType = vk::ImageType::e2D;
imgCreateInfo.extent = vk::Extent3D(screenWidth, screenHeight, 1);
imgCreateInfo.mipLevels = 1;
imgCreateInfo.arrayLayers = 1;
imgCreateInfo.format = vk::Format::eR8G8B8A8Unorm;
imgCreateInfo.tiling = vk::ImageTiling::eLinear;
imgCreateInfo.initialLayout = vk::ImageLayout::eUndefined;
imgCreateInfo.usage = vk::ImageUsageFlagBits::eColorAttachment;
imgCreateInfo.sharingMode = vk::SharingMode::eExclusive;
imgCreateInfo.samples = vk::SampleCountFlagBits::e1;
vk::UniqueImage image = device->createImageUnique(imgCreateInfo);
vk::ImageCreateInfo
とかいうばかでかい初期化用構造体がありますね。ここでは要点となるメンバの説明だけ書くにとどめて、詳細については必要に応じておいおい解説していくことにします。気になるという人は公式ドキュメントを見てみてください。
imageType
には画像の次元を指定します。1次元から3次元まで指定できます。2次元以外の画像ってなんじゃらほいという感じですが、Rampテクスチャやvoxelなど、普通に使い道があります。ここでは普通の2次元の画像のため vk::ImageType::e2D
を指定しています。
extent
には画像のサイズを指定します。ここでは640×480を指定しています。最大3次元の画像を扱うためvk::Extent3D
による指定ですが、今回は2次元であるため、第3引数の奥行には1を指定しています。640x480x1のマス目と思ってください。
format
には画素のフォーマットの種類を指定します。どのように各ピクセルが色を保存しているかの情報です。いろいろなフォーマットが存在するのですが、今回はひとまずR8G8B8A8Unorm
という形式を指定しています。RGB+A(透明度)をこの順でそれぞれ8bitで保存する形式になります。Unormの部分については今は無視しましょう。
これで画像オブジェクトを作成することができました。しかしこの段階ではまだ画像にメモリが割り当てられていません。メモリを割り当ててやらないと画像データを記録することは出来ません。
この節ではイメージの作成をやりました。次節ではメモリの確保をやります。この節のコード
#include <vulkan/vulkan.hpp>
#include <iostream>
#include <vector>
const uint32_t screenWidth = 640;
const uint32_t screenHeight = 480;
int main() {
vk::InstanceCreateInfo createInfo;
vk::UniqueInstance instance;
instance = vk::createInstanceUnique(createInfo);
std::vector<vk::PhysicalDevice> physicalDevices = instance->enumeratePhysicalDevices();
vk::PhysicalDevice physicalDevice;
bool existsSuitablePhysicalDevice = false;
uint32_t graphicsQueueFamilyIndex;
for (size_t i = 0; i < physicalDevices.size(); i++) {
std::vector<vk::QueueFamilyProperties> queueProps = physicalDevices[i].getQueueFamilyProperties();
bool existsGraphicsQueue = false;
for (size_t j = 0; j < queueProps.size(); j++) {
if (queueProps[j].queueFlags & vk::QueueFlagBits::eGraphics) {
existsGraphicsQueue = true;
graphicsQueueFamilyIndex = j;
break;
}
}
if (existsGraphicsQueue) {
physicalDevice = physicalDevices[i];
existsSuitablePhysicalDevice = true;
break;
}
}
if (!existsSuitablePhysicalDevice) {
std::cerr << "使用可能な物理デバイスがありません。" << std::endl;
return -1;
}
vk::DeviceCreateInfo devCreateInfo;
vk::DeviceQueueCreateInfo queueCreateInfo[1];
queueCreateInfo[0].queueFamilyIndex = graphicsQueueFamilyIndex;
queueCreateInfo[0].queueCount = 1;
float queuePriorities[1] = { 1.0 };
queueCreateInfo[0].pQueuePriorities = queuePriorities;
devCreateInfo.pQueueCreateInfos = queueCreateInfo;
devCreateInfo.queueCreateInfoCount = 1;
vk::UniqueDevice device = physicalDevice.createDeviceUnique(devCreateInfo);
vk::Queue graphicsQueue = device->getQueue(graphicsQueueFamilyIndex, 0);
vk::CommandPoolCreateInfo cmdPoolCreateInfo;
cmdPoolCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
vk::UniqueCommandPool cmdPool = device->createCommandPoolUnique(cmdPoolCreateInfo);
vk::CommandBufferAllocateInfo cmdBufAllocInfo;
cmdBufAllocInfo.commandPool = cmdPool.get();
cmdBufAllocInfo.commandBufferCount = 1;
cmdBufAllocInfo.level = vk::CommandBufferLevel::ePrimary;
std::vector<vk::UniqueCommandBuffer> cmdBufs =
device->allocateCommandBuffersUnique(cmdBufAllocInfo);
vk::ImageCreateInfo imgCreateInfo;
imgCreateInfo.imageType = vk::ImageType::e2D;
imgCreateInfo.extent = vk::Extent3D(screenWidth, screenHeight, 1);
imgCreateInfo.mipLevels = 1;
imgCreateInfo.arrayLayers = 1;
imgCreateInfo.format = vk::Format::eR8G8B8A8Unorm;
imgCreateInfo.tiling = vk::ImageTiling::eLinear;
imgCreateInfo.initialLayout = vk::ImageLayout::eColorAttachmentOptimal;
imgCreateInfo.usage = vk::ImageUsageFlagBits::eColorAttachment;
imgCreateInfo.sharingMode = vk::SharingMode::eExclusive;
imgCreateInfo.samples = vk::SampleCountFlagBits::e1;
vk::UniqueImage image = device->createImageUnique(imgCreateInfo);
vk::CommandBufferBeginInfo cmdBeginInfo;
cmdBufs[0]->begin(cmdBeginInfo);
// コマンドを記録
cmdBufs[0]->end();
vk::CommandBuffer submitCmdBuf[1] = { cmdBufs[0].get() };
vk::SubmitInfo submitInfo;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = submitCmdBuf;
graphicsQueue.submit({ submitInfo }, nullptr);
return 0;
}
cmake_minimum_required(VERSION 3.22)
project(vulkan-test)
set(CMAKE_CXX_STANDARD 17)
add_executable(app main.cpp)
find_package(Vulkan REQUIRED)
target_include_directories(app PRIVATE ${Vulkan_INCLUDE_DIRS})
target_link_libraries(app PRIVATE ${Vulkan_LIBRARIES})