Add Vulkan backend

This commit is contained in:
Jupeyy 2022-03-20 18:04:00 +01:00
parent e572704963
commit fbeba9eb5f
43 changed files with 8294 additions and 159 deletions

View file

@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest, ubuntu-18.04]
os: [ubuntu-latest, macOS-latest, windows-latest, ubuntu-20.04]
include:
- os: ubuntu-latest
cmake-args: -G Ninja
@ -23,7 +23,7 @@ jobs:
env:
CFLAGS: -Wdeclaration-after-statement -Werror
CXXFLAGS: -Werror
- os: ubuntu-18.04
- os: ubuntu-20.04
cmake-path: /usr/bin/
cmake-args: -G Ninja
package-file: "*-linux_x86_64.tar.xz"
@ -57,7 +57,7 @@ jobs:
if: contains(matrix.os, 'ubuntu')
run: |
sudo apt-get update -y
sudo apt-get install pkg-config cmake ninja-build libfreetype6-dev libnotify-dev libsdl2-dev libsqlite3-dev libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev libx264-dev -y
sudo apt-get install pkg-config cmake ninja-build libfreetype6-dev libnotify-dev libsdl2-dev libsqlite3-dev libvulkan-dev glslang-tools spirv-tools libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev libx264-dev -y
- name: Prepare Linux (fancy)
if: contains(matrix.os, 'ubuntu') && matrix.fancy
@ -78,7 +78,7 @@ jobs:
if: contains(matrix.os, 'macOS')
run: |
brew update || true
brew install pkg-config sdl2 ffmpeg python3 ninja
brew install pkg-config sdl2 ffmpeg python3 ninja molten-vk vulkan-headers glslang spirv-tools
brew upgrade freetype
pip3 install dmgbuild
sudo rm -rf /Library/Developer/CommandLineTools

View file

@ -20,7 +20,7 @@ jobs:
- name: Install clang-tidy
run: |
sudo apt-get update -y
sudo apt-get install pkg-config cmake ninja-build libfreetype6-dev libnotify-dev libsdl2-dev libsqlite3-dev libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev libx264-dev clang-tidy -y
sudo apt-get install pkg-config cmake ninja-build libfreetype6-dev libnotify-dev libsdl2-dev libsqlite3-dev libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev libx264-dev clang-tidy libvulkan-dev glslang-tools spirv-tools -y
- name: Build with clang-tidy
run: |
mkdir clang-tidy

View file

@ -38,7 +38,7 @@ jobs:
if: matrix.language == 'cpp'
run: |
sudo apt-get update -y
sudo apt-get install pkg-config cmake ninja-build libfreetype6-dev libnotify-dev libsdl2-dev libsqlite3-dev libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev libx264-dev libmariadbclient-dev libwebsockets-dev -y
sudo apt-get install pkg-config cmake ninja-build libfreetype6-dev libnotify-dev libsdl2-dev libsqlite3-dev libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev libx264-dev libmariadbclient-dev libwebsockets-dev libvulkan-dev glslang-tools spirv-tools -y
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL

View file

@ -19,7 +19,7 @@ jobs:
- name: Prepare
run: |
sudo apt-get update -y
sudo apt-get install clang-format imagemagick ddnet-tools shellcheck pkg-config cmake ninja-build libfreetype6-dev libnotify-dev libsdl2-dev libsqlite3-dev libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev libx264-dev pylint3 python3-clang -y
sudo apt-get install clang-format imagemagick ddnet-tools shellcheck pkg-config cmake ninja-build libfreetype6-dev libnotify-dev libsdl2-dev libsqlite3-dev libavcodec-dev libavformat-dev libavutil-dev libswresample-dev libswscale-dev libx264-dev pylint3 python3-clang libvulkan-dev glslang-tools spirv-tools -y
mkdir release
cd release
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DDOWNLOAD_GTEST=OFF -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE=. ..

View file

@ -93,9 +93,14 @@ else()
endif()
set(AUTO_DEPENDENCIES_DEFAULT OFF)
set(AUTO_VULKAN_BACKEND ON)
if(TARGET_OS STREQUAL "windows")
set(AUTO_DEPENDENCIES_DEFAULT ON)
elseif(TARGET_OS STREQUAL "linux")
if(TARGET_CPU_ARCHITECTURE STREQUAL "x86")
set(AUTO_VULKAN_BACKEND OFF)
endif()
elseif(TARGET_OS STREQUAL "mac")
set(AUTO_VULKAN_BACKEND OFF)
endif()
option(WEBSOCKETS "Enable websockets support" OFF)
@ -116,6 +121,7 @@ option(DISCORD "Enable Discord rich presence support" OFF)
option(DISCORD_DYNAMIC "Enable discovering Discord rich presence libraries at runtime (Linux only)" OFF)
option(PREFER_BUNDLED_LIBS "Prefer bundled libraries over system libraries" ${AUTO_DEPENDENCIES_DEFAULT})
option(DEV "Don't generate stuff necessary for packaging" OFF)
option(VULKAN "Enable the vulkan backend" ${AUTO_VULKAN_BACKEND})
option(EXCEPTION_HANDLING "Enable exception handling (only works with Windows as of now)" OFF)
@ -467,6 +473,15 @@ if(TARGET_OS AND TARGET_OS STREQUAL "mac")
find_program(DMGBUILD dmgbuild)
endif()
set(VULKAN_SHADER_FILE_LIST "" CACHE STRING "Vulkan shader file list")
if(VULKAN)
find_package(Vulkan)
include(cmake/BuildVulkanShaders.cmake)
else()
set(VULKAN_LIBRARIES)
set(VULKAN_INCLUDE_DIRS)
endif()
message(STATUS "******** ${CMAKE_PROJECT_NAME} ********")
set(TARGET "Target OS: ${TARGET_OS} ${CMAKE_SYSTEM_PROCESSOR}")
if(TARGET_OS STREQUAL "mac")
@ -528,6 +543,10 @@ if(WEBSOCKETS)
show_dependency_status("Websockets" WEBSOCKETS)
endif()
if(VULKAN)
show_dependency_status("Vulkan" VULKAN)
endif()
if(CLIENT AND NOT(CURL_FOUND))
message(SEND_ERROR "You must install Curl to compile DDNet")
endif()
@ -591,6 +610,10 @@ if(NOT(GTEST_FOUND))
endif()
endif()
if(VULKAN AND CLIENT AND NOT(VULKAN_FOUND))
message(SEND_ERROR "You must install Vulkan libraries to compile the DDNet client")
endif()
if(TARGET_OS STREQUAL "windows")
set(PLATFORM_CLIENT)
set(PLATFORM_CLIENT_LIBS opengl32 winmm)
@ -1277,6 +1300,20 @@ set(EXPECTED_DATA
shader/text.vert
shader/tile.frag
shader/tile.vert
shader/vulkan/prim.frag
shader/vulkan/prim.vert
shader/vulkan/prim3d.frag
shader/vulkan/prim3d.vert
shader/vulkan/primex.frag
shader/vulkan/primex.vert
shader/vulkan/quad.frag
shader/vulkan/quad.vert
shader/vulkan/spritemulti.frag
shader/vulkan/spritemulti.vert
shader/vulkan/text.frag
shader/vulkan/text.vert
shader/vulkan/tile.frag
shader/vulkan/tile.vert
skins/Aoe4leg.png
skins/PaladiN.png
skins/antiantey.png
@ -1422,6 +1459,7 @@ set(COPY_FILES
${FFMPEG_COPY_FILES}
${WEBSOCKETS_COPY_FILES}
${DISCORDSDK_COPY_FILES}
${VULKAN_COPY_FILES}
${EXCEPTION_HANDLING_COPY_FILES}
)
file(COPY ${COPY_FILES} DESTINATION .)
@ -1775,6 +1813,8 @@ if(CLIENT)
backend/opengles/gles_class_defines.h
backend/opengles/opengles_sl.cpp
backend/opengles/opengles_sl_program.cpp
backend/vulkan/backend_vulkan.cpp
backend/vulkan/backend_vulkan.h
backend_sdl.cpp
backend_sdl.h
blocklist_driver.cpp
@ -1962,6 +2002,8 @@ if(CLIENT)
${OPUS_LIBRARIES}
${OGG_LIBRARIES}
${VULKAN_LIBRARIES}
${TARGET_STEAMAPI}
${PLATFORM_CLIENT_LIBS}
@ -2033,6 +2075,8 @@ if(CLIENT)
${FFMPEG_INCLUDE_DIRS}
${DISCORDSDK_INCLUDE_DIRS}
${VULKAN_INCLUDE_DIRS}
${PLATFORM_CLIENT_INCLUDE_DIRS}
)
@ -2065,6 +2109,10 @@ if(CLIENT)
target_compile_definitions(${TARGET_CLIENT} PRIVATE CONF_GLEW_HAS_CONTEXT_INIT)
endif()
if(VULKAN)
target_compile_definitions(${TARGET_CLIENT} PRIVATE CONF_BACKEND_VULKAN)
endif()
list(APPEND TARGETS_OWN ${TARGET_CLIENT})
list(APPEND TARGETS_LINK ${TARGET_CLIENT})
endif()
@ -2578,6 +2626,11 @@ set(CPACK_FILES
storage.cfg
${COPY_FILES}
)
set(CPACK_GEN_FILES
${VULKAN_SHADER_FILE_LIST}
)
if(TARGET_OS STREQUAL "windows")
list(APPEND CPACK_FILES other/config_directory.bat)
endif()
@ -2600,6 +2653,9 @@ if(NOT DEV)
install(FILES other/icons/DDNet_${SIZE}x${SIZE}x32.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}x${SIZE}/apps RENAME ddnet.png COMPONENT client)
install(FILES other/icons/DDNet-Server_${SIZE}x${SIZE}x32.png DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}x${SIZE}/apps RENAME ddnet-server.png COMPONENT server)
endforeach()
foreach(file ${VULKAN_SHADER_FILE_LIST})
install(FILES ${PROJECT_BINARY_DIR}/${file} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/ddnet/data/shader/vulkan COMPONENT client)
endforeach()
endif()
if(DEV)
@ -2610,7 +2666,8 @@ else()
set(EXTRA_ARGS DESTINATION ${CPACK_PACKAGE_FILE_NAME} COMPONENT portable EXCLUDE_FROM_ALL)
install(TARGETS ${CPACK_TARGETS} ${EXTRA_ARGS})
install(DIRECTORY ${CPACK_DIRS} ${EXTRA_ARGS})
install(FILES ${CPACK_FILES} ${EXTRA_ARGS})
set(CPACK_FILES_TMP ${CPACK_FILES} ${CPACK_GEN_FILES})
install(FILES ${CPACK_FILES_TMP} ${EXTRA_ARGS})
endif()
set(PACKAGE_TARGETS)
@ -2714,6 +2771,9 @@ foreach(ext zip tar.gz tar.xz)
foreach(file ${CPACK_FILES})
list(APPEND COPY_FILE_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/${file} ${TMPDIR}/)
endforeach()
foreach(file ${CPACK_GEN_FILES})
list(APPEND COPY_FILE_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/${file} ${TMPDIR}/${file})
endforeach()
foreach(dir ${CPACK_DIRS})
list(APPEND COPY_DIR_COMMANDS COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/${dir} ${TMPDIR}/${dir})
endforeach()
@ -2761,6 +2821,7 @@ unset(CPACK_SOURCE_FILES_INVERTED)
unset(CPACK_TARGETS)
unset(CPACK_DIRS)
unset(CPACK_FILES)
unset(CPACK_GEN_FILES)
include(CPack)

View file

@ -34,21 +34,21 @@ Dependencies on Linux / macOS
You can install the required libraries on your system, `touch CMakeLists.txt` and CMake will use the system-wide libraries by default. You can install all required dependencies and CMake on Debian or Ubuntu like this:
sudo apt install build-essential cmake git google-mock libcurl4-openssl-dev libssl-dev libfreetype6-dev libglew-dev libnotify-dev libogg-dev libopus-dev libopusfile-dev libpnglite-dev libsdl2-dev libsqlite3-dev libwavpack-dev python libx264-dev libavfilter-dev libavdevice-dev libavformat-dev libavcodec-extra libavutil-dev
sudo apt install build-essential cmake git google-mock libcurl4-openssl-dev libssl-dev libfreetype6-dev libglew-dev libnotify-dev libogg-dev libopus-dev libopusfile-dev libpnglite-dev libsdl2-dev libsqlite3-dev libwavpack-dev python libx264-dev libavfilter-dev libavdevice-dev libavformat-dev libavcodec-extra libavutil-dev libvulkan-dev glslang-tools spirv-tools
Or on CentOS, RedHat and AlmaLinux like this:
sudo yum install gcc gcc-c++ make cmake git python2 gtest-devel gmock-devel libcurl-devel openssl-devel freetype-devel glew-devel libnotify-devel libogg-devel opus-devel opusfile-devel pnglite-devel SDL2-devel sqlite-devel wavpack-devel libx264-devel ffmpeg-devel
sudo yum install gcc gcc-c++ make cmake git python2 gtest-devel gmock-devel libcurl-devel openssl-devel freetype-devel glew-devel libnotify-devel libogg-devel opus-devel opusfile-devel pnglite-devel SDL2-devel sqlite-devel wavpack-devel libx264-devel ffmpeg-devel vulkan-devel glslang spirv-tools
Or on Arch Linux like this:
sudo pacman -S --needed base-devel cmake curl freetype2 git glew gmock libnotify opusfile python sdl2 sqlite wavpack x264 ffmpeg
sudo pacman -S --needed base-devel cmake curl freetype2 git glew gmock libnotify opusfile python sdl2 sqlite wavpack x264 ffmpeg vulkan-icd-loader vulkan-headers glslang spirv-tools
There is an [AUR package for pnglite](https://aur.archlinux.org/packages/pnglite/). For instructions on installing it, see [AUR packages installation instructions on ArchWiki](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages).
On macOS you can use [homebrew](https://brew.sh/) to install build dependencies like this:
brew install cmake freetype glew googletest opusfile SDL2 wavpack x264 ffmpeg
brew install cmake freetype glew googletest opusfile SDL2 wavpack x264 ffmpeg molten-vk vulkan-headers glslang spirv-tools
If you don't want to use the system libraries, you can pass the `-DPREFER_BUNDLED_LIBS=ON` parameter to cmake.
@ -109,6 +109,10 @@ Whether to optimize for development, speeding up the compilation process a littl
Whether to enable UPnP support for the server.
You need to install `libminiupnpc-dev` on Debian, `miniupnpc` on Arch Linux.
* **-DVULKAN=[ON|OFF]** <br>
Whether to enable the vulkan backend.
On Windows you need to install the Vulkan SDK and set the `VULKAN_SDK` environment flag accordingly.
* **-GNinja** <br>
Use the Ninja build system instead of Make. This automatically parallizes the build and is generally faster. Compile with `ninja` instead of `make`. Install Ninja with `sudo apt install ninja-build` on Debian, `sudo pacman -S --needed ninja` on Arch Linux.

View file

@ -0,0 +1,175 @@
find_program(GLSLANG_VALIDATOR_PROGRAM glslangValidator)
find_program(SPIRV_OPTIMIZER_PROGRAM spirv-opt)
set(GLSLANG_VALIDATOR_PROGRAM_FOUND TRUE)
if(NOT GLSLANG_VALIDATOR_PROGRAM)
set(GLSLANG_VALIDATOR_PROGRAM_FOUND FALSE)
if(TARGET_OS STREQUAL "windows")
if(${TARGET_CPU_ARCHITECTURE} STREQUAL "x86_64")
set(GLSLANG_VALIDATOR_PROGRAM "$ENV{VULKAN_SDK}/Bin/glslangValidator.exe")
else()
set(GLSLANG_VALIDATOR_PROGRAM "$ENV{VULKAN_SDK}/Bin32/glslangValidator.exe")
endif()
endif()
if(EXISTS ${GLSLANG_VALIDATOR_PROGRAM})
set(GLSLANG_VALIDATOR_PROGRAM_FOUND TRUE)
elseif(${TARGET_CPU_ARCHITECTURE} STREQUAL "x86_64")
set(GLSLANG_VALIDATOR_PROGRAM "${PROJECT_SOURCE_DIR}/ddnet-libs/vulkan/windows/lib64/glslangValidator.exe")
if(EXISTS ${GLSLANG_VALIDATOR_PROGRAM})
set(GLSLANG_VALIDATOR_PROGRAM_FOUND TRUE)
endif()
endif()
if(${GLSLANG_VALIDATOR_PROGRAM_FOUND} EQUAL FALSE)
message(FATAL_ERROR "glslangValidator binary was not found. Did you install the Vulkan SDK / packages ?")
endif()
endif()
set(SPIRV_OPTIMIZER_PROGRAM_FOUND TRUE)
if(NOT SPIRV_OPTIMIZER_PROGRAM)
set(SPIRV_OPTIMIZER_PROGRAM_FOUND FALSE)
if(TARGET_OS STREQUAL "windows")
if (${TARGET_CPU_ARCHITECTURE} STREQUAL "x86_64")
set(SPIRV_OPTIMIZER_PROGRAM "$ENV{VULKAN_SDK}/Bin/spirv-opt.exe")
else()
set(SPIRV_OPTIMIZER_PROGRAM "$ENV{VULKAN_SDK}/Bin32/spirv-opt.exe")
endif()
endif()
if(EXISTS ${SPIRV_OPTIMIZER_PROGRAM})
set(SPIRV_OPTIMIZER_PROGRAM_FOUND TRUE)
endif()
endif()
file(GLOB_RECURSE GLSL_SHADER_FILES
"data/shaders/vulkan/*.frag"
"data/shaders/vulkan/*.vert"
)
set(TMP_SHADER_SHA256_LIST "")
foreach(GLSL_SHADER_FILE ${GLSL_SHADER_FILES})
file(SHA256 ${FILE_NAME} TMP_FILE_SHA)
set(TMP_SHADER_SHA256_LIST "${TMP_SHADER_SHA256_LIST}${TMP_FILE_SHA}")
endforeach(GLSL_SHADER_FILE)
string(SHA256 GLSL_SHADER_SHA256 "${TMP_SHADER_SHA256_LIST}")
set(GLSL_SHADER_SHA256 "${GLSL_SHADER_SHA256}@v1")
set(FOUND_MATCHING_SHA256_FILE FALSE)
if(EXISTS "${PROJECT_BINARY_DIR}/vulkan_shaders_sha256.txt")
file(STRINGS "${PROJECT_BINARY_DIR}/vulkan_shaders_sha256.txt" VULKAN_SHADERS_SHA256_FILE_CONTENT)
if("${VULKAN_SHADERS_SHA256_FILE_CONTENT}" STREQUAL "${GLSL_SHADER_SHA256}")
set(FOUND_MATCHING_SHA256_FILE TRUE)
endif()
endif()
set(TW_VULKAN_VERSION "vulkan100")
set(GLSLANG_VALIDATOR_COMMAND_LIST)
set(GLSLANG_VALIDATOR_DELETE_LIST)
set(SPIRV_OPTIMIZER_COMMAND_LIST)
function(generate_shader_file FILE_ARGS1 FILE_ARGS2 FILE_NAME FILE_OUTPUT_NAME)
set(FILE_TMP_NAME_POSTFIX "")
if(SPIRV_OPTIMIZER_PROGRAM_FOUND)
set(FILE_TMP_NAME_POSTFIX ".tmp")
endif()
list(APPEND GLSLANG_VALIDATOR_COMMAND_LIST COMMAND ${GLSLANG_VALIDATOR_PROGRAM} --client ${TW_VULKAN_VERSION} ${FILE_ARGS1} ${FILE_ARGS2} ${FILE_NAME} -o "${PROJECT_BINARY_DIR}/${FILE_OUTPUT_NAME}${FILE_TMP_NAME_POSTFIX}")
if(SPIRV_OPTIMIZER_PROGRAM_FOUND)
list(APPEND SPIRV_OPTIMIZER_COMMAND_LIST COMMAND ${SPIRV_OPTIMIZER_PROGRAM} -O "${PROJECT_BINARY_DIR}/${FILE_OUTPUT_NAME}${FILE_TMP_NAME_POSTFIX}" -o "${PROJECT_BINARY_DIR}/${FILE_OUTPUT_NAME}")
list(APPEND GLSLANG_VALIDATOR_DELETE_LIST "${PROJECT_BINARY_DIR}/${FILE_OUTPUT_NAME}${FILE_TMP_NAME_POSTFIX}")
endif()
file(RELATIVE_PATH TMP_SHADER_FILE_REL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}/${FILE_OUTPUT_NAME}")
list(APPEND VULKAN_SHADER_FILE_LIST "${FILE_OUTPUT_NAME}")
set(VULKAN_SHADER_FILE_LIST ${VULKAN_SHADER_FILE_LIST} PARENT_SCOPE)
set(GLSLANG_VALIDATOR_DELETE_LIST ${GLSLANG_VALIDATOR_DELETE_LIST} PARENT_SCOPE)
set(SPIRV_OPTIMIZER_COMMAND_LIST ${SPIRV_OPTIMIZER_COMMAND_LIST} PARENT_SCOPE)
set(GLSLANG_VALIDATOR_COMMAND_LIST ${GLSLANG_VALIDATOR_COMMAND_LIST} PARENT_SCOPE)
endfunction()
if(NOT FOUND_MATCHING_SHA256_FILE)
message(STATUS "Building vulkan shaders")
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_BINARY_DIR}/data/shader/vulkan/")
unset(VULKAN_SHADER_FILE_LIST CACHE)
# primitives
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/prim.frag" "data/shader/vulkan/prim.frag.spv")
generate_shader_file("-DTW_TEXTURED" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/prim.frag" "data/shader/vulkan/prim_textured.frag.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/prim.vert" "data/shader/vulkan/prim.vert.spv")
generate_shader_file("-DTW_TEXTURED" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/prim.vert" "data/shader/vulkan/prim_textured.vert.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/prim3d.frag" "data/shader/vulkan/prim3d.frag.spv")
generate_shader_file("-DTW_TEXTURED" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/prim3d.frag" "data/shader/vulkan/prim3d_textured.frag.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/prim3d.vert" "data/shader/vulkan/prim3d.vert.spv")
generate_shader_file("-DTW_TEXTURED" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/prim3d.vert" "data/shader/vulkan/prim3d_textured.vert.spv")
# text
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/text.frag" "data/shader/vulkan/text.frag.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/text.vert" "data/shader/vulkan/text.vert.spv")
# quad container
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/primex.frag" "data/shader/vulkan/primex.frag.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/primex.vert" "data/shader/vulkan/primex.vert.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/primex.frag" "data/shader/vulkan/primex_rotationless.frag.spv")
generate_shader_file("-DTW_ROTATIONLESS" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/primex.vert" "data/shader/vulkan/primex_rotationless.vert.spv")
generate_shader_file("-DTW_TEXTURED" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/primex.frag" "data/shader/vulkan/primex_tex.frag.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/primex.vert" "data/shader/vulkan/primex_tex.vert.spv")
generate_shader_file("-DTW_TEXTURED" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/primex.frag" "data/shader/vulkan/primex_tex_rotationless.frag.spv")
generate_shader_file("-DTW_ROTATIONLESS" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/primex.vert" "data/shader/vulkan/primex_tex_rotationless.vert.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/spritemulti.frag" "data/shader/vulkan/spritemulti.frag.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/spritemulti.vert" "data/shader/vulkan/spritemulti.vert.spv")
generate_shader_file("-DTW_PUSH_CONST" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/spritemulti.frag" "data/shader/vulkan/spritemulti_push.frag.spv")
generate_shader_file("-DTW_PUSH_CONST" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/spritemulti.vert" "data/shader/vulkan/spritemulti_push.vert.spv")
# tile layer
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.frag" "data/shader/vulkan/tile.frag.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.vert" "data/shader/vulkan/tile.vert.spv")
generate_shader_file("-DTW_TILE_TEXTURED" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.frag" "data/shader/vulkan/tile_textured.frag.spv")
generate_shader_file("-DTW_TILE_TEXTURED" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.vert" "data/shader/vulkan/tile_textured.vert.spv")
generate_shader_file("-DTW_TILE_BORDER" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.frag" "data/shader/vulkan/tile_border.frag.spv")
generate_shader_file("-DTW_TILE_BORDER" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.vert" "data/shader/vulkan/tile_border.vert.spv")
generate_shader_file("-DTW_TILE_BORDER" "-DTW_TILE_TEXTURED" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.frag" "data/shader/vulkan/tile_border_textured.frag.spv")
generate_shader_file("-DTW_TILE_BORDER" "-DTW_TILE_TEXTURED" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.vert" "data/shader/vulkan/tile_border_textured.vert.spv")
generate_shader_file("-DTW_TILE_BORDER_LINE" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.frag" "data/shader/vulkan/tile_border_line.frag.spv")
generate_shader_file("-DTW_TILE_BORDER_LINE" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.vert" "data/shader/vulkan/tile_border_line.vert.spv")
generate_shader_file("-DTW_TILE_BORDER_LINE" "-DTW_TILE_TEXTURED" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.frag" "data/shader/vulkan/tile_border_line_textured.frag.spv")
generate_shader_file("-DTW_TILE_BORDER_LINE" "-DTW_TILE_TEXTURED" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/tile.vert" "data/shader/vulkan/tile_border_line_textured.vert.spv")
# quad layer
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/quad.frag" "data/shader/vulkan/quad.frag.spv")
generate_shader_file("" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/quad.vert" "data/shader/vulkan/quad.vert.spv")
generate_shader_file("-DTW_PUSH_CONST" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/quad.frag" "data/shader/vulkan/quad_push.frag.spv")
generate_shader_file("-DTW_PUSH_CONST" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/quad.vert" "data/shader/vulkan/quad_push.vert.spv")
generate_shader_file("-DTW_QUAD_TEXTURED" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/quad.frag" "data/shader/vulkan/quad_textured.frag.spv")
generate_shader_file("-DTW_QUAD_TEXTURED" "" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/quad.vert" "data/shader/vulkan/quad_textured.vert.spv")
generate_shader_file("-DTW_QUAD_TEXTURED" "-DTW_PUSH_CONST" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/quad.frag" "data/shader/vulkan/quad_push_textured.frag.spv")
generate_shader_file("-DTW_QUAD_TEXTURED" "-DTW_PUSH_CONST" "${PROJECT_SOURCE_DIR}/data/shader/vulkan/quad.vert" "data/shader/vulkan/quad_push_textured.vert.spv")
execute_process(${GLSLANG_VALIDATOR_COMMAND_LIST})
if(SPIRV_OPTIMIZER_PROGRAM_FOUND)
execute_process(${SPIRV_OPTIMIZER_COMMAND_LIST})
file(REMOVE ${GLSLANG_VALIDATOR_DELETE_LIST})
endif()
set(VULKAN_SHADER_FILE_LIST ${VULKAN_SHADER_FILE_LIST} CACHE STRING "Vulkan shader file list" FORCE)
message(STATUS "Finished building vulkan shaders")
file(WRITE "${PROJECT_BINARY_DIR}/vulkan_shaders_sha256.txt" "${GLSL_SHADER_SHA256}")
endif()

61
cmake/FindVulkan.cmake Normal file
View file

@ -0,0 +1,61 @@
if(NOT CMAKE_CROSSCOMPILING)
find_package(PkgConfig QUIET)
pkg_check_modules(PC_VULKAN vulkan)
if(PC_VULKAN_FOUND)
set(VULKAN_INCLUDE_DIRS "${PC_VULKAN_INCLUDE_DIRS}")
set(VULKAN_LIBRARIES "${PC_VULKAN_LIBRARIES}")
set(VULKAN_FOUND TRUE)
endif()
endif()
if(NOT VULKAN_FOUND)
if(TARGET_OS STREQUAL "android")
find_library(VULKAN_LIBRARIES
NAMES vulkan
)
find_path(
VULKAN_INCLUDE_DIRS
NAMES vulkan/vulkan.h
)
elseif(TARGET_OS STREQUAL "mac")
find_library(VULKAN_LIBRARIES
NAMES MoltenVK
)
find_path(
VULKAN_INCLUDE_DIRS
NAMES vulkan/vulkan.h
)
else()
set_extra_dirs_lib(VULKAN vulkan)
find_library(VULKAN_LIBRARIES
NAMES vulkan vulkan-1
HINTS ${HINTS_VULKAN_LIBDIR} ${PC_VULKAN_LIBDIR} ${PC_VULKAN_LIBRARY_DIRS}
PATHS ${PATHS_VULKAN_LIBDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
set_extra_dirs_include(VULKAN vulkan "${VULKAN_LIBRARIES}")
find_path(
VULKAN_INCLUDE_DIRS
NAMES vulkan/vulkan.h
HINTS ${HINTS_VULKAN_INCLUDEDIR} ${PC_VULKAN_INCLUDEDIR} ${PC_VULKAN_INCLUDE_DIRS}
PATHS ${PATHS_VULKAN_INCLUDEDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
endif()
if(VULKAN_INCLUDE_DIRS AND VULKAN_LIBRARIES)
set(VULKAN_FOUND TRUE)
else(VULKAN_INCLUDE_DIRS AND VULKAN_LIBRARIES)
set(VULKAN_FOUND FALSE)
endif(VULKAN_INCLUDE_DIRS AND VULKAN_LIBRARIES)
endif()
if(TARGET_OS STREQUAL "windows")
is_bundled(VULKAN_BUNDLED "${VULKAN_LIBRARIES}")
if(VULKAN_BUNDLED)
set(VULKAN_COPY_FILES "${EXTRA_VULKAN_LIBDIR}/vulkan-1.dll")
endif()
endif()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 B

After

Width:  |  Height:  |  Size: 114 B

View file

@ -0,0 +1,20 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#ifdef TW_TEXTURED
layout(binding = 0) uniform sampler2D gTextureSampler;
#endif
layout(location = 0) noperspective in vec2 texCoord;
layout(location = 1) noperspective in vec4 vertColor;
layout(location = 0) out vec4 FragClr;
void main()
{
#ifdef TW_TEXTURED
vec4 tex = texture(gTextureSampler, texCoord);
FragClr = tex * vertColor;
#else
FragClr = vertColor;
#endif
}

View file

@ -0,0 +1,20 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) in vec2 inVertex;
layout (location = 1) in vec2 inVertexTexCoord;
layout (location = 2) in vec4 inVertexColor;
layout(push_constant) uniform SPosBO {
layout(offset = 0) mat4x2 gPos;
} gPosBO;
layout (location = 0) noperspective out vec2 texCoord;
layout (location = 1) noperspective out vec4 vertColor;
void main()
{
gl_Position = vec4(gPosBO.gPos * vec4(inVertex, 0.0, 1.0), 0.0, 1.0);
texCoord = inVertexTexCoord;
vertColor = vec4(inVertexColor);
}

View file

@ -0,0 +1,24 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#ifdef TW_TEXTURED
layout (binding = 0) uniform sampler2DArray gTextureSampler;
#endif
layout (location = 0) noperspective in vec4 oVertColor;
#ifdef TW_TEXTURED
layout (location = 1) noperspective in vec3 oTexCoord;
#endif
layout (location = 0) out vec4 FragClr;
void main()
{
#ifdef TW_TEXTURED
vec4 TexColor = texture(gTextureSampler, oTexCoord.xyz).rgba;
FragClr = TexColor.rgba * oVertColor.rgba;
#else
FragClr = oVertColor.rgba;
#endif
}

View file

@ -0,0 +1,24 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) in vec2 inVertex;
layout (location = 1) in vec4 inVertexColor;
layout (location = 2) in vec3 inVertexTexCoord;
layout(push_constant) uniform SPosBO {
layout(offset = 0) mat4x2 gPos;
} gPosBO;
layout (location = 0) noperspective out vec4 oVertColor;
#ifdef TW_TEXTURED
layout (location = 1) noperspective out vec3 oTexCoord;
#endif
void main()
{
gl_Position = vec4(gPosBO.gPos * vec4(inVertex, 0.0, 1.0), 0.0, 1.0);
#ifdef TW_TEXTURED
oTexCoord = inVertexTexCoord;
#endif
oVertColor = inVertexColor;
}

View file

@ -0,0 +1,24 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#ifdef TW_TEXTURED
layout(binding = 0) uniform sampler2D gTextureSampler;
#endif
layout(push_constant) uniform SVertexColorBO {
layout(offset = 48) vec4 gVerticesColor;
} gColorBO;
layout (location = 0) noperspective in vec2 texCoord;
layout (location = 1) noperspective in vec4 vertColor;
layout (location = 0) out vec4 FragClr;
void main()
{
#ifdef TW_TEXTURED
vec4 tex = texture(gTextureSampler, texCoord);
FragClr = tex * vertColor * gColorBO.gVerticesColor;
#else
FragClr = vertColor * gColorBO.gVerticesColor;
#endif
}

View file

@ -0,0 +1,33 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) in vec2 inVertex;
layout (location = 1) in vec2 inVertexTexCoord;
layout (location = 2) in vec4 inVertexColor;
layout(push_constant) uniform SPosBO {
layout(offset = 0) mat4x2 gPos;
#ifndef TW_ROTATIONLESS
layout(offset = 32) vec2 gCenter;
layout(offset = 40) float gRotation;
#endif
} gPosBO;
layout (location = 0) noperspective out vec2 texCoord;
layout (location = 1) noperspective out vec4 vertColor;
void main()
{
vec2 FinalPos = vec2(inVertex.xy);
#ifndef TW_ROTATIONLESS
float X = FinalPos.x - gPosBO.gCenter.x;
float Y = FinalPos.y - gPosBO.gCenter.y;
FinalPos.x = X * cos(gPosBO.gRotation) - Y * sin(gPosBO.gRotation) + gPosBO.gCenter.x;
FinalPos.y = X * sin(gPosBO.gRotation) + Y * cos(gPosBO.gRotation) + gPosBO.gCenter.y;
#endif
gl_Position = vec4(gPosBO.gPos * vec4(FinalPos, 0.0, 1.0), 0.0, 1.0);
texCoord = inVertexTexCoord;
vertColor = inVertexColor;
}

View file

@ -0,0 +1,62 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#ifdef TW_QUAD_TEXTURED
layout (set = 0, binding = 0) uniform sampler2D gTextureSampler;
#endif
#ifdef TW_QUAD_TEXTURED
#define UBOSetIndex 1
#else
#define UBOSetIndex 0
#endif
struct SQuadUniformEl {
vec4 gVertColor;
vec2 gOffset;
float gRotation;
};
#ifndef TW_PUSH_CONST
#define TW_MAX_QUADS 256
layout (std140, set = UBOSetIndex, binding = 1) uniform SOffBO {
uniform SQuadUniformEl gUniEls[TW_MAX_QUADS];
} gQuadBO;
#else
#define gQuadBO gPosBO
#define QuadIndex 0
#endif
layout(push_constant) uniform SPosBO {
layout(offset = 0) uniform mat4x2 gPos;
#ifdef TW_PUSH_CONST
layout(offset = 32) uniform SQuadUniformEl gUniEls[1];
layout(offset = 64) uniform int gQuadOffset;
#else
layout(offset = 32) uniform int gQuadOffset;
#endif
} gPosBO;
layout (location = 0) noperspective in vec4 QuadColor;
#ifndef TW_PUSH_CONST
layout (location = 1) flat in int QuadIndex;
#endif
#ifdef TW_QUAD_TEXTURED
#ifndef TW_PUSH_CONST
layout (location = 2) noperspective in vec2 TexCoord;
#else
layout (location = 1) noperspective in vec2 TexCoord;
#endif
#endif
layout (location = 0) out vec4 FragClr;
void main()
{
#ifdef TW_QUAD_TEXTURED
vec4 TexColor = texture(gTextureSampler, TexCoord);
FragClr = TexColor * QuadColor * gQuadBO.gUniEls[QuadIndex].gVertColor;
#else
FragClr = QuadColor * gQuadBO.gUniEls[QuadIndex].gVertColor;
#endif
}

View file

@ -0,0 +1,83 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) in vec4 inVertex;
layout (location = 1) in vec4 inColor;
#ifdef TW_QUAD_TEXTURED
layout (location = 2) in vec2 inVertexTexCoord;
#endif
#ifdef TW_QUAD_TEXTURED
#define UBOSetIndex 1
#else
#define UBOSetIndex 0
#endif
struct SQuadUniformEl {
vec4 gVertColor;
vec2 gOffset;
float gRotation;
};
#ifndef TW_PUSH_CONST
#define TW_MAX_QUADS 256
layout (std140, set = UBOSetIndex, binding = 1) uniform SOffBO {
uniform SQuadUniformEl gUniEls[TW_MAX_QUADS];
} gQuadBO;
#else
#define gQuadBO gPosBO
#define TmpQuadIndex 0
#endif
layout(push_constant) uniform SPosBO {
layout(offset = 0) uniform mat4x2 gPos;
#ifdef TW_PUSH_CONST
layout(offset = 32) uniform SQuadUniformEl gUniEls[1];
layout(offset = 64) uniform int gQuadOffset;
#else
layout(offset = 32) uniform int gQuadOffset;
#endif
} gPosBO;
layout (location = 0) noperspective out vec4 QuadColor;
#ifndef TW_PUSH_CONST
layout (location = 1) flat out int QuadIndex;
#endif
#ifdef TW_QUAD_TEXTURED
#ifndef TW_PUSH_CONST
layout (location = 2) noperspective out vec2 TexCoord;
#else
layout (location = 1) noperspective out vec2 TexCoord;
#endif
#endif
void main()
{
vec2 FinalPos = vec2(inVertex.xy);
#ifndef TW_PUSH_CONST
int TmpQuadIndex = int(gl_VertexIndex / 4) - gPosBO.gQuadOffset;
#endif
if(gQuadBO.gUniEls[TmpQuadIndex].gRotation != 0.0)
{
float X = FinalPos.x - inVertex.z;
float Y = FinalPos.y - inVertex.w;
FinalPos.x = X * cos(gQuadBO.gUniEls[TmpQuadIndex].gRotation) - Y * sin(gQuadBO.gUniEls[TmpQuadIndex].gRotation) + inVertex.z;
FinalPos.y = X * sin(gQuadBO.gUniEls[TmpQuadIndex].gRotation) + Y * cos(gQuadBO.gUniEls[TmpQuadIndex].gRotation) + inVertex.w;
}
FinalPos.x = FinalPos.x / 1024.0 + gQuadBO.gUniEls[TmpQuadIndex].gOffset.x;
FinalPos.y = FinalPos.y / 1024.0 + gQuadBO.gUniEls[TmpQuadIndex].gOffset.y;
gl_Position = vec4(gPosBO.gPos * vec4(FinalPos, 0.0, 1.0), 0.0, 1.0);
QuadColor = inColor;
#ifndef TW_PUSH_CONST
QuadIndex = TmpQuadIndex;
#endif
#ifdef TW_QUAD_TEXTURED
TexCoord = inVertexTexCoord;
#endif
}

View file

@ -0,0 +1,13 @@
struct SQuadUniformEl {
vec4 gVertColor;
vec2 gOffset;
float gRotation;
};
#define TW_MAX_QUADS 256
layout (std140, set = 2, binding = 2) uniform SOffBO {
uniform SQuadUniformEl gUniEls[TW_MAX_QUADS];
} gQuadBO;

View file

@ -0,0 +1,23 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout (set = 0, binding = 0) uniform sampler2D gTextureSampler;
layout(push_constant) uniform SVertexColorBO {
#ifdef TW_PUSH_CONST
layout(offset = 64) vec4 gVerticesColor;
#else
layout(offset = 48) vec4 gVerticesColor;
#endif
} gColorBO;
layout (location = 0) noperspective in vec2 texCoord;
layout (location = 1) noperspective in vec4 vertColor;
layout (location = 0) out vec4 FragClr;
void main()
{
vec4 tex = texture(gTextureSampler, texCoord);
FragClr = tex * vertColor * gColorBO.gVerticesColor;
}

View file

@ -0,0 +1,50 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) in vec2 inVertex;
layout (location = 1) in vec2 inVertexTexCoord;
layout (location = 2) in vec4 inVertexColor;
layout(push_constant) uniform SPosBO {
layout(offset = 0) uniform mat4x2 gPos;
layout(offset = 32) uniform vec2 gCenter;
#ifdef TW_PUSH_CONST
layout(offset = 48) uniform vec4 gRSP[1];
#endif
} gPosBO;
#ifndef TW_PUSH_CONST
layout (std140, set = 1, binding = 1) uniform SRSPBO {
vec4 gRSP[512];
} gRSPBO;
#define RSPIndex gl_InstanceIndex
#else
#define gRSPBO gPosBO
#define RSPIndex 0
#endif
layout (location = 0) noperspective out vec2 texCoord;
layout (location = 1) noperspective out vec4 vertColor;
void main()
{
vec2 FinalPos = vec2(inVertex.xy);
if(gRSPBO.gRSP[RSPIndex].w != 0.0)
{
float X = FinalPos.x - gPosBO.gCenter.x;
float Y = FinalPos.y - gPosBO.gCenter.y;
FinalPos.x = X * cos(gRSPBO.gRSP[RSPIndex].w) - Y * sin(gRSPBO.gRSP[RSPIndex].w) + gPosBO.gCenter.x;
FinalPos.y = X * sin(gRSPBO.gRSP[RSPIndex].w) + Y * cos(gRSPBO.gRSP[RSPIndex].w) + gPosBO.gCenter.y;
}
FinalPos.x *= gRSPBO.gRSP[RSPIndex].z;
FinalPos.y *= gRSPBO.gRSP[RSPIndex].z;
FinalPos.x += gRSPBO.gRSP[RSPIndex].x;
FinalPos.y += gRSPBO.gRSP[RSPIndex].y;
gl_Position = vec4(gPosBO.gPos * vec4(FinalPos, 0.0, 1.0), 0.0, 1.0);
texCoord = inVertexTexCoord;
vertColor = inVertexColor;
}

View file

@ -0,0 +1,43 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(binding = 0) uniform sampler2D gTextSampler;
layout(binding = 1) uniform sampler2D gTextOutlineSampler;
layout(push_constant) uniform SFragConstBO {
layout(offset = 48) uniform vec4 gVertColor;
layout(offset = 64) uniform vec4 gVertOutlineColor;
} gFragConst;
layout (location = 0) noperspective in vec2 texCoord;
layout (location = 1) noperspective in vec4 outVertColor;
layout(location = 0) out vec4 FragClr;
void main()
{
vec4 textColor = gFragConst.gVertColor * outVertColor * vec4(1.0, 1.0, 1.0, texture(gTextSampler, texCoord).r);
vec4 textOutlineTex = gFragConst.gVertOutlineColor * vec4(1.0, 1.0, 1.0, texture(gTextOutlineSampler, texCoord).r);
// ratio between the two textures
float OutlineBlend = (1.0 - textColor.a);
// since the outline is always black, or even if it has decent colors, it can be just added to the actual color
// without loosing any or too much color
// lerp isn't commutative, so add the color the fragment looses by lerping
// this reduces the chance of false color calculation if the text is transparent
// first get the right color
vec4 textOutlineFrag = vec4(textOutlineTex.rgb * textOutlineTex.a, textOutlineTex.a) * OutlineBlend;
vec3 textFrag = (textColor.rgb * textColor.a);
vec3 finalFragColor = textOutlineFrag.rgb + textFrag;
float RealAlpha = (textOutlineFrag.a + textColor.a);
// simply add the color we will loose through blending
if(RealAlpha > 0.0)
FragClr = vec4(finalFragColor / RealAlpha, RealAlpha);
else
FragClr = vec4(0.0, 0.0, 0.0, 0.0);
}

View file

@ -0,0 +1,22 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) in vec2 inVertex;
layout (location = 1) in vec2 inVertexTexCoord;
layout (location = 2) in vec4 inVertexColor;
layout(push_constant) uniform SPosBO {
layout(offset = 0) mat4x2 gPos;
layout(offset = 32) float gTextureSize;
} gPosBO;
layout (location = 0) noperspective out vec2 texCoord;
layout (location = 1) noperspective out vec4 outVertColor;
void main()
{
gl_Position = vec4(gPosBO.gPos * vec4(inVertex, 0.0, 1.0), 0.0, 1.0);
texCoord = vec2(inVertexTexCoord.x / gPosBO.gTextureSize, inVertexTexCoord.y / gPosBO.gTextureSize);
outVertColor = inVertexColor;
}

View file

@ -0,0 +1,25 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#ifdef TW_TILE_TEXTURED
layout(binding = 0) uniform sampler2DArray gTextureSampler;
#endif
layout(push_constant) uniform SVertexColorBO {
layout(offset = 64) uniform vec4 gVertColor;
} gColorBO;
#ifdef TW_TILE_TEXTURED
layout (location = 0) noperspective in vec3 TexCoord;
#endif
layout (location = 0) out vec4 FragClr;
void main()
{
#ifdef TW_TILE_TEXTURED
vec4 TexColor = texture(gTextureSampler, TexCoord.xyz);
FragClr = TexColor * gColorBO.gVertColor;
#else
FragClr = gColorBO.gVertColor;
#endif
}

View file

@ -0,0 +1,49 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) in vec2 inVertex;
#ifdef TW_TILE_TEXTURED
layout (location = 1) in vec3 inVertexTexCoord;
#endif
layout(push_constant) uniform SPosBO {
layout(offset = 0) uniform mat4x2 gPos;
#if defined(TW_TILE_BORDER) || defined(TW_TILE_BORDER_LINE)
layout(offset = 32) uniform vec2 gDir;
layout(offset = 40) uniform vec2 gOffset;
#endif
#if defined(TW_TILE_BORDER)
layout(offset = 48) uniform int gJumpIndex;
#endif
} gPosBO;
#ifdef TW_TILE_TEXTURED
layout (location = 0) noperspective out vec3 TexCoord;
#endif
void main()
{
#if defined(TW_TILE_BORDER)
vec4 VertPos = vec4(inVertex, 0.0, 1.0);
int XCount = gl_InstanceIndex - (int(gl_InstanceIndex/gPosBO.gJumpIndex) * gPosBO.gJumpIndex);
int YCount = (int(gl_InstanceIndex/gPosBO.gJumpIndex));
VertPos.x += gPosBO.gOffset.x + gPosBO.gDir.x * float(XCount);
VertPos.y += gPosBO.gOffset.y + gPosBO.gDir.y * float(YCount);
gl_Position = vec4(gPosBO.gPos * VertPos, 0.0, 1.0);
#elif defined(TW_TILE_BORDER_LINE)
vec4 VertPos = vec4(inVertex.x + gPosBO.gOffset.x, inVertex.y + gPosBO.gOffset.y, 0.0, 1.0);
VertPos.x += gPosBO.gDir.x * float(gl_InstanceIndex);
VertPos.y += gPosBO.gDir.y * float(gl_InstanceIndex);
gl_Position = vec4(gPosBO.gPos * VertPos, 0.0, 1.0);
#else
gl_Position = vec4(gPosBO.gPos * vec4(inVertex, 0.0, 1.0), 0.0, 1.0);
#endif
#ifdef TW_TILE_TEXTURED
TexCoord = inVertexTexCoord;
#endif
}

View file

@ -104,7 +104,8 @@ function build_for_type() {
-DTOOLS=OFF \
-DDEV=TRUE \
-DCMAKE_CROSSCOMPILING=ON \
-DPREFER_BUNDLED_LIBS=ON
-DPREFER_BUNDLED_LIBS=ON \
-DVULKAN=ON
(
cd "build_android/$_ANDROID_SUB_BUILD_DIR/$1" || exit 1
cmake --build . --target DDNet

View file

@ -29,7 +29,7 @@ public:
virtual ~CCommandProcessorFragment_GLBase() = default;
virtual bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand) = 0;
virtual void StartCommands(size_t CommandCount) {}
virtual void StartCommands(size_t CommandCount, size_t EstimatedRenderCallCount) {}
virtual void EndCommands() {}
enum

View file

@ -1005,8 +1005,10 @@ void CCommandProcessorFragment_OpenGL::Cmd_Render(const CCommandBuffer::SCommand
#endif
}
void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand)
void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCommand_TrySwapAndScreenshot *pCommand)
{
*pCommand->m_pSwapped = false;
// fetch image data
GLint aViewport[4] = {0, 0, 0, 0};
glGetIntegerv(GL_VIEWPORT, aViewport);
@ -1088,8 +1090,8 @@ bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand
case CCommandBuffer::CMD_RENDER_TEX3D:
Cmd_RenderTex3D(static_cast<const CCommandBuffer::SCommand_RenderTex3D *>(pBaseCommand));
break;
case CCommandBuffer::CMD_SCREENSHOT:
Cmd_Screenshot(static_cast<const CCommandBuffer::SCommand_Screenshot *>(pBaseCommand));
case CCommandBuffer::CMD_TRY_SWAP_AND_SCREENSHOT:
Cmd_Screenshot(static_cast<const CCommandBuffer::SCommand_TrySwapAndScreenshot *>(pBaseCommand));
break;
case CCommandBuffer::CMD_UPDATE_VIEWPORT:
Cmd_Update_Viewport(static_cast<const CCommandBuffer::SCommand_Update_Viewport *>(pBaseCommand));
@ -1971,6 +1973,7 @@ void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferContainer(const CCommand
{
SBufferContainer Container;
Container.m_ContainerInfo.m_Stride = 0;
Container.m_ContainerInfo.m_VertBufferBindingIndex = -1;
m_BufferContainers.push_back(Container);
}
}

View file

@ -103,7 +103,7 @@ protected:
virtual void Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand);
virtual void Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand);
virtual void Cmd_RenderTex3D(const CCommandBuffer::SCommand_RenderTex3D *pCommand) { dbg_assert(false, "Call of unsupported Cmd_RenderTex3D"); }
virtual void Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand);
virtual void Cmd_Screenshot(const CCommandBuffer::SCommand_TrySwapAndScreenshot *pCommand);
virtual void Cmd_Update_Viewport(const CCommandBuffer::SCommand_Update_Viewport *pCommand);
virtual void Cmd_Finish(const CCommandBuffer::SCommand_Finish *pCommand);
@ -139,7 +139,6 @@ class CCommandProcessorFragment_OpenGL2 : public CCommandProcessorFragment_OpenG
{
struct SBufferContainer
{
SBufferContainer() {}
SBufferContainerInfo m_ContainerInfo;
};
std::vector<SBufferContainer> m_BufferContainers;

View file

@ -1042,6 +1042,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferContainer(const CComma
{
SBufferContainer Container;
Container.m_ContainerInfo.m_Stride = 0;
Container.m_ContainerInfo.m_VertBufferBindingIndex = -1;
m_BufferContainers.push_back(Container);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
#ifndef ENGINE_CLIENT_BACKEND_VULKAN_BACKEND_VULKAN_H
#define ENGINE_CLIENT_BACKEND_VULKAN_BACKEND_VULKAN_H
#include <base/detect.h>
#include <engine/client/backend_sdl.h>
static constexpr int gs_BackendVulkanMajor = 1;
static constexpr int gs_BackendVulkanMinor = 0;
CCommandProcessorFragment_GLBase *CreateVulkanCommandProcessorFragment();
#endif

View file

@ -68,10 +68,10 @@ void CGraphicsBackend_Threaded::ThreadFunc(void *pUser)
std::unique_lock<std::mutex> Lock(pSelf->m_BufferSwapMutex);
// notify, that the thread started
pSelf->m_Started = true;
pSelf->m_BufferDoneCond.notify_all();
pSelf->m_BufferSwapCond.notify_all();
while(!pSelf->m_Shutdown)
{
pSelf->m_BufferSwapCond.wait(Lock);
pSelf->m_BufferSwapCond.wait(Lock, [&pSelf] { return pSelf->m_pBuffer != nullptr || pSelf->m_Shutdown; });
if(pSelf->m_pBuffer)
{
#ifdef CONF_PLATFORM_MACOS
@ -81,7 +81,7 @@ void CGraphicsBackend_Threaded::ThreadFunc(void *pUser)
pSelf->m_pBuffer = nullptr;
pSelf->m_BufferInProcess.store(false, std::memory_order_relaxed);
pSelf->m_BufferDoneCond.notify_all();
pSelf->m_BufferSwapCond.notify_all();
#if defined(CONF_VIDEORECORDER)
if(IVideo::Current())
@ -100,16 +100,18 @@ CGraphicsBackend_Threaded::CGraphicsBackend_Threaded()
void CGraphicsBackend_Threaded::StartProcessor(ICommandProcessor *pProcessor)
{
dbg_assert(m_Shutdown, "Processor was already not shut down.");
m_Shutdown = false;
m_pProcessor = pProcessor;
std::unique_lock<std::mutex> Lock(m_BufferSwapMutex);
m_Thread = thread_init(ThreadFunc, this, "Graphics thread");
// wait for the thread to start
m_BufferDoneCond.wait(Lock, [this]() -> bool { return m_Started; });
m_BufferSwapCond.wait(Lock, [this]() -> bool { return m_Started; });
}
void CGraphicsBackend_Threaded::StopProcessor()
{
dbg_assert(!m_Shutdown, "Processor was already shut down.");
m_Shutdown = true;
{
std::unique_lock<std::mutex> Lock(m_BufferSwapMutex);
@ -140,8 +142,7 @@ bool CGraphicsBackend_Threaded::IsIdle() const
void CGraphicsBackend_Threaded::WaitForIdle()
{
std::unique_lock<std::mutex> Lock(m_BufferSwapMutex);
while(m_pBuffer != nullptr)
m_BufferDoneCond.wait(Lock);
m_BufferSwapCond.wait(Lock, [this]() { return m_pBuffer == nullptr; });
}
// ------------ CCommandProcessorFragment_General
@ -236,7 +237,7 @@ bool CCommandProcessorFragment_SDL::RunCommand(const CCommandBuffer::SCommand *p
void CCommandProcessor_SDL_GL::RunBuffer(CCommandBuffer *pBuffer)
{
m_pGLBackend->StartCommands(pBuffer->m_CommandCount);
m_pGLBackend->StartCommands(pBuffer->m_CommandCount, pBuffer->m_RenderCallCount);
for(CCommandBuffer::SCommand *pCommand = pBuffer->Head(); pCommand; pCommand = pCommand->m_pNext)
{
@ -560,10 +561,8 @@ static int IsVersionSupportedGlew(EBackendType BackendType, int VersionMajor, in
EBackendType CGraphicsBackend_SDL_GL::DetectBackend()
{
// TODO
return BACKEND_TYPE_VULKAN;
EBackendType RetBackendType = BACKEND_TYPE_OPENGL;
const char *pEnvDriver = getenv("DDNET_DRIVER");
const char *pEnvDriver = SDL_getenv("DDNET_DRIVER");
if(pEnvDriver && str_comp_nocase(pEnvDriver, "GLES") == 0)
RetBackendType = BACKEND_TYPE_OPENGL_ES;
else if(pEnvDriver && str_comp_nocase(pEnvDriver, "Vulkan") == 0)
@ -581,9 +580,15 @@ EBackendType CGraphicsBackend_SDL_GL::DetectBackend()
else if(str_comp_nocase(pConfBackend, "OpenGL") == 0)
RetBackendType = BACKEND_TYPE_OPENGL;
}
#if !defined(CONF_BACKEND_VULKAN)
RetBackendType = BACKEND_TYPE_OPENGL;
#endif
#if !defined(CONF_BACKEND_OPENGL_ES) && !defined(CONF_BACKEND_OPENGL_ES3)
if(RetBackendType == BACKEND_TYPE_OPENGL_ES)
RetBackendType = BACKEND_TYPE_OPENGL;
#elif defined(CONF_BACKEND_OPENGL_ES)
if(RetBackendType == BACKEND_TYPE_OPENGL)
RetBackendType = BACKEND_TYPE_OPENGL_ES;
#endif
return RetBackendType;
}
@ -635,9 +640,11 @@ void CGraphicsBackend_SDL_GL::ClampDriverVersion(EBackendType BackendType)
}
else if(BackendType == BACKEND_TYPE_VULKAN)
{
g_Config.m_GfxGLMajor = 1;
g_Config.m_GfxGLMinor = 1;
#if defined(CONF_BACKEND_VULKAN)
g_Config.m_GfxGLMajor = gs_BackendVulkanMajor;
g_Config.m_GfxGLMinor = gs_BackendVulkanMinor;
g_Config.m_GfxGLPatch = 0;
#endif
}
}
@ -653,50 +660,81 @@ bool CGraphicsBackend_SDL_GL::IsModernAPI(EBackendType BackendType)
return false;
}
void CGraphicsBackend_SDL_GL::GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch)
bool CGraphicsBackend_SDL_GL::GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType)
{
if(m_BackendType == BACKEND_TYPE_OPENGL)
if(BackendType == BACKEND_TYPE_AUTO)
BackendType = m_BackendType;
if(BackendType == BACKEND_TYPE_OPENGL)
{
pName = "OpenGL";
if(DriverAgeType == GRAPHICS_DRIVER_AGE_TYPE_LEGACY)
{
Major = 1;
Minor = 4;
Patch = 0;
return true;
}
else if(DriverAgeType == GRAPHICS_DRIVER_AGE_TYPE_DEFAULT)
{
Major = 3;
Minor = 0;
Patch = 0;
return true;
}
else if(DriverAgeType == GRAPHICS_DRIVER_AGE_TYPE_MODERN)
{
Major = 3;
Minor = 3;
Patch = 0;
return true;
}
}
else if(m_BackendType == BACKEND_TYPE_OPENGL_ES)
else if(BackendType == BACKEND_TYPE_OPENGL_ES)
{
pName = "GLES";
#ifdef CONF_BACKEND_OPENGL_ES
if(DriverAgeType == GRAPHICS_DRIVER_AGE_TYPE_LEGACY)
{
Major = 1;
Minor = 0;
Patch = 0;
return true;
}
else if(DriverAgeType == GRAPHICS_DRIVER_AGE_TYPE_DEFAULT)
{
Major = 3;
Minor = 0;
Patch = 0;
// there isn't really a default one
return false;
}
else if(DriverAgeType == GRAPHICS_DRIVER_AGE_TYPE_MODERN)
#endif
#ifdef CONF_BACKEND_OPENGL_ES3
if(DriverAgeType == GRAPHICS_DRIVER_AGE_TYPE_MODERN)
{
Major = 3;
Minor = 0;
Patch = 0;
return true;
}
#endif
}
else if(BackendType == BACKEND_TYPE_VULKAN)
{
pName = "Vulkan";
#ifdef CONF_BACKEND_VULKAN
if(DriverAgeType == GRAPHICS_DRIVER_AGE_TYPE_DEFAULT)
{
Major = gs_BackendVulkanMajor;
Minor = gs_BackendVulkanMinor;
Patch = 0;
return true;
}
#else
return false;
#endif
}
return false;
}
static void DisplayToVideoMode(CVideoMode *pVMode, SDL_DisplayMode *pMode, int HiDPIScale, int RefreshRate)
@ -830,12 +868,19 @@ int CGraphicsBackend_SDL_GL::Init(const char *pName, int *pScreen, int *pWidth,
dbg_msg("gfx", "unable to init SDL video: %s", SDL_GetError());
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_SDL_INIT_FAILED;
}
#if defined(CONF_FAMILY_WINDOWS) && defined(CONF_BACKEND_VULKAN)
SDL_Vulkan_LoadLibrary("libvulkan-1.dll");
#endif
}
EBackendType OldBackendType = m_BackendType;
m_BackendType = DetectBackend();
// little fallback for Vulkan
if(OldBackendType != BACKEND_TYPE_AUTO)
{
if(m_BackendType == BACKEND_TYPE_VULKAN)
{
SDL_setenv("DDNET_DRIVER", "OpenGL", 1);
m_BackendType = DetectBackend();
}
}
ClampDriverVersion(m_BackendType);
@ -918,7 +963,7 @@ int CGraphicsBackend_SDL_GL::Init(const char *pName, int *pScreen, int *pWidth,
// set flags
int SdlFlags = SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS;
SdlFlags |= (m_BackendType == BACKEND_TYPE_OPENGL || m_BackendType == BACKEND_TYPE_OPENGL_ES) ? SDL_WINDOW_OPENGL : SDL_WINDOW_VULKAN;
SdlFlags |= (IsOpenGLFamilyBackend) ? SDL_WINDOW_OPENGL : SDL_WINDOW_VULKAN;
if(Flags & IGraphicsBackend::INITFLAG_HIGHDPI)
SdlFlags |= SDL_WINDOW_ALLOW_HIGHDPI;
if(Flags & IGraphicsBackend::INITFLAG_RESIZABLE)
@ -981,7 +1026,10 @@ int CGraphicsBackend_SDL_GL::Init(const char *pName, int *pScreen, int *pWidth,
if(m_pWindow == NULL)
{
dbg_msg("gfx", "unable to create window: %s", SDL_GetError());
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_SDL_WINDOW_CREATE_FAILED;
if(m_BackendType == BACKEND_TYPE_VULKAN)
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_GL_CONTEXT_FAILED;
else
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_SDL_WINDOW_CREATE_FAILED;
}
int GlewMajor = 0;
@ -1013,7 +1061,7 @@ int CGraphicsBackend_SDL_GL::Init(const char *pName, int *pScreen, int *pWidth,
InitError = IsVersionSupportedGlew(m_BackendType, g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch, GlewMajor, GlewMinor, GlewPatch);
// SDL_GL_GetDrawableSize reports HiDPI resolution even with SDL_WINDOW_ALLOW_HIGHDPI not set, which is wrong
if(SdlFlags & SDL_WINDOW_ALLOW_HIGHDPI)
if(SdlFlags & SDL_WINDOW_ALLOW_HIGHDPI && IsOpenGLFamilyBackend)
SDL_GL_GetDrawableSize(m_pWindow, pCurrentWidth, pCurrentHeight);
else
SDL_GetWindowSize(m_pWindow, pCurrentWidth, pCurrentHeight);
@ -1039,6 +1087,7 @@ int CGraphicsBackend_SDL_GL::Init(const char *pName, int *pScreen, int *pWidth,
}
// start the command processor
dbg_assert(m_pProcessor == nullptr, "Processor was not cleaned up properly.");
m_pProcessor = new CCommandProcessor_SDL_GL(m_BackendType, g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch);
StartProcessor(m_pProcessor);
@ -1124,7 +1173,7 @@ int CGraphicsBackend_SDL_GL::Init(const char *pName, int *pScreen, int *pWidth,
// stop and delete the processor
StopProcessor();
delete m_pProcessor;
m_pProcessor = 0;
m_pProcessor = nullptr;
if(m_GLContext)
SDL_GL_DeleteContext(m_GLContext);
@ -1188,7 +1237,7 @@ int CGraphicsBackend_SDL_GL::Shutdown()
// stop and delete the processor
StopProcessor();
delete m_pProcessor;
m_pProcessor = 0;
m_pProcessor = nullptr;
SDL_GL_DeleteContext(m_GLContext);
SDL_DestroyWindow(m_pWindow);

View file

@ -5,6 +5,7 @@
#include <base/detect.h>
#include "engine/graphics.h"
#include "graphics_defines.h"
#include "blocklist_driver.h"
@ -70,9 +71,8 @@ private:
ICommandProcessor *m_pProcessor;
std::mutex m_BufferSwapMutex;
std::condition_variable m_BufferSwapCond;
std::condition_variable m_BufferDoneCond;
CCommandBuffer *m_pBuffer;
std::atomic_bool m_Shutdown;
std::atomic_bool m_Shutdown = true;
bool m_Started = false;
std::atomic_bool m_BufferInProcess;
void *m_Thread;
@ -90,13 +90,6 @@ public:
bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand);
};
enum EBackendType
{
BACKEND_TYPE_OPENGL = 0,
BACKEND_TYPE_OPENGL_ES,
BACKEND_TYPE_VULKAN,
};
struct SBackendCapabilites
{
bool m_TileBuffering;
@ -183,7 +176,7 @@ class CGraphicsBackend_SDL_GL : public CGraphicsBackend_Threaded
{
SDL_Window *m_pWindow = NULL;
SDL_GLContext m_GLContext;
ICommandProcessor *m_pProcessor;
ICommandProcessor *m_pProcessor = nullptr;
std::atomic<uint64_t> m_TextureMemoryUsage{0};
std::atomic<uint64_t> m_BufferMemoryUsage{0};
std::atomic<uint64_t> m_StreamMemoryUsage{0};
@ -201,7 +194,7 @@ class CGraphicsBackend_SDL_GL : public CGraphicsBackend_Threaded
char m_aVersionString[gs_GPUInfoStringSize] = {};
char m_aRendererString[gs_GPUInfoStringSize] = {};
EBackendType m_BackendType;
EBackendType m_BackendType = BACKEND_TYPE_AUTO;
char m_aErrorString[256];
@ -241,7 +234,7 @@ public:
virtual void WindowDestroyNtf(uint32_t WindowID);
virtual void WindowCreateNtf(uint32_t WindowID);
virtual void GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch);
virtual bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType);
virtual bool IsConfigModernAPI() { return IsModernAPI(m_BackendType); }
virtual bool UseTrianglesAsQuad() { return m_Capabilites.m_TrianglesAsQuads; }
virtual bool HasTileBuffering() { return m_Capabilites.m_TileBuffering; }

View file

@ -496,7 +496,7 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Heig
void *pTmpData = malloc(MemSize);
if(!ConvertToRGBA((uint8_t *)pTmpData, (const uint8_t *)pData, Width, Height, Format))
{
dbg_msg("graphics", "converted image %s to RGBA, consider making its file format using RGBA", pTexName);
dbg_msg("graphics", "converted image %s to RGBA, consider making its file format RGBA", pTexName);
}
Cmd.m_pData = pTmpData;
@ -624,7 +624,7 @@ bool CGraphics_Threaded::UpdateTextTexture(CTextureHandle TextureID, int x, int
AddCmd(
Cmd, [] { return true; }, "failed to update text texture.");
return 0;
return true;
}
int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType)
@ -739,7 +739,7 @@ bool CGraphics_Threaded::CheckImageDivisibility(const char *pFileName, CImageInf
bool CGraphics_Threaded::IsImageFormatRGBA(const char *pFileName, CImageInfo &Img)
{
if(Img.m_Format != CImageInfo::FORMAT_RGBA && Img.m_Format != CImageInfo::FORMAT_ALPHA)
if(Img.m_Format != CImageInfo::FORMAT_RGBA)
{
SWarning NewWarning;
char aText[128];
@ -787,14 +787,17 @@ void CGraphics_Threaded::KickCommandBuffer()
m_pCommandBuffer->Reset();
}
void CGraphics_Threaded::ScreenshotDirect()
bool CGraphics_Threaded::ScreenshotDirect()
{
// add swap command
CImageInfo Image;
mem_zero(&Image, sizeof(Image));
CCommandBuffer::SCommand_Screenshot Cmd;
bool DidSwap = false;
CCommandBuffer::SCommand_TrySwapAndScreenshot Cmd;
Cmd.m_pImage = &Image;
Cmd.m_pSwapped = &DidSwap;
AddCmd(
Cmd, [] { return true; }, "failed to take screenshot.");
@ -826,6 +829,8 @@ void CGraphics_Threaded::ScreenshotDirect()
free(Image.m_pData);
}
return DidSwap;
}
void CGraphics_Threaded::TextureSet(CTextureHandle TextureID)
@ -834,13 +839,14 @@ void CGraphics_Threaded::TextureSet(CTextureHandle TextureID)
m_State.m_Texture = TextureID.Id();
}
void CGraphics_Threaded::Clear(float r, float g, float b)
void CGraphics_Threaded::Clear(float r, float g, float b, bool ForceClearNow)
{
CCommandBuffer::SCommand_Clear Cmd;
Cmd.m_Color.r = r;
Cmd.m_Color.g = g;
Cmd.m_Color.b = b;
Cmd.m_Color.a = 0;
Cmd.m_ForceClear = ForceClearNow || m_IsForcedViewport;
AddCmd(
Cmd, [] { return true; }, "failed to clear graphics.");
}
@ -1218,25 +1224,25 @@ void CGraphics_Threaded::QuadsText(float x, float y, float Size, const char *pTe
}
}
void CGraphics_Threaded::RenderTileLayer(int BufferContainerIndex, float *pColor, char **pOffsets, unsigned int *IndicedVertexDrawNum, size_t NumIndicesOffet)
void CGraphics_Threaded::RenderTileLayer(int BufferContainerIndex, float *pColor, char **pOffsets, unsigned int *IndicedVertexDrawNum, size_t NumIndicesOffset)
{
if(NumIndicesOffet == 0)
if(NumIndicesOffset == 0)
return;
// add the VertexArrays and draw
CCommandBuffer::SCommand_RenderTileLayer Cmd;
Cmd.m_State = m_State;
Cmd.m_IndicesDrawNum = NumIndicesOffet;
Cmd.m_IndicesDrawNum = NumIndicesOffset;
Cmd.m_BufferContainerIndex = BufferContainerIndex;
mem_copy(&Cmd.m_Color, pColor, sizeof(Cmd.m_Color));
void *Data = m_pCommandBuffer->AllocData((sizeof(char *) + sizeof(unsigned int)) * NumIndicesOffet);
void *Data = m_pCommandBuffer->AllocData((sizeof(char *) + sizeof(unsigned int)) * NumIndicesOffset);
if(Data == 0x0)
{
// kick command buffer and try again
KickCommandBuffer();
Data = m_pCommandBuffer->AllocData((sizeof(char *) + sizeof(unsigned int)) * NumIndicesOffet);
Data = m_pCommandBuffer->AllocData((sizeof(char *) + sizeof(unsigned int)) * NumIndicesOffset);
if(Data == 0x0)
{
dbg_msg("graphics", "failed to allocate data for vertices");
@ -1244,18 +1250,18 @@ void CGraphics_Threaded::RenderTileLayer(int BufferContainerIndex, float *pColor
}
}
Cmd.m_pIndicesOffsets = (char **)Data;
Cmd.m_pDrawCount = (unsigned int *)(((char *)Data) + (sizeof(char *) * NumIndicesOffet));
Cmd.m_pDrawCount = (unsigned int *)(((char *)Data) + (sizeof(char *) * NumIndicesOffset));
if(!AddCmd(
Cmd, [&] {
Data = m_pCommandBuffer->AllocData((sizeof(char *) + sizeof(unsigned int)) * NumIndicesOffet);
Data = m_pCommandBuffer->AllocData((sizeof(char *) + sizeof(unsigned int)) * NumIndicesOffset);
if(Data == 0x0)
{
dbg_msg("graphics", "failed to allocate data for vertices");
return false;
}
Cmd.m_pIndicesOffsets = (char **)Data;
Cmd.m_pDrawCount = (unsigned int *)(((char *)Data) + (sizeof(char *) * NumIndicesOffet));
Cmd.m_pDrawCount = (unsigned int *)(((char *)Data) + (sizeof(char *) * NumIndicesOffset));
return true;
},
"failed to allocate memory for render command"))
@ -1263,9 +1269,10 @@ void CGraphics_Threaded::RenderTileLayer(int BufferContainerIndex, float *pColor
return;
}
mem_copy(Cmd.m_pIndicesOffsets, pOffsets, sizeof(char *) * NumIndicesOffet);
mem_copy(Cmd.m_pDrawCount, IndicedVertexDrawNum, sizeof(unsigned int) * NumIndicesOffet);
mem_copy(Cmd.m_pIndicesOffsets, pOffsets, sizeof(char *) * NumIndicesOffset);
mem_copy(Cmd.m_pDrawCount, IndicedVertexDrawNum, sizeof(unsigned int) * NumIndicesOffset);
m_pCommandBuffer->AddRenderCalls(NumIndicesOffset);
// todo max indices group check!!
}
@ -1294,6 +1301,8 @@ void CGraphics_Threaded::RenderBorderTiles(int BufferContainerIndex, float *pCol
{
return;
}
m_pCommandBuffer->AddRenderCalls(1);
}
void CGraphics_Threaded::RenderBorderTileLines(int BufferContainerIndex, float *pColor, char *pIndexBufferOffset, float *pOffset, float *pDir, unsigned int IndexDrawNum, unsigned int RedrawNum)
@ -1321,6 +1330,8 @@ void CGraphics_Threaded::RenderBorderTileLines(int BufferContainerIndex, float *
{
return;
}
m_pCommandBuffer->AddRenderCalls(1);
}
void CGraphics_Threaded::RenderQuadLayer(int BufferContainerIndex, SQuadRenderInfo *pQuadInfo, int QuadNum, int QuadOffset)
@ -1356,6 +1367,8 @@ void CGraphics_Threaded::RenderQuadLayer(int BufferContainerIndex, SQuadRenderIn
}
mem_copy(Cmd.m_pQuadInfo, pQuadInfo, sizeof(SQuadRenderInfo) * QuadNum);
m_pCommandBuffer->AddRenderCalls(((QuadNum - 1) / gs_GraphicsMaxQuadsRenderCount) + 1);
}
void CGraphics_Threaded::RenderText(int BufferContainerIndex, int TextQuadNum, int TextureSize, int TextureTextIndex, int TextureTextOutlineIndex, float *pTextColor, float *pTextoutlineColor)
@ -1378,6 +1391,8 @@ void CGraphics_Threaded::RenderText(int BufferContainerIndex, int TextQuadNum, i
{
return;
}
m_pCommandBuffer->AddRenderCalls(1);
}
int CGraphics_Threaded::CreateQuadContainer(bool AutomaticUpload)
@ -1594,6 +1609,8 @@ void CGraphics_Threaded::RenderQuadContainer(int ContainerIndex, int QuadOffset,
{
return;
}
m_pCommandBuffer->AddRenderCalls(1);
}
else
{
@ -1671,6 +1688,8 @@ void CGraphics_Threaded::RenderQuadContainerEx(int ContainerIndex, int QuadOffse
{
return;
}
m_pCommandBuffer->AddRenderCalls(1);
}
else
{
@ -1815,6 +1834,9 @@ void CGraphics_Threaded::RenderQuadContainerAsSpriteMultiple(int ContainerIndex,
}
mem_copy(Cmd.m_pRenderInfo, pRenderInfo, sizeof(IGraphics::SRenderSpriteInfo) * DrawCount);
m_pCommandBuffer->AddRenderCalls(((DrawCount - 1) / gs_GraphicsMaxParticlesRenderCount) + 1);
WrapNormal();
}
else
@ -2235,6 +2257,37 @@ int CGraphics_Threaded::IssueInit()
return r;
}
void CGraphics_Threaded::AdjustViewport(bool SendViewportChangeToBackend)
{
// adjust the viewport to only allow certain aspect ratios
// keep this in sync with backend_vulkan GetSwapImageSize's check
if(m_ScreenHeight > 4 * m_ScreenWidth / 5)
{
m_IsForcedViewport = true;
m_ScreenHeight = 4 * m_ScreenWidth / 5;
if(SendViewportChangeToBackend)
{
CCommandBuffer::SCommand_Update_Viewport Cmd;
Cmd.m_X = 0;
Cmd.m_Y = 0;
Cmd.m_Width = m_ScreenWidth;
Cmd.m_Height = m_ScreenHeight;
Cmd.m_ByResize = true;
if(!AddCmd(
Cmd, [] { return true; }, "failed to add resize command"))
{
return;
}
}
}
else
{
m_IsForcedViewport = false;
}
}
void CGraphics_Threaded::AddBackEndWarningIfExists()
{
const char *pErrStr = m_pBackend->GetErrorString();
@ -2354,6 +2407,16 @@ int CGraphics_Threaded::InitWindow()
return 0;
}
// at the very end, just try to set to gl 1.4
{
g_Config.m_GfxGLMajor = 1;
g_Config.m_GfxGLMinor = 4;
g_Config.m_GfxGLPatch = 0;
if(IssueInit() == 0)
return 0;
}
dbg_msg("gfx", "out of ideas. failed to init graphics");
return -1;
@ -2413,6 +2476,8 @@ int CGraphics_Threaded::Init()
str_format(aBuf, sizeof(aBuf), "GPU version: %s", GetVersionString());
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gfx", aBuf, GPUInfoPrintColor);
AdjustViewport(true);
return 0;
}
@ -2460,6 +2525,7 @@ bool CGraphics_Threaded::SetWindowScreen(int Index)
}
m_pBackend->GetViewportSize(m_ScreenWidth, m_ScreenHeight);
AdjustViewport(true);
m_ScreenHiDPIScale = m_ScreenWidth / (float)g_Config.m_GfxScreenWidth;
return true;
}
@ -2475,6 +2541,7 @@ void CGraphics_Threaded::Move(int x, int y)
const int CurScreen = m_pBackend->GetWindowScreen();
m_pBackend->UpdateDisplayMode(CurScreen);
m_pBackend->GetViewportSize(m_ScreenWidth, m_ScreenHeight);
AdjustViewport(true);
m_ScreenHiDPIScale = m_ScreenWidth / (float)g_Config.m_GfxScreenWidth;
}
@ -2511,9 +2578,7 @@ void CGraphics_Threaded::GotResized(int w, int h, int RefreshRate)
// if the size change event is triggered, set all parameters and change the viewport
m_pBackend->GetViewportSize(m_ScreenWidth, m_ScreenHeight);
// adjust the viewport to only allow certain aspect ratios
if(m_ScreenHeight > 4 * m_ScreenWidth / 5)
m_ScreenHeight = 4 * m_ScreenWidth / 5;
AdjustViewport(false);
m_ScreenRefreshRate = RefreshRate;
@ -2635,14 +2700,16 @@ void CGraphics_Threaded::Swap()
}
}
// TODO: screenshot support
bool TookScreenshotAndSwapped = false;
if(m_DoScreenshot)
{
if(WindowActive())
ScreenshotDirect();
TookScreenshotAndSwapped = ScreenshotDirect();
m_DoScreenshot = false;
}
if(!TookScreenshotAndSwapped)
{
// add swap command
CCommandBuffer::SCommand_Swap Cmd;

View file

@ -61,6 +61,7 @@ class CCommandBuffer
public:
CBuffer m_CmdBuffer;
size_t m_CommandCount = 0;
size_t m_RenderCallCount = 0;
CBuffer m_DataBuffer;
@ -128,7 +129,7 @@ public:
// misc
CMD_VSYNC,
CMD_SCREENSHOT,
CMD_TRY_SWAP_AND_SCREENSHOT,
CMD_UPDATE_VIEWPORT,
// in Android a window that minimizes gets destroyed
@ -213,6 +214,7 @@ public:
SCommand_Clear() :
SCommand(CMD_CLEAR) {}
SColorf m_Color;
bool m_ForceClear;
};
struct SCommand_Signal : public SCommand
@ -477,11 +479,12 @@ public:
void *m_pOffset;
};
struct SCommand_Screenshot : public SCommand
struct SCommand_TrySwapAndScreenshot : public SCommand
{
SCommand_Screenshot() :
SCommand(CMD_SCREENSHOT) {}
SCommand_TrySwapAndScreenshot() :
SCommand(CMD_TRY_SWAP_AND_SCREENSHOT) {}
CImageInfo *m_pImage; // processor will fill this out, the one who adds this command must free the data as well
bool *m_pSwapped;
};
struct SCommand_Swap : public SCommand
@ -663,6 +666,12 @@ public:
m_DataBuffer.Reset();
m_CommandCount = 0;
m_RenderCallCount = 0;
}
void AddRenderCalls(size_t RenderCallCountToAdd)
{
m_RenderCallCount += RenderCallCountToAdd;
}
};
@ -733,7 +742,7 @@ public:
virtual bool IsIdle() const = 0;
virtual void WaitForIdle() = 0;
virtual void GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch) {}
virtual bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType) = 0;
// checks if the current values of the config are a graphics modern API
virtual bool IsConfigModernAPI() { return false; }
virtual bool UseTrianglesAsQuad() { return false; }
@ -806,6 +815,10 @@ class CGraphics_Threaded : public IEngineGraphics
std::vector<SWarning> m_Warnings;
// is a non full windowed (in a sense that the viewport won't include the whole window),
// forced viewport, so that it justifies our UI ratio needs
bool m_IsForcedViewport = false;
struct SVertexArrayInfo
{
SVertexArrayInfo() :
@ -906,6 +919,8 @@ class CGraphics_Threaded : public IEngineGraphics
void AddBackEndWarningIfExists();
void AdjustViewport(bool SendViewportChangeToBackend);
int IssueInit();
int InitWindow();
@ -962,11 +977,11 @@ public:
void CopyTextureBufferSub(uint8_t *pDestBuffer, uint8_t *pSourceBuffer, int FullWidth, int FullHeight, int ColorChannelCount, int SubOffsetX, int SubOffsetY, int SubCopyWidth, int SubCopyHeight) override;
void CopyTextureFromTextureBufferSub(uint8_t *pDestBuffer, int DestWidth, int DestHeight, uint8_t *pSourceBuffer, int SrcWidth, int SrcHeight, int ColorChannelCount, int SrcSubOffsetX, int SrcSubOffsetY, int SrcSubCopyWidth, int SrcSubCopyHeight) override;
void ScreenshotDirect();
bool ScreenshotDirect();
void TextureSet(CTextureHandle TextureID) override;
void Clear(float r, float g, float b) override;
void Clear(float r, float g, float b, bool ForceClearNow = false) override;
void QuadsBegin() override;
void QuadsEnd() override;
@ -1197,12 +1212,14 @@ public:
{
return;
}
m_pCommandBuffer->AddRenderCalls(1);
}
void FlushVertices(bool KeepVertices = false) override;
void FlushVerticesTex3D() override;
void RenderTileLayer(int BufferContainerIndex, float *pColor, char **pOffsets, unsigned int *IndicedVertexDrawNum, size_t NumIndicesOffet) override;
void RenderTileLayer(int BufferContainerIndex, float *pColor, char **pOffsets, unsigned int *IndicedVertexDrawNum, size_t NumIndicesOffset) override;
void RenderBorderTiles(int BufferContainerIndex, float *pColor, char *pIndexBufferOffset, float *pOffset, float *pDir, int JumpIndex, unsigned int DrawNum) override;
void RenderBorderTileLines(int BufferContainerIndex, float *pColor, char *pIndexBufferOffset, float *pOffset, float *pDir, unsigned int IndexDrawNum, unsigned int RedrawNum) override;
void RenderQuadLayer(int BufferContainerIndex, SQuadRenderInfo *pQuadInfo, int QuadNum, int QuadOffset) override;
@ -1261,7 +1278,7 @@ public:
SWarning *GetCurWarning() override;
void GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch) override { m_pBackend->GetDriverVersion(DriverAgeType, Major, Minor, Patch); }
bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType) override { return m_pBackend->GetDriverVersion(DriverAgeType, Major, Minor, Patch, pName, BackendType); }
bool IsConfigModernAPI() override { return m_pBackend->IsConfigModernAPI(); }
bool IsTileBufferingEnabled() override { return m_GLTileBufferingEnabled; }
bool IsQuadBufferingEnabled() override { return m_GLQuadBufferingEnabled; }

View file

@ -82,7 +82,7 @@ public:
void TextureSet(CTextureHandle TextureID) override{};
void Clear(float r, float g, float b) override{};
void Clear(float r, float g, float b, bool ForceClearNow = false) override{};
void QuadsBegin() override{};
void QuadsEnd() override{};
@ -138,7 +138,7 @@ public:
void FlushVertices(bool KeepVertices = false) override{};
void FlushVerticesTex3D() override{};
void RenderTileLayer(int BufferContainerIndex, float *pColor, char **pOffsets, unsigned int *IndicedVertexDrawNum, size_t NumIndicesOffet) override{};
void RenderTileLayer(int BufferContainerIndex, float *pColor, char **pOffsets, unsigned int *IndicedVertexDrawNum, size_t NumIndicesOffset) override{};
void RenderBorderTiles(int BufferContainerIndex, float *pColor, char *pIndexBufferOffset, float *pOffset, float *pDir, int JumpIndex, unsigned int DrawNum) override{};
void RenderBorderTileLines(int BufferContainerIndex, float *pColor, char *pIndexBufferOffset, float *pOffset, float *pDir, unsigned int IndexDrawNum, unsigned int RedrawNum) override{};
void RenderQuadLayer(int BufferContainerIndex, SQuadRenderInfo *pQuadInfo, int QuadNum, int QuadOffset) override{};
@ -194,7 +194,7 @@ public:
SWarning *GetCurWarning() override { return NULL; }
void GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch) override {}
bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType) override { return false; }
bool IsConfigModernAPI() override { return false; }
bool IsTileBufferingEnabled() override { return false; }
bool IsQuadBufferingEnabled() override { return false; }

View file

@ -42,6 +42,8 @@ struct SQuadRenderInfo
float m_aColor[4];
float m_aOffsets[2];
float m_Rotation;
// allows easier upload for uniform buffers because of the alignment requirements
float m_Padding;
};
struct SGraphicTile
@ -151,11 +153,28 @@ struct GL_SVertexTex3DStream
GL_STexCoord3D m_Tex;
};
static constexpr size_t gs_GraphicsMaxQuadsRenderCount = 256;
static constexpr size_t gs_GraphicsMaxParticlesRenderCount = 512;
enum EGraphicsDriverAgeType
{
GRAPHICS_DRIVER_AGE_TYPE_LEGACY = 0,
GRAPHICS_DRIVER_AGE_TYPE_DEFAULT,
GRAPHICS_DRIVER_AGE_TYPE_MODERN,
GRAPHICS_DRIVER_AGE_TYPE_COUNT,
};
enum EBackendType
{
BACKEND_TYPE_OPENGL = 0,
BACKEND_TYPE_OPENGL_ES,
BACKEND_TYPE_VULKAN,
// special value to tell the backend to identify the current backend
BACKEND_TYPE_AUTO,
BACKEND_TYPE_COUNT,
};
struct STWGraphicGPU
@ -235,7 +254,8 @@ public:
virtual void WindowDestroyNtf(uint32_t WindowID) = 0;
virtual void WindowCreateNtf(uint32_t WindowID) = 0;
virtual void Clear(float r, float g, float b) = 0;
// ForceClearNow forces the backend to trigger a clear, even at performance cost, else it might be delayed by one frame
virtual void Clear(float r, float g, float b, bool ForceClearNow = false) = 0;
virtual void ClipEnable(int x, int y, int w, int h) = 0;
virtual void ClipDisable() = 0;
@ -291,7 +311,7 @@ public:
virtual void FlushVerticesTex3D() = 0;
// specific render functions
virtual void RenderTileLayer(int BufferContainerIndex, float *pColor, char **pOffsets, unsigned int *IndicedVertexDrawNum, size_t NumIndicesOffet) = 0;
virtual void RenderTileLayer(int BufferContainerIndex, float *pColor, char **pOffsets, unsigned int *IndicedVertexDrawNum, size_t NumIndicesOffset) = 0;
virtual void RenderBorderTiles(int BufferContainerIndex, float *pColor, char *pIndexBufferOffset, float *pOffset, float *pDir, int JumpIndex, unsigned int DrawNum) = 0;
virtual void RenderBorderTileLines(int BufferContainerIndex, float *pColor, char *pIndexBufferOffset, float *pOffset, float *pDir, unsigned int IndexDrawNum, unsigned int RedrawNum) = 0;
virtual void RenderQuadLayer(int BufferContainerIndex, SQuadRenderInfo *pQuadInfo, int QuadNum, int QuadOffset) = 0;
@ -315,7 +335,8 @@ public:
virtual void DeleteBufferContainer(int ContainerIndex, bool DestroyAllBO = true) = 0;
virtual void IndicesNumRequiredNotify(unsigned int RequiredIndicesCount) = 0;
virtual void GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch) = 0;
// returns true if the driver age type is supported, passing BACKEND_TYPE_AUTO for BackendType will query the values for the currently used backend
virtual bool GetDriverVersion(EGraphicsDriverAgeType DriverAgeType, int &Major, int &Minor, int &Patch, const char *&pName, EBackendType BackendType) = 0;
virtual bool IsConfigModernAPI() = 0;
virtual bool IsTileBufferingEnabled() = 0;
virtual bool IsQuadBufferingEnabled() = 0;
@ -440,6 +461,7 @@ public:
virtual void NotifyWindow() = 0;
// be aware that this function should only be called from the graphics thread, and even then you should really know what you are doing
// this function always returns the pixels in RGB
virtual TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() = 0;
virtual SWarning *GetCurWarning() = 0;

View file

@ -178,7 +178,7 @@ MACRO_CONFIG_INT(DbgCurl, dbg_curl, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SERVER, "D
MACRO_CONFIG_INT(DbgPref, dbg_pref, 0, 0, 1, CFGFLAG_SERVER, "Performance outputs")
MACRO_CONFIG_INT(DbgGraphs, dbg_graphs, 0, 0, 1, CFGFLAG_CLIENT, "Performance graphs")
MACRO_CONFIG_INT(DbgHitch, dbg_hitch, 0, 0, 0, CFGFLAG_SERVER, "Hitch warnings")
MACRO_CONFIG_INT(DbgGfx, dbg_gfx, 0, 0, 4, CFGFLAG_CLIENT, "Show graphic library warnings and errors, if the GPU supports it (0: none, 1: minimal, 2: affects performance, 3: verbose, 4: all")
MACRO_CONFIG_INT(DbgGfx, dbg_gfx, 0, 0, 4, CFGFLAG_CLIENT, "Show graphic library warnings and errors, if the GPU supports it (0: none, 1: minimal, 2: affects performance, 3: verbose, 4: all)")
#ifdef CONF_DEBUG
MACRO_CONFIG_INT(DbgStress, dbg_stress, 0, 0, 0, CFGFLAG_CLIENT | CFGFLAG_SERVER, "Stress systems (Debug build only)")
MACRO_CONFIG_INT(DbgStressNetwork, dbg_stress_network, 0, 0, 0, CFGFLAG_CLIENT | CFGFLAG_SERVER, "Stress network (Debug build only)")
@ -418,7 +418,7 @@ MACRO_CONFIG_STR(Gfx3DTextureAnalysisRenderer, gfx_3d_texture_analysis_renderer,
MACRO_CONFIG_STR(Gfx3DTextureAnalysisVersion, gfx_3d_texture_analysis_version, 128, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The version on which the analysis was performed")
MACRO_CONFIG_STR(GfxGPUName, gfx_gpu_name, 256, "auto", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The GPU's name, which will be selected by the backend. (if supported by the backend)")
MACRO_CONFIG_STR(GfxBackend, gfx_backend, 256, "auto", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The backend to use (e.g. opengl or vulkan)")
MACRO_CONFIG_STR(GfxBackend, gfx_backend, 256, "OpenGL", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The backend to use (e.g. OpenGL or Vulkan)")
MACRO_CONFIG_INT(GfxRenderThreadCount, gfx_render_thread_count, 3, 0, 0, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Number of threads the backend can use for rendering. (note: the value can be ignored by the backend)")
MACRO_CONFIG_INT(GfxDriverIsBlocked, gfx_driver_is_blocked, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "If 1, the current driver is in a blocked error state.")

View file

@ -844,6 +844,7 @@ void CMapLayers::OnMapLoad()
// then create the buffer container
SBufferContainerInfo ContainerInfo;
ContainerInfo.m_Stride = (DoTextureCoords ? (sizeof(float) * 2 + sizeof(vec3)) : 0);
ContainerInfo.m_VertBufferBindingIndex = BufferObjectIndex;
ContainerInfo.m_Attributes.emplace_back();
SBufferContainerInfo::SAttribute *pAttr = &ContainerInfo.m_Attributes.back();
pAttr->m_DataTypeCount = 2;
@ -946,6 +947,7 @@ void CMapLayers::OnMapLoad()
// then create the buffer container
SBufferContainerInfo ContainerInfo;
ContainerInfo.m_Stride = (Textured ? (sizeof(STmpQuadTextured) / 4) : (sizeof(STmpQuad) / 4));
ContainerInfo.m_VertBufferBindingIndex = BufferObjectIndex;
ContainerInfo.m_Attributes.emplace_back();
SBufferContainerInfo::SAttribute *pAttr = &ContainerInfo.m_Attributes.back();
pAttr->m_DataTypeCount = 4;
@ -1401,6 +1403,17 @@ void CMapLayers::RenderQuadLayer(int LayerIndex, CMapItemLayerQuads *pQuadLayer,
Rot = aChannels[2] / 180.0f * pi;
}
bool NeedsFlush = QuadsRenderCount == gs_GraphicsMaxQuadsRenderCount || !(aColor[3] > 0);
if(NeedsFlush)
{
// render quads of the current offset directly(cancel batching)
Graphics()->RenderQuadLayer(Visuals.m_BufferContainerIndex, &s_QuadRenderInfo[0], QuadsRenderCount, CurQuadOffset);
QuadsRenderCount = 0;
// since this quad is ignored, the offset is the next quad
CurQuadOffset = i + 1;
}
if(aColor[3] > 0)
{
SQuadRenderInfo &QInfo = s_QuadRenderInfo[QuadsRenderCount++];
@ -1409,14 +1422,6 @@ void CMapLayers::RenderQuadLayer(int LayerIndex, CMapItemLayerQuads *pQuadLayer,
QInfo.m_aOffsets[1] = OffsetY;
QInfo.m_Rotation = Rot;
}
else
{
// render quads of the current offset directly(cancel batching)
Graphics()->RenderQuadLayer(Visuals.m_BufferContainerIndex, &s_QuadRenderInfo[0], QuadsRenderCount, CurQuadOffset);
QuadsRenderCount = 0;
// since this quad is ignored, the offset is the next quad
CurQuadOffset = i + 1;
}
}
Graphics()->RenderQuadLayer(Visuals.m_BufferContainerIndex, &s_QuadRenderInfo[0], QuadsRenderCount, CurQuadOffset);
}

View file

@ -35,6 +35,8 @@
#include <utility>
#include <vector>
#include <array>
CMenusKeyBinder CMenus::m_Binder;
CMenusKeyBinder::CMenusKeyBinder()
@ -1100,9 +1102,7 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
static CVideoMode s_aModes[MAX_RESOLUTIONS];
static int s_NumNodes = Graphics()->GetVideoModes(s_aModes, MAX_RESOLUTIONS, g_Config.m_GfxScreen);
static int s_GfxFsaaSamples = g_Config.m_GfxFsaaSamples;
static int s_GfxModernGLVersion = Graphics()->IsConfigModernAPI();
static int s_GfxEnableTextureUnitOptimization = g_Config.m_GfxEnableTextureUnitOptimization;
static int s_GfxUsePreinitBuffer = g_Config.m_GfxUsePreinitBuffer;
static bool s_GfxBackendChanged = false;
static int s_GfxHighdpi = g_Config.m_GfxHighdpi;
static int s_InitDisplayAllVideoModes = g_Config.m_GfxDisplayAllVideoModes;
@ -1185,6 +1185,8 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
aWindowModeIDs[i] = &s_aWindowModeIDs[i];
static int s_WindowModeDropDownState = 0;
static int s_OldSelectedBackend = -1;
OldSelected = (g_Config.m_GfxFullscreen ? (g_Config.m_GfxFullscreen == 1 ? 4 : (g_Config.m_GfxFullscreen == 2 ? 3 : 2)) : (g_Config.m_GfxBorderless ? 1 : 0));
const int NewWindowMode = RenderDropDown(s_WindowModeDropDownState, &MainView, OldSelected, aWindowModeIDs, pWindowModes, s_NumWindowMode, &s_NumWindowMode, s_ScrollValueDrop);
@ -1244,46 +1246,6 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
if(DoButton_CheckBox(&g_Config.m_GfxHighDetail, Localize("High Detail"), g_Config.m_GfxHighDetail, &Button))
g_Config.m_GfxHighDetail ^= 1;
bool IsModernGL = Graphics()->IsConfigModernAPI();
// only promote modern GL in menu settings if the driver isn't on the blocklist already
if(g_Config.m_GfxDriverIsBlocked == 0)
{
MainView.HSplitTop(20.0f, &Button, &MainView);
if(DoButton_CheckBox(&g_Config.m_GfxGLMajor, Localize("Use modern OpenGL"), IsModernGL, &Button))
{
CheckSettings = true;
if(IsModernGL)
{
Graphics()->GetDriverVersion(GRAPHICS_DRIVER_AGE_TYPE_DEFAULT, g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch);
IsModernGL = false;
}
else
{
Graphics()->GetDriverVersion(GRAPHICS_DRIVER_AGE_TYPE_MODERN, g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch);
IsModernGL = true;
}
}
if(IsModernGL)
{
MainView.HSplitTop(20.0f, &Button, &MainView);
if(DoButton_CheckBox(&g_Config.m_GfxUsePreinitBuffer, Localize("Preinit VBO (iGPUs only)"), g_Config.m_GfxUsePreinitBuffer, &Button))
{
CheckSettings = true;
g_Config.m_GfxUsePreinitBuffer ^= 1;
}
MainView.HSplitTop(20.0f, &Button, &MainView);
if(DoButton_CheckBox(&g_Config.m_GfxEnableTextureUnitOptimization, Localize("Multiple texture units (disable for macOS)"), g_Config.m_GfxEnableTextureUnitOptimization, &Button))
{
CheckSettings = true;
g_Config.m_GfxEnableTextureUnitOptimization ^= 1;
}
}
}
MainView.HSplitTop(20.0f, &Button, &MainView);
if(DoButton_CheckBox(&g_Config.m_GfxHighdpi, Localize("Use high DPI"), g_Config.m_GfxHighdpi, &Button))
{
@ -1291,16 +1253,6 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
g_Config.m_GfxHighdpi ^= 1;
}
// check if the new settings require a restart
if(CheckSettings)
{
m_NeedRestartGraphics = !(s_GfxFsaaSamples == g_Config.m_GfxFsaaSamples &&
s_GfxModernGLVersion == (int)IsModernGL &&
s_GfxUsePreinitBuffer == g_Config.m_GfxUsePreinitBuffer &&
s_GfxEnableTextureUnitOptimization == g_Config.m_GfxEnableTextureUnitOptimization &&
s_GfxHighdpi == g_Config.m_GfxHighdpi);
}
MainView.HSplitTop(20.0f, &Label, &MainView);
Label.VSplitLeft(160.0f, &Label, &Button);
if(g_Config.m_GfxRefreshRate)
@ -1322,13 +1274,143 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
MainView.y = HSLBar.y;
MainView.h = MainView.h - MainView.y;
// Backend list
struct SMenuBackendInfo
{
int m_Major = 0;
int m_Minor = 0;
int m_Patch = 0;
const char *m_pBackendName = "";
bool m_Found = false;
};
std::array<std::array<SMenuBackendInfo, EGraphicsDriverAgeType::GRAPHICS_DRIVER_AGE_TYPE_COUNT>, EBackendType::BACKEND_TYPE_COUNT> aaSupportedBackends{};
uint32_t FoundBackendCount = 0;
for(uint32_t i = 0; i < BACKEND_TYPE_COUNT; ++i)
{
if(EBackendType(i) == BACKEND_TYPE_AUTO)
continue;
for(uint32_t n = 0; n < GRAPHICS_DRIVER_AGE_TYPE_COUNT; ++n)
{
auto &Info = aaSupportedBackends[i][n];
if(Graphics()->GetDriverVersion(EGraphicsDriverAgeType(n), Info.m_Major, Info.m_Minor, Info.m_Patch, Info.m_pBackendName, EBackendType(i)))
{
// don't count blocked opengl drivers
if(EBackendType(i) != BACKEND_TYPE_OPENGL || EGraphicsDriverAgeType(n) == GRAPHICS_DRIVER_AGE_TYPE_LEGACY || g_Config.m_GfxDriverIsBlocked == 0)
{
Info.m_Found = true;
++FoundBackendCount;
}
}
}
}
if(FoundBackendCount > 1)
{
MainView.HSplitTop(10.0f, nullptr, &MainView);
MainView.HSplitTop(20.0f, &Text, &MainView);
UI()->DoLabelScaled(&Text, Localize("Renderer"), 16.0f, TEXTALIGN_CENTER);
static float s_ScrollValueDropBackend = 0;
static int s_BackendDropDownState = 0;
static std::vector<std::unique_ptr<int>> vBackendIDs;
static std::vector<const void *> vBackendIDPtrs;
static std::vector<std::string> vBackendIDNames;
static std::vector<const char *> vBackendIDNamesCStr;
static std::vector<SMenuBackendInfo> vBackendInfos;
size_t BackendCount = FoundBackendCount + 1;
vBackendIDs.resize(BackendCount);
vBackendIDPtrs.resize(BackendCount);
vBackendIDNames.resize(BackendCount);
vBackendIDNamesCStr.resize(BackendCount);
vBackendInfos.resize(BackendCount);
char aTmpBackendName[256];
auto IsInfoDefault = [](const SMenuBackendInfo &CheckInfo) {
return str_comp_nocase(CheckInfo.m_pBackendName, "OpenGL") == 0 && CheckInfo.m_Major == 3 && CheckInfo.m_Minor == 0 && CheckInfo.m_Patch == 0;
};
int OldSelectedBackend = -1;
uint32_t CurCounter = 0;
for(uint32_t i = 0; i < BACKEND_TYPE_COUNT; ++i)
{
for(uint32_t n = 0; n < GRAPHICS_DRIVER_AGE_TYPE_COUNT; ++n)
{
auto &Info = aaSupportedBackends[i][n];
if(Info.m_Found)
{
if(vBackendIDs[CurCounter].get() == nullptr)
vBackendIDs[CurCounter] = std::make_unique<int>();
vBackendIDPtrs[CurCounter] = vBackendIDs[CurCounter].get();
{
bool IsDefault = IsInfoDefault(Info);
str_format(aTmpBackendName, sizeof(aTmpBackendName), "%s (%d.%d.%d)%s%s", Info.m_pBackendName, Info.m_Major, Info.m_Minor, Info.m_Patch, IsDefault ? " - " : "", IsDefault ? Localize("default") : "");
vBackendIDNames[CurCounter] = aTmpBackendName;
vBackendIDNamesCStr[CurCounter] = vBackendIDNames[CurCounter].c_str();
if(str_comp_nocase(Info.m_pBackendName, g_Config.m_GfxBackend) == 0 && g_Config.m_GfxGLMajor == Info.m_Major && g_Config.m_GfxGLMinor == Info.m_Minor && g_Config.m_GfxGLPatch == Info.m_Patch)
{
OldSelectedBackend = CurCounter;
}
vBackendInfos[CurCounter] = Info;
}
++CurCounter;
}
}
}
if(OldSelectedBackend != -1)
{
// no custom selected
BackendCount -= 1;
}
else
{
// custom selected one
if(vBackendIDs[CurCounter].get() == nullptr)
vBackendIDs[CurCounter] = std::make_unique<int>();
vBackendIDPtrs[CurCounter] = vBackendIDs[CurCounter].get();
str_format(aTmpBackendName, sizeof(aTmpBackendName), "%s (%s %d.%d.%d)", Localize("custom"), g_Config.m_GfxBackend, g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch);
vBackendIDNames[CurCounter] = aTmpBackendName;
vBackendIDNamesCStr[CurCounter] = vBackendIDNames[CurCounter].c_str();
OldSelectedBackend = CurCounter;
vBackendInfos[CurCounter].m_pBackendName = "custom";
vBackendInfos[CurCounter].m_Major = g_Config.m_GfxGLMajor;
vBackendInfos[CurCounter].m_Minor = g_Config.m_GfxGLMinor;
vBackendInfos[CurCounter].m_Patch = g_Config.m_GfxGLPatch;
}
if(s_OldSelectedBackend == -1)
s_OldSelectedBackend = OldSelectedBackend;
static int s_BackendCount = 0;
s_BackendCount = BackendCount;
const int NewBackend = RenderDropDown(s_BackendDropDownState, &MainView, OldSelectedBackend, vBackendIDPtrs.data(), vBackendIDNamesCStr.data(), s_BackendCount, &s_BackendCount, s_ScrollValueDropBackend);
if(OldSelectedBackend != NewBackend)
{
str_copy(g_Config.m_GfxBackend, vBackendInfos[NewBackend].m_pBackendName, sizeof(g_Config.m_GfxBackend));
g_Config.m_GfxGLMajor = vBackendInfos[NewBackend].m_Major;
g_Config.m_GfxGLMinor = vBackendInfos[NewBackend].m_Minor;
g_Config.m_GfxGLPatch = vBackendInfos[NewBackend].m_Patch;
CheckSettings = true;
s_GfxBackendChanged = s_OldSelectedBackend != NewBackend;
}
}
// GPU list
const auto &GPUList = Graphics()->GetGPUs();
if(GPUList.m_GPUs.size() > 1)
{
MainView.HSplitTop(10.0f, nullptr, &MainView);
MainView.HSplitTop(20.0f, &Text, &MainView);
UI()->DoLabelScaled(&Text, Localize("Graphic cards"), 16.0f, TEXTALIGN_CENTER);
UI()->DoLabelScaled(&Text, Localize("Graphics cards"), 16.0f, TEXTALIGN_CENTER);
static float s_ScrollValueDropGPU = 0;
static int s_GPUDropDownState = 0;
@ -1348,7 +1430,7 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
for(size_t i = 0; i < GPUCount; ++i)
{
if(vGPUIDs[i].get() == nullptr)
vGPUIDs[i] = std::unique_ptr<int>(new int());
vGPUIDs[i] = std::make_unique<int>();
vGPUIDPtrs[i] = vGPUIDs[i].get();
if(i == 0)
{
@ -1381,6 +1463,14 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
str_copy(g_Config.m_GfxGPUName, GPUList.m_GPUs[NewGPU - 1].m_Name, sizeof(g_Config.m_GfxGPUName));
}
}
// check if the new settings require a restart
if(CheckSettings)
{
m_NeedRestartGraphics = !(s_GfxFsaaSamples == g_Config.m_GfxFsaaSamples &&
!s_GfxBackendChanged &&
s_GfxHighdpi == g_Config.m_GfxHighdpi);
}
}
void CMenus::RenderSettingsSound(CUIRect MainView)

View file

@ -231,7 +231,7 @@ void CParticles::RenderGroup(int Group)
// the current position, respecting the size, is inside the viewport, render it, else ignore
if(ParticleIsVisibleOnScreen(p, Size))
{
if(LastColor[0] != m_aParticles[i].m_Color.r || LastColor[1] != m_aParticles[i].m_Color.g || LastColor[2] != m_aParticles[i].m_Color.b || LastColor[3] != m_aParticles[i].m_Color.a || LastQuadOffset != QuadOffset)
if((size_t)CurParticleRenderCount == gs_GraphicsMaxParticlesRenderCount || LastColor[0] != m_aParticles[i].m_Color.r || LastColor[1] != m_aParticles[i].m_Color.g || LastColor[2] != m_aParticles[i].m_Color.b || LastColor[3] != m_aParticles[i].m_Color.a || LastQuadOffset != QuadOffset)
{
Graphics()->TextureSet(GameClient()->m_ParticlesSkin.m_SpriteParticles[LastQuadOffset - SPRITE_PART_SLICE]);
Graphics()->RenderQuadContainerAsSpriteMultiple(m_ParticleQuadContainerIndex, LastQuadOffset, CurParticleRenderCount, s_aParticleRenderInfo);

View file

@ -5666,7 +5666,7 @@ void CEditor::RenderMenubar(CUIRect MenuBar)
void CEditor::Render()
{
// basic start
Graphics()->Clear(1.0f, 0.0f, 1.0f);
Graphics()->Clear(0.0f, 0.0f, 0.0f);
CUIRect View = *UI()->Screen();
UI()->MapScreen();