diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1237432d..181b39db 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -530,6 +530,13 @@ endif()
 
 target_include_directories(shadps4 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
 
+# Shaders sources
+set(HOST_SHADERS_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/src/video_core/host_shaders)
+
+add_subdirectory(${HOST_SHADERS_INCLUDE})
+add_dependencies(shadps4 host_shaders)
+target_include_directories(shadps4 PRIVATE ${HOST_SHADERS_INCLUDE})
+
 if (ENABLE_QT_GUI)
     set_target_properties(shadps4 PROPERTIES
         WIN32_EXECUTABLE ON
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
new file mode 100644
index 00000000..04ecca7d
--- /dev/null
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -0,0 +1,43 @@
+# Copyright 2023 Citra Emulator Project
+# Licensed under GPLv2 or any later version
+# Refer to the license.txt file included.
+
+set(SHADER_FILES
+    detile_m8x1.comp
+    detile_m8x4.comp
+)
+
+set(SHADER_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/include)
+set(SHADER_DIR ${SHADER_INCLUDE}/video_core/host_shaders)
+set(HOST_SHADERS_INCLUDE ${SHADER_INCLUDE} PARENT_SCOPE)
+
+set(INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/source_shader.h.in)
+set(HEADER_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/StringShaderHeader.cmake)
+
+foreach(FILENAME IN ITEMS ${SHADER_FILES})
+    string(REPLACE "." "_" SHADER_NAME ${FILENAME})
+    set(SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME})
+    set(SOURCE_HEADER_FILE ${SHADER_DIR}/${SHADER_NAME}.h)
+    add_custom_command(
+        OUTPUT
+            ${SOURCE_HEADER_FILE}
+        COMMAND
+            ${CMAKE_COMMAND} -P ${HEADER_GENERATOR} ${SOURCE_FILE} ${SOURCE_HEADER_FILE} ${INPUT_FILE}
+        MAIN_DEPENDENCY
+            ${SOURCE_FILE}
+        DEPENDS
+            ${INPUT_FILE}
+            # HEADER_GENERATOR should be included here but msbuild seems to assume it's always modified
+    )
+    set(SHADER_HEADERS ${SHADER_HEADERS} ${SOURCE_HEADER_FILE})
+endforeach()
+
+set(SHADER_SOURCES ${SHADER_FILES})
+list(APPEND SHADER_SOURCES ${GLSL_INCLUDES})
+
+add_custom_target(host_shaders
+    DEPENDS
+        ${SHADER_HEADERS}
+    SOURCES
+        ${SHADER_SOURCES}
+)
diff --git a/src/video_core/host_shaders/StringShaderHeader.cmake b/src/video_core/host_shaders/StringShaderHeader.cmake
new file mode 100644
index 00000000..9f752553
--- /dev/null
+++ b/src/video_core/host_shaders/StringShaderHeader.cmake
@@ -0,0 +1,36 @@
+# SPDX-FileCopyrightText: 2020 yuzu Emulator Project
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(SOURCE_FILE ${CMAKE_ARGV3})
+set(HEADER_FILE ${CMAKE_ARGV4})
+set(INPUT_FILE ${CMAKE_ARGV5})
+
+get_filename_component(CONTENTS_NAME ${SOURCE_FILE} NAME)
+string(REPLACE "." "_" CONTENTS_NAME ${CONTENTS_NAME})
+string(TOUPPER ${CONTENTS_NAME} CONTENTS_NAME)
+
+FILE(READ ${SOURCE_FILE} line_contents)
+
+# Replace double quotes with single quotes,
+# as double quotes will be used to wrap the lines
+STRING(REGEX REPLACE "\"" "'" line_contents "${line_contents}")
+
+# CMake separates list elements with semicolons, but semicolons
+# are used extensively in the shader code.
+# Replace with a temporary marker, to be reverted later.
+STRING(REGEX REPLACE ";" "{{SEMICOLON}}" line_contents "${line_contents}")
+
+# Make every line an individual element in the CMake list.
+STRING(REGEX REPLACE "\n" ";" line_contents "${line_contents}")
+
+# Build the shader string, wrapping each line in double quotes.
+foreach(line IN LISTS line_contents)
+    string(CONCAT CONTENTS "${CONTENTS}" \"${line}\\n\"\n)
+endforeach()
+
+# Revert the original semicolons in the source.
+STRING(REGEX REPLACE "{{SEMICOLON}}" ";" CONTENTS "${CONTENTS}")
+
+get_filename_component(OUTPUT_DIR ${HEADER_FILE} DIRECTORY)
+make_directory(${OUTPUT_DIR})
+configure_file(${INPUT_FILE} ${HEADER_FILE} @ONLY)
diff --git a/src/video_core/host_shaders/source_shader.h.in b/src/video_core/host_shaders/source_shader.h.in
new file mode 100644
index 00000000..4d1b0702
--- /dev/null
+++ b/src/video_core/host_shaders/source_shader.h.in
@@ -0,0 +1,15 @@
+// Copyright 2022 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string_view>
+
+namespace HostShaders {
+
+constexpr std::string_view @CONTENTS_NAME@ = {
+@CONTENTS@
+};
+
+} // namespace HostShaders