// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
/**
 * @class   vtkWebGPURenderPipelineCache
 * @brief   Class to create and retrieve render pipelines based on a given key.
 *
 * vtkWebGPURenderPipelineCache is meant to reduce the cost of creating render
 * pipelines by caching `wgpu::RenderPipeline` instances that are similar.
 * This class generates a unique hash for a given `wgpu::RenderPipelineDescriptor`
 * and a shader source string.
 *
 * The key is built from certain properties. It is guaranteed that the combination
 * of a collection of properties result in a unique pipeline. Here are the properties
 * which are used to generate a hash.
 * 1. Shader source string
 * 2. Culling mode
 * 3. Topology
 *
 * The hash is generated by stringifying the properties and generating a hash using
 * md5sum.
 *
 * This class can be made to write the final processed shader source code
 * to the filesystem as it is extremely useful to inspect the actual shader source code used by a
 * pipeline.
 *
 * Set the `VTK_WEBGPU_SHADER_DUMP_PREFIX` environment variable to the directory inside
 * which shader files will be written to. The name of the shader files will contain the pipeline
 * label and the extensions are named `.vert.wgsl`, `.frag.wgsl` for vertex shader source code and
 * fragment shader source code respectively.
 *
 * @sa
 * vtkWebGPURenderer, vtkWebGPURenderWindow, vtkWebGPUPolyDataMapper
 */

#ifndef vtkWebGPURenderPipelineCache_h
#define vtkWebGPURenderPipelineCache_h

#include "vtkObject.h"

#include "vtkRenderingWebGPUModule.h" // for export macro
#include "vtkWrappingHints.h"         // For VTK_MARSHALAUTO
#include "vtk_wgpu.h"                 // for webgpu

VTK_ABI_NAMESPACE_BEGIN

class vtkWebGPURenderer;
class vtkWebGPURenderWindow;
class vtkWindow;

class VTKRENDERINGWEBGPU_EXPORT VTK_MARSHALAUTO vtkWebGPURenderPipelineCache : public vtkObject
{
public:
  static vtkWebGPURenderPipelineCache* New();
  vtkTypeMacro(vtkWebGPURenderPipelineCache, vtkObject);
  void PrintSelf(ostream& os, vtkIndent indent) override;

  /**
   * Reset the pipeline cache.
   * @param window The window associated with the cache.
   */
  void ReleaseGraphicsResources(vtkWindow* window);

  /**
   * Get a render pipeline associated with the given hash.
   * @param key The unique hash of the render pipeline to retrieve.
   */
  wgpu::RenderPipeline GetRenderPipeline(const std::string& key);

  /**
   * Get a unique hash for the given combination of render pipeline descriptor and shader source.
   * @param descriptor The render pipeline descriptor to use.
   * @param shaderSource The source code for the shader.
   */
  std::string GetPipelineKey(wgpu::RenderPipelineDescriptor* descriptor, const char* shaderSource);

  /**
   * Get a unique hash for the given combination of render pipeline descriptor and shader source.
   * @param descriptor The render pipeline descriptor to use.
   * @param vertexShaderSource The source code for the vertex shader.
   * @param fragmentShaderSource The source code for the fragment shader.
   */
  std::string GetPipelineKey(wgpu::RenderPipelineDescriptor* descriptor,
    const char* vertexShaderSource, const char* fragmentShaderSource);

  /**
   * Create a render pipeline for the given combination of render pipeline descriptor and shader
   * source.
   * @param descriptor The render pipeline descriptor to use.
   * @param wgpuRenderWindow The WebGPU render window to use for creating the pipeline.
   * @param shaderSource The source code for the shader.
   */
  void CreateRenderPipeline(wgpu::RenderPipelineDescriptor* descriptor,
    vtkWebGPURenderWindow* wgpuRenderWindow, const char* shaderSource);

  /**
   * Create a render pipeline for the given combination of render pipeline descriptor and shader
   * source.
   * @param descriptor The render pipeline descriptor to use.
   * @param wgpuRenderWindow The WebGPU render window to use for creating the pipeline.
   * @param vertexShaderSource The source code for the vertex shader.
   * @param fragmentShaderSource The source code for the fragment shader.
   */
  void CreateRenderPipeline(wgpu::RenderPipelineDescriptor* descriptor,
    vtkWebGPURenderWindow* wgpuRenderWindow, const char* vertexShaderSource,
    const char* fragmentShaderSource);

  /**
   * Substitute all occurrences of `search` with `replace` in `source`.
   * @param source The string in which to perform the substitution.
   * @param search The substring to search for.
   * @param replace The substring to replace `search` with.
   * @param all If true, replace all occurrences of `search` with `replace`.
   */
  static bool Substitute(
    std::string& source, const std::string& search, const std::string& replace, bool all);

  /**
   * Destroy the render pipeline associated with the given hash.
   * @param key The unique hash of the render pipeline to destroy.
   */
  void DestroyRenderPipeline(const std::string& key);

protected:
  vtkWebGPURenderPipelineCache();
  ~vtkWebGPURenderPipelineCache() override;

private:
  vtkWebGPURenderPipelineCache(const vtkWebGPURenderPipelineCache&) = delete;
  void operator=(const vtkWebGPURenderPipelineCache&) = delete;

  class vtkInternals;
  std::unique_ptr<vtkInternals> Internals;
};

VTK_ABI_NAMESPACE_END
#endif
