summaryrefslogtreecommitdiff
path: root/src/gpu/texture_manager.cc
blob: 4240245d2ab38450b261fe048bb27b2a1d65f14e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// This file is part of the 64k demo project.
// It implements the TextureManager.

#include "gpu/texture_manager.h"
#include <iostream>
#include <vector>

#if defined(DEMO_CROSS_COMPILE_WIN32)
// Old API
#define WGPU_TEX_COPY_INFO WGPUImageCopyTexture
#define WGPU_TEX_DATA_LAYOUT WGPUTextureDataLayout
#else
// New API
#define WGPU_TEX_COPY_INFO WGPUTexelCopyTextureInfo
#define WGPU_TEX_DATA_LAYOUT WGPUTexelCopyBufferLayout
#endif

void TextureManager::init(WGPUDevice device, WGPUQueue queue) {
  device_ = device;
  queue_ = queue;
}

void TextureManager::shutdown() {
  for (auto& pair : textures_) {
    wgpuTextureViewRelease(pair.second.view);
    wgpuTextureRelease(pair.second.texture);
  }
  textures_.clear();
}

void TextureManager::create_procedural_texture(
    const std::string& name, const ProceduralTextureDef& def) {
  // 1. Generate Data on CPU
  std::vector<uint8_t> pixel_data;
  pixel_data.resize(def.width * def.height * 4);
  def.gen_func(pixel_data.data(), def.width, def.height, def.params.data(),
               (int)def.params.size());

  WGPUExtent3D tex_size = {(uint32_t)def.width, (uint32_t)def.height, 1};

  // 2. Create GPU Texture
  WGPUTextureDescriptor tex_desc = {};
  tex_desc.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
  tex_desc.dimension = WGPUTextureDimension_2D;
  tex_desc.size = tex_size;
  tex_desc.format = WGPUTextureFormat_RGBA8Unorm;
  tex_desc.mipLevelCount = 1;
  tex_desc.sampleCount = 1;
#if defined(DEMO_CROSS_COMPILE_WIN32)
  tex_desc.label = nullptr;
#else
  tex_desc.label = {nullptr, 0};
#endif

  WGPUTexture texture = wgpuDeviceCreateTexture(device_, &tex_desc);

  // 3. Upload Data
  WGPU_TEX_COPY_INFO destination = {};
  destination.texture = texture;
  destination.mipLevel = 0;
  destination.origin = {0, 0, 0};
  destination.aspect = WGPUTextureAspect_All;

  WGPU_TEX_DATA_LAYOUT source_layout = {};
  source_layout.offset = 0;
  source_layout.bytesPerRow = def.width * 4;
  source_layout.rowsPerImage = def.height;

  wgpuQueueWriteTexture(queue_, &destination, pixel_data.data(),
                        pixel_data.size(), &source_layout, &tex_size);

  // 4. Create View
  WGPUTextureViewDescriptor view_desc = {};
  view_desc.format = WGPUTextureFormat_RGBA8Unorm;
  view_desc.dimension = WGPUTextureViewDimension_2D;
  view_desc.baseMipLevel = 0;
  view_desc.mipLevelCount = 1;
  view_desc.baseArrayLayer = 0;
  view_desc.arrayLayerCount = 1;
  view_desc.aspect = WGPUTextureAspect_All;

  WGPUTextureView view = wgpuTextureCreateView(texture, &view_desc);

  // 5. Store
  GpuTexture gpu_tex;
  gpu_tex.texture = texture;
  gpu_tex.view = view;
  gpu_tex.width = def.width;
  gpu_tex.height = def.height;

  textures_[name] = gpu_tex;

#if !defined(STRIP_ALL)
  std::cout << "Generated procedural texture: " << name << " (" << def.width
            << "x" << def.height << ")" << std::endl;
#endif
}

WGPUTextureView TextureManager::get_texture_view(const std::string& name) {
  auto it = textures_.find(name);
  if (it != textures_.end()) {
    return it->second.view;
  }
  return nullptr;
}