# The GPU interface, its test double, and the platform backend.
add_library(gpu_fake OBJECT fake/fake_device.cpp)
target_include_directories(gpu_fake PUBLIC ${POP_ROOT} ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_options(gpu_fake PRIVATE ${POP_WARN_STRICT})
pop_optimize(gpu_fake 1)

if(NOT IOS AND NOT ANDROID)
add_executable(d3d9_trace_tests tests/d3d9_trace_tests.cpp)
target_compile_options(d3d9_trace_tests PRIVATE ${POP_WARN_STRICT})
pop_optimize(d3d9_trace_tests 1)
pop_test_binary(d3d9_trace_tests)
add_test(NAME d3d9_trace_tests COMMAND d3d9_trace_tests WORKING_DIRECTORY ${POP_ROOT})
set_tests_properties(d3d9_trace_tests PROPERTIES LABELS nogame)

add_executable(shader_warm_queue_tests tests/shader_warm_queue_tests.cpp)
target_compile_options(shader_warm_queue_tests PRIVATE ${POP_WARN_STRICT})
pop_optimize(shader_warm_queue_tests 1)
pop_test_binary(shader_warm_queue_tests)
add_test(NAME shader_warm_queue_tests COMMAND shader_warm_queue_tests WORKING_DIRECTORY ${POP_ROOT})
set_tests_properties(shader_warm_queue_tests PROPERTIES LABELS nogame)

add_executable(pipeline_warm_spec_tests tests/pipeline_warm_spec_tests.cpp)
target_compile_options(pipeline_warm_spec_tests PRIVATE ${POP_WARN_STRICT})
pop_optimize(pipeline_warm_spec_tests 1)
pop_test_binary(pipeline_warm_spec_tests)
add_test(NAME pipeline_warm_spec_tests COMMAND pipeline_warm_spec_tests WORKING_DIRECTORY ${POP_ROOT})
set_tests_properties(pipeline_warm_spec_tests PROPERTIES LABELS nogame)

add_executable(gpu_fake_tests fake/tests/gpu_fake_tests.cpp)
target_link_libraries(gpu_fake_tests PRIVATE gpu_fake)
target_compile_options(gpu_fake_tests PRIVATE ${POP_WARN_STRICT})
pop_optimize(gpu_fake_tests 1)
pop_test_binary(gpu_fake_tests)
add_test(NAME gpu_fake_tests COMMAND gpu_fake_tests WORKING_DIRECTORY ${POP_ROOT})
set_tests_properties(gpu_fake_tests PROPERTIES LABELS nogame)
endif()

if(EMSCRIPTEN)
  # The web renders through the browser's WebGPU and nothing else.
  add_library(gpu_backend STATIC gpu_factory.cpp webgpu/webgpu_device.cpp)
  set_target_properties(gpu_backend PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${POP_ARCHIVE_DIR})
  target_include_directories(gpu_backend PUBLIC ${POP_ROOT} ${CMAKE_CURRENT_SOURCE_DIR})
  target_compile_options(gpu_backend PRIVATE ${POP_WARN_HOST})
  target_compile_options(gpu_backend PUBLIC --use-port=emdawnwebgpu)
  target_link_options(gpu_backend PUBLIC --use-port=emdawnwebgpu)
  target_link_libraries(gpu_backend PUBLIC recomp_platform)
  pop_optimize(gpu_backend 1)
  return()
endif()

# The Vulkan backend builds everywhere; the loader is found at run time.
add_library(volk OBJECT ${POP_ROOT}/third_party/volk/volk.c)
target_include_directories(volk PUBLIC ${POP_ROOT}/third_party/volk ${POP_ROOT}/third_party/vulkan-headers/include)
target_compile_definitions(volk PUBLIC VK_NO_PROTOTYPES)
pop_optimize(volk 2)

add_library(gpu_vulkan OBJECT vulkan/vulkan_loader.cpp vulkan/vulkan_device.cpp vulkan/vulkan_pipeline.cpp
                               vulkan/vulkan_swapchain.cpp)
target_link_libraries(gpu_vulkan PUBLIC volk)
target_include_directories(gpu_vulkan PUBLIC ${POP_ROOT} ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_options(gpu_vulkan PRIVATE ${POP_WARN_HOST})
pop_link_sdl(gpu_vulkan)
if(NOT WIN32 AND NOT APPLE)
  target_link_libraries(gpu_vulkan PUBLIC dl)
endif()
if(ANDROID)
  target_link_libraries(gpu_vulkan PUBLIC vulkan)
endif()
pop_optimize(gpu_vulkan 2)

# gpu_backend: every backend this platform has plus the factory, as one
# static library so indirect consumers get the objects. Hosts and tests link
# this, never a backend directly.
set(POP_GPU_BACKEND_OBJECTS $<TARGET_OBJECTS:gpu_vulkan> $<TARGET_OBJECTS:volk>)
if(APPLE)
  add_library(gpu_metal OBJECT metal/metal_device.mm metal/metal_surface.mm)
  target_compile_options(gpu_metal PRIVATE ${POP_WARN_HOST} $<$<COMPILE_LANGUAGE:OBJCXX>:-fobjc-arc>)
  target_include_directories(gpu_metal PUBLIC ${POP_ROOT} ${CMAKE_CURRENT_SOURCE_DIR})
  pop_link_sdl(gpu_metal)
  pop_optimize(gpu_metal 2)
  list(APPEND POP_GPU_BACKEND_OBJECTS $<TARGET_OBJECTS:gpu_metal>)
endif()
add_library(gpu_backend STATIC gpu_factory.cpp ${POP_GPU_BACKEND_OBJECTS})
set_target_properties(gpu_backend PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${POP_ARCHIVE_DIR})
target_include_directories(gpu_backend PUBLIC ${POP_ROOT} ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_options(gpu_backend PRIVATE ${POP_WARN_HOST})
target_link_libraries(gpu_backend PUBLIC recomp_platform)
pop_link_sdl(gpu_backend)
if(NOT WIN32 AND NOT APPLE)
  target_link_libraries(gpu_backend PUBLIC dl)
endif()
if(ANDROID)
  # Object inclusion above does not carry gpu_vulkan's link dependencies.
  target_link_libraries(gpu_backend PUBLIC vulkan)
endif()
if(APPLE)
  target_link_libraries(gpu_backend PUBLIC "-framework Metal" "-framework QuartzCore" "-framework CoreVideo"
                                           "-framework CoreGraphics" "-framework Foundation")
endif()
pop_optimize(gpu_backend 1)

# The contract suite, once per backend. `gpu` is the platform's default
# backend; `moltenvk` is Vulkan on Apple, which needs MoltenVK installed.
if(NOT IOS AND NOT ANDROID)
function(pop_gpu_contract_test target backend label)
  add_executable(${target} tests/gpu_contract_tests.cpp)
  target_link_libraries(${target} PRIVATE gpu_backend)
  target_compile_definitions(${target} PRIVATE POP_GPU_TEST_BACKEND="${backend}")
  target_compile_options(${target} PRIVATE ${POP_WARN_STRICT})
  pop_optimize(${target} 1)
  pop_test_binary(${target})
  add_test(NAME ${target} COMMAND ${target} WORKING_DIRECTORY ${POP_ROOT})
  set_tests_properties(${target} PROPERTIES LABELS ${label})
endfunction()
if(APPLE)
  pop_gpu_contract_test(gpu_metal_tests metal gpu)
  pop_gpu_contract_test(gpu_vulkan_tests vulkan moltenvk)
  # Explicit, private shader-corpus audit. It is built by the test wrapper but
  # never run by CTest: the caller must supply their own shader bytecode.
  add_executable(d3d9_shader_corpus metal/tests/d3d9_shader_corpus.mm
    ${POP_ROOT}/dx/d3d9_shader.cpp ${POP_ROOT}/dx/d3d9_shadergen.cpp)
  target_compile_options(d3d9_shader_corpus PRIVATE ${POP_WARN_HOST}
    $<$<COMPILE_LANGUAGE:OBJCXX>:-fobjc-arc>)
  target_link_libraries(d3d9_shader_corpus PRIVATE "-framework Metal" "-framework Foundation")
  pop_optimize(d3d9_shader_corpus 1)
  pop_test_binary(d3d9_shader_corpus)
else()
  pop_gpu_contract_test(gpu_vulkan_tests vulkan gpu)
endif()
endif()
