mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
Merge #4687
4687: Add Vulkan backend r=def- a=Jupeyy This adds a Vulkan 1.0 backend and new features to the graphic settings to select the GPU(if multiple Vulkan GPUs are supported, and a new list for renderers (see screenshot below)) Mutleasy benchmark (CPU bound): Vulkan multithreaded, single threaded vs OpenGL (lower graphs are histograms, code by `@Chairn` ) Y = Frametimes in microseconds lower graphs = amount of frametimes that happened (histogram) (since the renderer speed differs, you should look at it more like a spread of values rather than the actual values) ![Figure_1](https://user-images.githubusercontent.com/6654924/153448356-941222a3-8bd3-424d-8685-a43389a4f691.png) Vulkan is especially good in these scenarios, beating OpenGL 3.3 almost 3x with my setup (~600-700 FPS vs. ~1700-1800FPS) Remaining TODO list: - [x] compile shaders in cmake ( e.g. `https://gist.github.com/evilactually/a0d191701cb48f157b05be7f74d79396` ) - [ ] needs windows vulkan libraries - [x] add build instructions (packages) - [x] get away from coherent memory even for staging buffers (flushing memory just seems to be faster) - [ ] a lot of testing :P ![screenshot_2022-02-10_17-13-46](https://user-images.githubusercontent.com/6654924/153449066-38d8741b-60c1-4c0c-ba50-57cc07aa2f9d.png) ![screenshot_2022-02-10_17-13-50](https://user-images.githubusercontent.com/6654924/153449075-91ef3b7b-7238-4cad-9a4c-aeb2d784238b.png) If there are bugs and it's crashing inside the driver the best you can do is to start the client with `dbg_gfx 4` which will (if supported) add Khronos standard validation layers + verbose debugging information + validation layer extensions, e.g. a synchronization validation layer and validation errors reported by the GPU driver directly. (setting for dbg_gfx (0: none, 1: minimal, 2: affects performance, 3: verbose, 4: all)) edits: fixes #3547 (probably fixes it, fixed some data races) ## Checklist - [x] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [x] Tested in combination with possibly related configuration options - [ ] Written a unit test if it works standalone, system.c especially - [x] Considered possible null pointers and out of bounds array indexing - [x] Changed no physics that affect existing maps - [x] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Jupeyy <jupjopjap@gmail.com> Co-authored-by: Dennis Felsing <dennis@felsin9.de>
This commit is contained in:
commit
e632859707
8
.github/workflows/build.yaml
vendored
8
.github/workflows/build.yaml
vendored
|
@ -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
|
||||
|
|
2
.github/workflows/clang-tidy.yml
vendored
2
.github/workflows/clang-tidy.yml
vendored
|
@ -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
|
||||
|
|
2
.github/workflows/codeql-analysis.yaml
vendored
2
.github/workflows/codeql-analysis.yaml
vendored
|
@ -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
|
||||
|
|
2
.github/workflows/style.yml
vendored
2
.github/workflows/style.yml
vendored
|
@ -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=. ..
|
||||
|
|
|
@ -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 .)
|
||||
|
@ -1756,6 +1794,8 @@ if(CLIENT)
|
|||
list(APPEND TARGETS_OWN ${TARGET_STEAMAPI})
|
||||
|
||||
set_src(ENGINE_CLIENT GLOB_RECURSE src/engine/client
|
||||
backend/backend_base.cpp
|
||||
backend/backend_base.h
|
||||
backend/glsl_shader_compiler.cpp
|
||||
backend/glsl_shader_compiler.h
|
||||
backend/opengl/backend_opengl.cpp
|
||||
|
@ -1773,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
|
||||
|
@ -1960,6 +2002,8 @@ if(CLIENT)
|
|||
${OPUS_LIBRARIES}
|
||||
${OGG_LIBRARIES}
|
||||
|
||||
${VULKAN_LIBRARIES}
|
||||
|
||||
${TARGET_STEAMAPI}
|
||||
|
||||
${PLATFORM_CLIENT_LIBS}
|
||||
|
@ -2031,6 +2075,8 @@ if(CLIENT)
|
|||
${FFMPEG_INCLUDE_DIRS}
|
||||
${DISCORDSDK_INCLUDE_DIRS}
|
||||
|
||||
${VULKAN_INCLUDE_DIRS}
|
||||
|
||||
${PLATFORM_CLIENT_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
|
@ -2063,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()
|
||||
|
@ -2576,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()
|
||||
|
@ -2598,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)
|
||||
|
@ -2608,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)
|
||||
|
@ -2712,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()
|
||||
|
@ -2759,6 +2821,7 @@ unset(CPACK_SOURCE_FILES_INVERTED)
|
|||
unset(CPACK_TARGETS)
|
||||
unset(CPACK_DIRS)
|
||||
unset(CPACK_FILES)
|
||||
unset(CPACK_GEN_FILES)
|
||||
|
||||
include(CPack)
|
||||
|
||||
|
|
12
README.md
12
README.md
|
@ -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.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
status = [
|
||||
"build-cmake (ubuntu-latest)",
|
||||
"build-cmake (ubuntu-18.04)",
|
||||
"build-cmake (ubuntu-20.04)",
|
||||
"build-cmake (macOS-latest)",
|
||||
"build-cmake (windows-latest)",
|
||||
"check-clang-tidy",
|
||||
|
|
175
cmake/BuildVulkanShaders.cmake
Normal file
175
cmake/BuildVulkanShaders.cmake
Normal 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
61
cmake/FindVulkan.cmake
Normal 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 |
20
data/shader/vulkan/prim.frag
Normal file
20
data/shader/vulkan/prim.frag
Normal 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
|
||||
}
|
20
data/shader/vulkan/prim.vert
Normal file
20
data/shader/vulkan/prim.vert
Normal 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);
|
||||
}
|
24
data/shader/vulkan/prim3d.frag
Normal file
24
data/shader/vulkan/prim3d.frag
Normal 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
|
||||
}
|
||||
|
24
data/shader/vulkan/prim3d.vert
Normal file
24
data/shader/vulkan/prim3d.vert
Normal 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;
|
||||
}
|
24
data/shader/vulkan/primex.frag
Normal file
24
data/shader/vulkan/primex.frag
Normal 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
|
||||
}
|
33
data/shader/vulkan/primex.vert
Normal file
33
data/shader/vulkan/primex.vert
Normal 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;
|
||||
}
|
62
data/shader/vulkan/quad.frag
Normal file
62
data/shader/vulkan/quad.frag
Normal 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
|
||||
}
|
83
data/shader/vulkan/quad.vert
Normal file
83
data/shader/vulkan/quad.vert
Normal 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
|
||||
}
|
13
data/shader/vulkan/quadbo.vertfrag
Normal file
13
data/shader/vulkan/quadbo.vertfrag
Normal 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;
|
||||
|
23
data/shader/vulkan/spritemulti.frag
Normal file
23
data/shader/vulkan/spritemulti.frag
Normal 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;
|
||||
}
|
50
data/shader/vulkan/spritemulti.vert
Normal file
50
data/shader/vulkan/spritemulti.vert
Normal 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;
|
||||
}
|
43
data/shader/vulkan/text.frag
Normal file
43
data/shader/vulkan/text.frag
Normal 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);
|
||||
}
|
22
data/shader/vulkan/text.vert
Normal file
22
data/shader/vulkan/text.vert
Normal 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;
|
||||
}
|
25
data/shader/vulkan/tile.frag
Normal file
25
data/shader/vulkan/tile.frag
Normal 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
|
||||
}
|
49
data/shader/vulkan/tile.vert
Normal file
49
data/shader/vulkan/tile.vert
Normal 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
|
||||
}
|
|
@ -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
|
||||
|
|
41
src/engine/client/backend/backend_base.cpp
Normal file
41
src/engine/client/backend/backend_base.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include "backend_base.h"
|
||||
#include "engine/shared/image_manipulation.h"
|
||||
|
||||
size_t CCommandProcessorFragment_GLBase::TexFormatToImageColorChannelCount(int TexFormat)
|
||||
{
|
||||
if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA)
|
||||
return 4;
|
||||
return 4;
|
||||
}
|
||||
|
||||
void *CCommandProcessorFragment_GLBase::Resize(const unsigned char *pData, int Width, int Height, int NewWidth, int NewHeight, int BPP)
|
||||
{
|
||||
return ResizeImage((const uint8_t *)pData, Width, Height, NewWidth, NewHeight, BPP);
|
||||
}
|
||||
|
||||
bool CCommandProcessorFragment_GLBase::Texture2DTo3D(void *pImageBuffer, int ImageWidth, int ImageHeight, int ImageColorChannelCount, int SplitCountWidth, int SplitCountHeight, void *pTarget3DImageData, int &Target3DImageWidth, int &Target3DImageHeight)
|
||||
{
|
||||
Target3DImageWidth = ImageWidth / SplitCountWidth;
|
||||
Target3DImageHeight = ImageHeight / SplitCountHeight;
|
||||
|
||||
size_t FullImageWidth = (size_t)ImageWidth * ImageColorChannelCount;
|
||||
|
||||
for(int Y = 0; Y < SplitCountHeight; ++Y)
|
||||
{
|
||||
for(int X = 0; X < SplitCountWidth; ++X)
|
||||
{
|
||||
for(int Y3D = 0; Y3D < Target3DImageHeight; ++Y3D)
|
||||
{
|
||||
int DepthIndex = X + Y * SplitCountWidth;
|
||||
|
||||
size_t TargetImageFullWidth = (size_t)Target3DImageWidth * ImageColorChannelCount;
|
||||
size_t TargetImageFullSize = (size_t)TargetImageFullWidth * Target3DImageHeight;
|
||||
ptrdiff_t ImageOffset = (ptrdiff_t)(((size_t)Y * FullImageWidth * (size_t)Target3DImageHeight) + ((size_t)Y3D * FullImageWidth) + ((size_t)X * TargetImageFullWidth));
|
||||
ptrdiff_t TargetImageOffset = (ptrdiff_t)(TargetImageFullSize * (size_t)DepthIndex + ((size_t)Y3D * TargetImageFullWidth));
|
||||
mem_copy(((uint8_t *)pTarget3DImageData) + TargetImageOffset, ((uint8_t *)pImageBuffer) + (ptrdiff_t)(ImageOffset), TargetImageFullWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
111
src/engine/client/backend/backend_base.h
Normal file
111
src/engine/client/backend/backend_base.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
#ifndef ENGINE_CLIENT_BACKEND_BACKEND_BASE_H
|
||||
#define ENGINE_CLIENT_BACKEND_BACKEND_BASE_H
|
||||
|
||||
#include "../backend_sdl.h"
|
||||
#include "engine/graphics.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
enum EDebugGFXModes
|
||||
{
|
||||
DEBUG_GFX_MODE_NONE = 0,
|
||||
DEBUG_GFX_MODE_MINIMUM,
|
||||
DEBUG_GFX_MODE_AFFECTS_PERFORMANCE,
|
||||
DEBUG_GFX_MODE_VERBOSE,
|
||||
DEBUG_GFX_MODE_ALL,
|
||||
};
|
||||
|
||||
class CCommandProcessorFragment_GLBase
|
||||
{
|
||||
protected:
|
||||
static size_t TexFormatToImageColorChannelCount(int TexFormat);
|
||||
static void *Resize(const unsigned char *pData, int Width, int Height, int NewWidth, int NewHeight, int BPP);
|
||||
|
||||
static bool Texture2DTo3D(void *pImageBuffer, int ImageWidth, int ImageHeight, int ImageColorChannelCount, int SplitCountWidth, int SplitCountHeight, void *pTarget3DImageData, int &Target3DImageWidth, int &Target3DImageHeight);
|
||||
|
||||
virtual bool GetPresentedImageData(uint32_t &Width, uint32_t &Height, uint32_t &Format, std::vector<uint8_t> &DstData) = 0;
|
||||
|
||||
public:
|
||||
virtual ~CCommandProcessorFragment_GLBase() = default;
|
||||
virtual bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand) = 0;
|
||||
|
||||
virtual void StartCommands(size_t CommandCount, size_t EstimatedRenderCallCount) {}
|
||||
virtual void EndCommands() {}
|
||||
|
||||
enum
|
||||
{
|
||||
CMD_PRE_INIT = CCommandBuffer::CMDGROUP_PLATFORM_GL,
|
||||
CMD_INIT,
|
||||
CMD_SHUTDOWN,
|
||||
CMD_POST_SHUTDOWN,
|
||||
};
|
||||
|
||||
struct SCommand_PreInit : public CCommandBuffer::SCommand
|
||||
{
|
||||
SCommand_PreInit() :
|
||||
SCommand(CMD_PRE_INIT) {}
|
||||
|
||||
SDL_Window *m_pWindow;
|
||||
uint32_t m_Width;
|
||||
uint32_t m_Height;
|
||||
|
||||
char *m_pVendorString;
|
||||
char *m_pVersionString;
|
||||
char *m_pRendererString;
|
||||
|
||||
TTWGraphicsGPUList *m_pGPUList;
|
||||
};
|
||||
|
||||
struct SCommand_Init : public CCommandBuffer::SCommand
|
||||
{
|
||||
SCommand_Init() :
|
||||
SCommand(CMD_INIT) {}
|
||||
|
||||
SDL_Window *m_pWindow;
|
||||
uint32_t m_Width;
|
||||
uint32_t m_Height;
|
||||
|
||||
class IStorage *m_pStorage;
|
||||
std::atomic<uint64_t> *m_pTextureMemoryUsage;
|
||||
std::atomic<uint64_t> *m_pBufferMemoryUsage;
|
||||
std::atomic<uint64_t> *m_pStreamMemoryUsage;
|
||||
std::atomic<uint64_t> *m_pStagingMemoryUsage;
|
||||
|
||||
TTWGraphicsGPUList *m_pGPUList;
|
||||
|
||||
TGLBackendReadPresentedImageData *m_pReadPresentedImageDataFunc;
|
||||
|
||||
SBackendCapabilites *m_pCapabilities;
|
||||
int *m_pInitError;
|
||||
|
||||
const char **m_pErrStringPtr;
|
||||
|
||||
char *m_pVendorString;
|
||||
char *m_pVersionString;
|
||||
char *m_pRendererString;
|
||||
|
||||
int m_RequestedMajor;
|
||||
int m_RequestedMinor;
|
||||
int m_RequestedPatch;
|
||||
|
||||
EBackendType m_RequestedBackend;
|
||||
|
||||
int m_GlewMajor;
|
||||
int m_GlewMinor;
|
||||
int m_GlewPatch;
|
||||
};
|
||||
|
||||
struct SCommand_Shutdown : public CCommandBuffer::SCommand
|
||||
{
|
||||
SCommand_Shutdown() :
|
||||
SCommand(CMD_SHUTDOWN) {}
|
||||
};
|
||||
|
||||
struct SCommand_PostShutdown : public CCommandBuffer::SCommand
|
||||
{
|
||||
SCommand_PostShutdown() :
|
||||
SCommand(CMD_POST_SHUTDOWN) {}
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,4 +1,5 @@
|
|||
#include "backend_opengl.h"
|
||||
#include "engine/graphics.h"
|
||||
|
||||
#include <base/detect.h>
|
||||
|
||||
|
@ -29,6 +30,11 @@
|
|||
// ------------ CCommandProcessorFragment_OpenGL
|
||||
void CCommandProcessorFragment_OpenGL::Cmd_Update_Viewport(const CCommandBuffer::SCommand_Update_Viewport *pCommand)
|
||||
{
|
||||
if(pCommand->m_ByResize)
|
||||
{
|
||||
m_CanvasWidth = (uint32_t)pCommand->m_Width;
|
||||
m_CanvasHeight = (uint32_t)pCommand->m_Height;
|
||||
}
|
||||
glViewport(pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height);
|
||||
}
|
||||
|
||||
|
@ -37,60 +43,23 @@ void CCommandProcessorFragment_OpenGL::Cmd_Finish(const CCommandBuffer::SCommand
|
|||
glFinish();
|
||||
}
|
||||
|
||||
bool CCommandProcessorFragment_OpenGL::Texture2DTo3D(void *pImageBuffer, int ImageWidth, int ImageHeight, int ImageColorChannelCount, int SplitCountWidth, int SplitCountHeight, void *pTarget3DImageData, int &Target3DImageWidth, int &Target3DImageHeight)
|
||||
{
|
||||
Target3DImageWidth = ImageWidth / SplitCountWidth;
|
||||
Target3DImageHeight = ImageHeight / SplitCountHeight;
|
||||
|
||||
size_t FullImageWidth = (size_t)ImageWidth * ImageColorChannelCount;
|
||||
|
||||
for(int Y = 0; Y < SplitCountHeight; ++Y)
|
||||
{
|
||||
for(int X = 0; X < SplitCountWidth; ++X)
|
||||
{
|
||||
for(int Y3D = 0; Y3D < Target3DImageHeight; ++Y3D)
|
||||
{
|
||||
int DepthIndex = X + Y * SplitCountWidth;
|
||||
|
||||
size_t TargetImageFullWidth = (size_t)Target3DImageWidth * ImageColorChannelCount;
|
||||
size_t TargetImageFullSize = (size_t)TargetImageFullWidth * Target3DImageHeight;
|
||||
ptrdiff_t ImageOffset = (ptrdiff_t)(((size_t)Y * FullImageWidth * (size_t)Target3DImageHeight) + ((size_t)Y3D * FullImageWidth) + ((size_t)X * TargetImageFullWidth));
|
||||
ptrdiff_t TargetImageOffset = (ptrdiff_t)(TargetImageFullSize * (size_t)DepthIndex + ((size_t)Y3D * TargetImageFullWidth));
|
||||
mem_copy(((uint8_t *)pTarget3DImageData) + TargetImageOffset, ((uint8_t *)pImageBuffer) + (ptrdiff_t)(ImageOffset), TargetImageFullWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CCommandProcessorFragment_OpenGL::TexFormatToOpenGLFormat(int TexFormat)
|
||||
{
|
||||
if(TexFormat == CCommandBuffer::TEXFORMAT_RGB)
|
||||
return GL_RGB;
|
||||
if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA)
|
||||
return GL_ALPHA;
|
||||
if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA)
|
||||
return GL_RGBA;
|
||||
return GL_RGBA;
|
||||
}
|
||||
|
||||
int CCommandProcessorFragment_OpenGL::TexFormatToImageColorChannelCount(int TexFormat)
|
||||
size_t CCommandProcessorFragment_OpenGL::GLFormatToImageColorChannelCount(int GLFormat)
|
||||
{
|
||||
if(TexFormat == CCommandBuffer::TEXFORMAT_RGB)
|
||||
return 3;
|
||||
if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA)
|
||||
return 1;
|
||||
if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA)
|
||||
return 4;
|
||||
return 4;
|
||||
}
|
||||
|
||||
void *CCommandProcessorFragment_OpenGL::Resize(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData)
|
||||
{
|
||||
int Bpp = TexFormatToImageColorChannelCount(Format);
|
||||
|
||||
return ResizeImage((const uint8_t *)pData, Width, Height, NewWidth, NewHeight, Bpp);
|
||||
switch(GLFormat)
|
||||
{
|
||||
case GL_RGBA: return 4;
|
||||
case GL_RGB: return 3;
|
||||
case GL_RED: return 1;
|
||||
case GL_ALPHA: return 1;
|
||||
default: return 4;
|
||||
}
|
||||
}
|
||||
|
||||
bool CCommandProcessorFragment_OpenGL::IsTexturedState(const CCommandBuffer::SState &State)
|
||||
|
@ -312,10 +281,44 @@ GfxOpenGLMessageCallback(GLenum source,
|
|||
}
|
||||
#endif
|
||||
|
||||
bool CCommandProcessorFragment_OpenGL::GetPresentedImageData(uint32_t &Width, uint32_t &Height, uint32_t &Format, std::vector<uint8_t> &DstData)
|
||||
{
|
||||
if(m_CanvasWidth == 0 || m_CanvasHeight == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Width = m_CanvasWidth;
|
||||
Height = m_CanvasHeight;
|
||||
Format = CImageInfo::FORMAT_RGBA;
|
||||
DstData.resize((size_t)Width * (Height + 1) * 4); // +1 for flipping image
|
||||
glReadBuffer(GL_FRONT);
|
||||
GLint Alignment;
|
||||
glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(0, 0, m_CanvasWidth, m_CanvasHeight, GL_RGBA, GL_UNSIGNED_BYTE, DstData.data());
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, Alignment);
|
||||
|
||||
uint8_t *pTempRow = DstData.data() + Width * Height * 4;
|
||||
for(uint32_t Y = 0; Y < Height / 2; ++Y)
|
||||
{
|
||||
mem_copy(pTempRow, DstData.data() + Y * Width * 4, Width * 4);
|
||||
mem_copy(DstData.data() + Y * Width * 4, DstData.data() + ((Height - Y) - 1) * Width * 4, Width * 4);
|
||||
mem_copy(DstData.data() + ((Height - Y) - 1) * Width * 4, pTempRow, Width * 4);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool CCommandProcessorFragment_OpenGL::InitOpenGL(const SCommand_Init *pCommand)
|
||||
{
|
||||
m_IsOpenGLES = pCommand->m_RequestedBackend == BACKEND_TYPE_OPENGL_ES;
|
||||
|
||||
TGLBackendReadPresentedImageData &ReadPresentedImgDataFunc = *pCommand->m_pReadPresentedImageDataFunc;
|
||||
ReadPresentedImgDataFunc = [this](uint32_t &Width, uint32_t &Height, uint32_t &Format, std::vector<uint8_t> &DstData) { return GetPresentedImageData(Width, Height, Format, DstData); };
|
||||
|
||||
const char *pVendorString = (const char *)glGetString(GL_VENDOR);
|
||||
dbg_msg("opengl", "Vendor string: %s", pVendorString);
|
||||
|
||||
|
@ -337,7 +340,7 @@ bool CCommandProcessorFragment_OpenGL::InitOpenGL(const SCommand_Init *pCommand)
|
|||
int BlocklistMajor = -1, BlocklistMinor = -1, BlocklistPatch = -1;
|
||||
bool RequiresWarning = false;
|
||||
const char *pErrString = ParseBlocklistDriverVersions(pVendorString, pVersionString, BlocklistMajor, BlocklistMinor, BlocklistPatch, RequiresWarning);
|
||||
//if the driver is buggy, and the requested GL version is the default, fallback
|
||||
// if the driver is buggy, and the requested GL version is the default, fallback
|
||||
if(pErrString != NULL && pCommand->m_RequestedMajor == 3 && pCommand->m_RequestedMinor == 0 && pCommand->m_RequestedPatch == 0)
|
||||
{
|
||||
// if not already in the error state, set the GL version
|
||||
|
@ -405,6 +408,7 @@ bool CCommandProcessorFragment_OpenGL::InitOpenGL(const SCommand_Init *pCommand)
|
|||
|
||||
pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension = false;
|
||||
pCommand->m_pCapabilities->m_NPOTTextures = true;
|
||||
pCommand->m_pCapabilities->m_TrianglesAsQuads = false;
|
||||
|
||||
if(MajorV >= 4 || (MajorV == 3 && MinorV == 3))
|
||||
{
|
||||
|
@ -417,6 +421,8 @@ bool CCommandProcessorFragment_OpenGL::InitOpenGL(const SCommand_Init *pCommand)
|
|||
pCommand->m_pCapabilities->m_MipMapping = true;
|
||||
pCommand->m_pCapabilities->m_3DTextures = true;
|
||||
pCommand->m_pCapabilities->m_2DArrayTextures = true;
|
||||
|
||||
pCommand->m_pCapabilities->m_TrianglesAsQuads = true;
|
||||
}
|
||||
else if(MajorV == 3)
|
||||
{
|
||||
|
@ -563,7 +569,7 @@ bool CCommandProcessorFragment_OpenGL::InitOpenGL(const SCommand_Init *pCommand)
|
|||
glDepthMask(0);
|
||||
|
||||
#ifndef BACKEND_AS_OPENGL_ES
|
||||
if(g_Config.m_DbgGfx)
|
||||
if(g_Config.m_DbgGfx != DEBUG_GFX_MODE_NONE)
|
||||
{
|
||||
if(GLEW_KHR_debug || GLEW_ARB_debug_output)
|
||||
{
|
||||
|
@ -624,26 +630,20 @@ bool CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand)
|
|||
return true;
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand)
|
||||
void CCommandProcessorFragment_OpenGL::TextureUpdate(int Slot, int X, int Y, int Width, int Height, int GLFormat, void *pTexData)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex);
|
||||
|
||||
void *pTexData = pCommand->m_pData;
|
||||
int Width = pCommand->m_Width;
|
||||
int Height = pCommand->m_Height;
|
||||
int X = pCommand->m_X;
|
||||
int Y = pCommand->m_Y;
|
||||
glBindTexture(GL_TEXTURE_2D, m_Textures[Slot].m_Tex);
|
||||
|
||||
if(!m_HasNPOTTextures)
|
||||
{
|
||||
float ResizeW = m_Textures[pCommand->m_Slot].m_ResizeWidth;
|
||||
float ResizeH = m_Textures[pCommand->m_Slot].m_ResizeHeight;
|
||||
float ResizeW = m_Textures[Slot].m_ResizeWidth;
|
||||
float ResizeH = m_Textures[Slot].m_ResizeHeight;
|
||||
if(ResizeW > 0 && ResizeH > 0)
|
||||
{
|
||||
int ResizedW = (int)(Width * ResizeW);
|
||||
int ResizedH = (int)(Height * ResizeH);
|
||||
|
||||
void *pTmpData = Resize(Width, Height, ResizedW, ResizedH, pCommand->m_Format, static_cast<const unsigned char *>(pTexData));
|
||||
void *pTmpData = Resize(static_cast<const unsigned char *>(pTexData), Width, Height, ResizedW, ResizedH, GLFormatToImageColorChannelCount(GLFormat));
|
||||
free(pTexData);
|
||||
pTexData = pTmpData;
|
||||
|
||||
|
@ -652,11 +652,11 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::
|
|||
}
|
||||
}
|
||||
|
||||
if(m_Textures[pCommand->m_Slot].m_RescaleCount > 0)
|
||||
if(m_Textures[Slot].m_RescaleCount > 0)
|
||||
{
|
||||
int OldWidth = Width;
|
||||
int OldHeight = Height;
|
||||
for(int i = 0; i < m_Textures[pCommand->m_Slot].m_RescaleCount; ++i)
|
||||
for(int i = 0; i < m_Textures[Slot].m_RescaleCount; ++i)
|
||||
{
|
||||
Width >>= 1;
|
||||
Height >>= 1;
|
||||
|
@ -665,16 +665,20 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::
|
|||
Y /= 2;
|
||||
}
|
||||
|
||||
void *pTmpData = Resize(OldWidth, OldHeight, Width, Height, pCommand->m_Format, static_cast<const unsigned char *>(pTexData));
|
||||
void *pTmpData = Resize(static_cast<const unsigned char *>(pTexData), OldWidth, OldHeight, Width, Height, GLFormatToImageColorChannelCount(GLFormat));
|
||||
free(pTexData);
|
||||
pTexData = pTmpData;
|
||||
}
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, X, Y, Width, Height,
|
||||
TexFormatToOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pTexData);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, X, Y, Width, Height, GLFormat, GL_UNSIGNED_BYTE, pTexData);
|
||||
free(pTexData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand)
|
||||
{
|
||||
TextureUpdate(pCommand->m_Slot, pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height, TexFormatToOpenGLFormat(pCommand->m_Format), pCommand->m_pData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL::DestroyTexture(int Slot)
|
||||
{
|
||||
m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) - m_Textures[Slot].m_MemSize, std::memory_order_relaxed);
|
||||
|
@ -713,12 +717,9 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer:
|
|||
DestroyTexture(pCommand->m_Slot);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand)
|
||||
void CCommandProcessorFragment_OpenGL::TextureCreate(int Slot, int Width, int Height, int PixelSize, int GLFormat, int GLStoreFormat, int Flags, void *pTexData)
|
||||
{
|
||||
#ifndef BACKEND_GL_MODERN_API
|
||||
int Width = pCommand->m_Width;
|
||||
int Height = pCommand->m_Height;
|
||||
void *pTexData = pCommand->m_pData;
|
||||
|
||||
if(m_MaxTexSize == -1)
|
||||
{
|
||||
|
@ -727,11 +728,11 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize);
|
||||
}
|
||||
|
||||
if(pCommand->m_Slot >= (int)m_Textures.size())
|
||||
if(Slot >= (int)m_Textures.size())
|
||||
m_Textures.resize(m_Textures.size() * 2);
|
||||
|
||||
m_Textures[pCommand->m_Slot].m_ResizeWidth = -1.f;
|
||||
m_Textures[pCommand->m_Slot].m_ResizeHeight = -1.f;
|
||||
m_Textures[Slot].m_ResizeWidth = -1.f;
|
||||
m_Textures[Slot].m_ResizeHeight = -1.f;
|
||||
|
||||
if(!m_HasNPOTTextures)
|
||||
{
|
||||
|
@ -739,12 +740,12 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
int PowerOfTwoHeight = HighestBit(Height);
|
||||
if(Width != PowerOfTwoWidth || Height != PowerOfTwoHeight)
|
||||
{
|
||||
void *pTmpData = Resize(Width, Height, PowerOfTwoWidth, PowerOfTwoHeight, pCommand->m_Format, static_cast<const unsigned char *>(pTexData));
|
||||
void *pTmpData = Resize(static_cast<const unsigned char *>(pTexData), Width, Height, PowerOfTwoWidth, PowerOfTwoHeight, GLFormatToImageColorChannelCount(GLFormat));
|
||||
free(pTexData);
|
||||
pTexData = pTmpData;
|
||||
|
||||
m_Textures[pCommand->m_Slot].m_ResizeWidth = (float)PowerOfTwoWidth / (float)Width;
|
||||
m_Textures[pCommand->m_Slot].m_ResizeHeight = (float)PowerOfTwoHeight / (float)Height;
|
||||
m_Textures[Slot].m_ResizeWidth = (float)PowerOfTwoWidth / (float)Width;
|
||||
m_Textures[Slot].m_ResizeHeight = (float)PowerOfTwoHeight / (float)Height;
|
||||
|
||||
Width = PowerOfTwoWidth;
|
||||
Height = PowerOfTwoHeight;
|
||||
|
@ -752,7 +753,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
}
|
||||
|
||||
int RescaleCount = 0;
|
||||
if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB || pCommand->m_Format == CCommandBuffer::TEXFORMAT_ALPHA)
|
||||
if(GLFormat == GL_RGBA)
|
||||
{
|
||||
int OldWidth = Width;
|
||||
int OldHeight = Height;
|
||||
|
@ -771,27 +772,27 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
|
||||
if(NeedsResize)
|
||||
{
|
||||
void *pTmpData = Resize(OldWidth, OldHeight, Width, Height, pCommand->m_Format, static_cast<const unsigned char *>(pTexData));
|
||||
void *pTmpData = Resize(static_cast<const unsigned char *>(pTexData), OldWidth, OldHeight, Width, Height, GLFormatToImageColorChannelCount(GLFormat));
|
||||
free(pTexData);
|
||||
pTexData = pTmpData;
|
||||
}
|
||||
}
|
||||
m_Textures[pCommand->m_Slot].m_Width = Width;
|
||||
m_Textures[pCommand->m_Slot].m_Height = Height;
|
||||
m_Textures[pCommand->m_Slot].m_RescaleCount = RescaleCount;
|
||||
m_Textures[Slot].m_Width = Width;
|
||||
m_Textures[Slot].m_Height = Height;
|
||||
m_Textures[Slot].m_RescaleCount = RescaleCount;
|
||||
|
||||
int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format);
|
||||
int StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat);
|
||||
int Oglformat = GLFormat;
|
||||
int StoreOglformat = GLStoreFormat;
|
||||
|
||||
if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
if((Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
{
|
||||
glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex);
|
||||
glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex);
|
||||
glGenTextures(1, &m_Textures[Slot].m_Tex);
|
||||
glBindTexture(GL_TEXTURE_2D, m_Textures[Slot].m_Tex);
|
||||
}
|
||||
|
||||
if(pCommand->m_Flags & CCommandBuffer::TEXFLAG_NOMIPMAPS || !m_HasMipMaps)
|
||||
if(Flags & CCommandBuffer::TEXFLAG_NOMIPMAPS || !m_HasMipMaps)
|
||||
{
|
||||
if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
if((Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
@ -800,7 +801,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
}
|
||||
else
|
||||
{
|
||||
if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
if((Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
|
@ -816,11 +817,11 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
|
||||
int Flag2DArrayTexture = (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE | CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER);
|
||||
int Flag3DTexture = (CCommandBuffer::TEXFLAG_TO_3D_TEXTURE | CCommandBuffer::TEXFLAG_TO_3D_TEXTURE_SINGLE_LAYER);
|
||||
if((pCommand->m_Flags & (Flag2DArrayTexture | Flag3DTexture)) != 0)
|
||||
if((Flags & (Flag2DArrayTexture | Flag3DTexture)) != 0)
|
||||
{
|
||||
bool Is3DTexture = (pCommand->m_Flags & Flag3DTexture) != 0;
|
||||
bool Is3DTexture = (Flags & Flag3DTexture) != 0;
|
||||
|
||||
glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex2DArray);
|
||||
glGenTextures(1, &m_Textures[Slot].m_Tex2DArray);
|
||||
|
||||
GLenum Target = GL_TEXTURE_3D;
|
||||
|
||||
|
@ -833,12 +834,12 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
Target = m_2DArrayTarget;
|
||||
}
|
||||
|
||||
glBindTexture(Target, m_Textures[pCommand->m_Slot].m_Tex2DArray);
|
||||
glBindTexture(Target, m_Textures[Slot].m_Tex2DArray);
|
||||
|
||||
if(IsNewApi())
|
||||
{
|
||||
glGenSamplers(1, &m_Textures[pCommand->m_Slot].m_Sampler2DArray);
|
||||
glBindSampler(0, m_Textures[pCommand->m_Slot].m_Sampler2DArray);
|
||||
glGenSamplers(1, &m_Textures[Slot].m_Sampler2DArray);
|
||||
glBindSampler(0, m_Textures[Slot].m_Sampler2DArray);
|
||||
}
|
||||
|
||||
glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
@ -846,14 +847,14 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
{
|
||||
glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
if(IsNewApi())
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(Target, GL_GENERATE_MIPMAP, GL_TRUE);
|
||||
if(IsNewApi())
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
|
||||
glTexParameteri(Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
|
@ -867,23 +868,23 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
|
||||
if(IsNewApi())
|
||||
{
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
|
||||
|
||||
#ifndef BACKEND_AS_OPENGL_ES
|
||||
if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
|
||||
glSamplerParameterf(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
|
||||
glSamplerParameterf(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
|
||||
#endif
|
||||
|
||||
glBindSampler(0, 0);
|
||||
}
|
||||
|
||||
int ImageColorChannels = TexFormatToImageColorChannelCount(pCommand->m_Format);
|
||||
int ImageColorChannels = GLFormatToImageColorChannelCount(GLFormat);
|
||||
|
||||
uint8_t *p3DImageData = NULL;
|
||||
|
||||
bool IsSingleLayer = (pCommand->m_Flags & (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER | CCommandBuffer::TEXFLAG_TO_3D_TEXTURE_SINGLE_LAYER)) != 0;
|
||||
bool IsSingleLayer = (Flags & (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER | CCommandBuffer::TEXFLAG_TO_3D_TEXTURE_SINGLE_LAYER)) != 0;
|
||||
|
||||
if(!IsSingleLayer)
|
||||
p3DImageData = (uint8_t *)malloc((size_t)ImageColorChannels * Width * Height);
|
||||
|
@ -899,7 +900,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
dbg_msg("gfx", "3D/2D array texture was resized");
|
||||
int NewWidth = maximum<int>(HighestBit(ConvertWidth), 16);
|
||||
int NewHeight = maximum<int>(HighestBit(ConvertHeight), 16);
|
||||
uint8_t *pNewTexData = (uint8_t *)Resize(ConvertWidth, ConvertHeight, NewWidth, NewHeight, pCommand->m_Format, (const uint8_t *)pTexData);
|
||||
uint8_t *pNewTexData = (uint8_t *)Resize((const uint8_t *)pTexData, ConvertWidth, ConvertHeight, NewWidth, NewHeight, GLFormatToImageColorChannelCount(GLFormat));
|
||||
|
||||
ConvertWidth = NewWidth;
|
||||
ConvertHeight = NewHeight;
|
||||
|
@ -927,22 +928,46 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
|
|||
}
|
||||
|
||||
// This is the initial value for the wrap modes
|
||||
m_Textures[pCommand->m_Slot].m_LastWrapMode = CCommandBuffer::WRAP_REPEAT;
|
||||
m_Textures[Slot].m_LastWrapMode = CCommandBuffer::WRAP_REPEAT;
|
||||
|
||||
// calculate memory usage
|
||||
m_Textures[pCommand->m_Slot].m_MemSize = Width * Height * pCommand->m_PixelSize;
|
||||
m_Textures[Slot].m_MemSize = Width * Height * PixelSize;
|
||||
while(Width > 2 && Height > 2)
|
||||
{
|
||||
Width >>= 1;
|
||||
Height >>= 1;
|
||||
m_Textures[pCommand->m_Slot].m_MemSize += Width * Height * pCommand->m_PixelSize;
|
||||
m_Textures[Slot].m_MemSize += Width * Height * PixelSize;
|
||||
}
|
||||
m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) + m_Textures[pCommand->m_Slot].m_MemSize, std::memory_order_relaxed);
|
||||
m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) + m_Textures[Slot].m_MemSize, std::memory_order_relaxed);
|
||||
|
||||
free(pTexData);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand)
|
||||
{
|
||||
TextureCreate(pCommand->m_Slot, pCommand->m_Width, pCommand->m_Height, pCommand->m_PixelSize, TexFormatToOpenGLFormat(pCommand->m_Format), TexFormatToOpenGLFormat(pCommand->m_StoreFormat), pCommand->m_Flags, pCommand->m_pData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL::Cmd_TextTexture_Update(const CCommandBuffer::SCommand_TextTexture_Update *pCommand)
|
||||
{
|
||||
TextureUpdate(pCommand->m_Slot, pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height, GL_ALPHA, pCommand->m_pData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL::Cmd_TextTextures_Destroy(const CCommandBuffer::SCommand_TextTextures_Destroy *pCommand)
|
||||
{
|
||||
DestroyTexture(pCommand->m_Slot);
|
||||
DestroyTexture(pCommand->m_SlotOutline);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL::Cmd_TextTextures_Create(const CCommandBuffer::SCommand_TextTextures_Create *pCommand)
|
||||
{
|
||||
void *pTextData = pCommand->m_pTextData;
|
||||
void *pTextOutlineData = pCommand->m_pTextOutlineData;
|
||||
TextureCreate(pCommand->m_Slot, pCommand->m_Width, pCommand->m_Height, 1, GL_ALPHA, GL_ALPHA, CCommandBuffer::TEXFLAG_NOMIPMAPS, pTextData);
|
||||
TextureCreate(pCommand->m_SlotOutline, pCommand->m_Width, pCommand->m_Height, 1, GL_ALPHA, GL_ALPHA, CCommandBuffer::TEXFLAG_NOMIPMAPS, pTextOutlineData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand)
|
||||
{
|
||||
glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f);
|
||||
|
@ -980,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);
|
||||
|
@ -1045,6 +1072,15 @@ bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand
|
|||
case CCommandBuffer::CMD_TEXTURE_UPDATE:
|
||||
Cmd_Texture_Update(static_cast<const CCommandBuffer::SCommand_Texture_Update *>(pBaseCommand));
|
||||
break;
|
||||
case CCommandBuffer::CMD_TEXT_TEXTURES_CREATE:
|
||||
Cmd_TextTextures_Create(static_cast<const CCommandBuffer::SCommand_TextTextures_Create *>(pBaseCommand));
|
||||
break;
|
||||
case CCommandBuffer::CMD_TEXT_TEXTURES_DESTROY:
|
||||
Cmd_TextTextures_Destroy(static_cast<const CCommandBuffer::SCommand_TextTextures_Destroy *>(pBaseCommand));
|
||||
break;
|
||||
case CCommandBuffer::CMD_TEXT_TEXTURE_UPDATE:
|
||||
Cmd_TextTexture_Update(static_cast<const CCommandBuffer::SCommand_TextTexture_Update *>(pBaseCommand));
|
||||
break;
|
||||
case CCommandBuffer::CMD_CLEAR:
|
||||
Cmd_Clear(static_cast<const CCommandBuffer::SCommand_Clear *>(pBaseCommand));
|
||||
break;
|
||||
|
@ -1054,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));
|
||||
|
@ -1080,7 +1116,6 @@ bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand
|
|||
case CCommandBuffer::CMD_RENDER_BORDER_TILE_LINE: Cmd_RenderBorderTileLine(static_cast<const CCommandBuffer::SCommand_RenderBorderTileLine *>(pBaseCommand)); break;
|
||||
case CCommandBuffer::CMD_RENDER_QUAD_LAYER: Cmd_RenderQuadLayer(static_cast<const CCommandBuffer::SCommand_RenderQuadLayer *>(pBaseCommand)); break;
|
||||
case CCommandBuffer::CMD_RENDER_TEXT: Cmd_RenderText(static_cast<const CCommandBuffer::SCommand_RenderText *>(pBaseCommand)); break;
|
||||
case CCommandBuffer::CMD_RENDER_TEXT_STREAM: Cmd_RenderTextStream(static_cast<const CCommandBuffer::SCommand_RenderTextStream *>(pBaseCommand)); break;
|
||||
case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER: Cmd_RenderQuadContainer(static_cast<const CCommandBuffer::SCommand_RenderQuadContainer *>(pBaseCommand)); break;
|
||||
case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_EX: Cmd_RenderQuadContainerEx(static_cast<const CCommandBuffer::SCommand_RenderQuadContainerEx *>(pBaseCommand)); break;
|
||||
case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE: Cmd_RenderQuadContainerAsSpriteMultiple(static_cast<const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *>(pBaseCommand)); break;
|
||||
|
@ -1103,7 +1138,7 @@ bool CCommandProcessorFragment_OpenGL2::IsAndUpdateTextureSlotBound(int IDX, int
|
|||
return true;
|
||||
else
|
||||
{
|
||||
//the texture slot uses this index now
|
||||
// the texture slot uses this index now
|
||||
m_TextureSlotBoundToUnit[IDX].m_TextureSlot = Slot;
|
||||
m_TextureSlotBoundToUnit[IDX].m_Is2DArray = Is2DArray;
|
||||
return false;
|
||||
|
@ -1125,14 +1160,14 @@ void CCommandProcessorFragment_OpenGL2::SetState(const CCommandBuffer::SState &S
|
|||
{
|
||||
case CCommandBuffer::BLEND_NONE:
|
||||
// We don't really need this anymore
|
||||
//glDisable(GL_BLEND);
|
||||
// glDisable(GL_BLEND);
|
||||
break;
|
||||
case CCommandBuffer::BLEND_ALPHA:
|
||||
//glEnable(GL_BLEND);
|
||||
// glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
break;
|
||||
case CCommandBuffer::BLEND_ADDITIVE:
|
||||
//glEnable(GL_BLEND);
|
||||
// glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
break;
|
||||
default:
|
||||
|
@ -1267,10 +1302,14 @@ void CCommandProcessorFragment_OpenGL2::SetState(const CCommandBuffer::SState &S
|
|||
// orthographic projection matrix
|
||||
// the z coordinate is the same for every vertex, so just ignore the z coordinate and set it in the shaders
|
||||
float m[2 * 4] = {
|
||||
2.f / (State.m_ScreenBR.x - State.m_ScreenTL.x), 0, 0, -((State.m_ScreenBR.x + State.m_ScreenTL.x) / (State.m_ScreenBR.x - State.m_ScreenTL.x)),
|
||||
0, (2.f / (State.m_ScreenTL.y - State.m_ScreenBR.y)), 0, -((State.m_ScreenTL.y + State.m_ScreenBR.y) / (State.m_ScreenTL.y - State.m_ScreenBR.y)),
|
||||
//0, 0, -(2.f/(9.f)), -((11.f)/(9.f)),
|
||||
//0, 0, 0, 1.0f
|
||||
2.f / (State.m_ScreenBR.x - State.m_ScreenTL.x),
|
||||
0,
|
||||
0,
|
||||
-((State.m_ScreenBR.x + State.m_ScreenTL.x) / (State.m_ScreenBR.x - State.m_ScreenTL.x)),
|
||||
0,
|
||||
(2.f / (State.m_ScreenTL.y - State.m_ScreenBR.y)),
|
||||
0,
|
||||
-((State.m_ScreenTL.y + State.m_ScreenBR.y) / (State.m_ScreenTL.y - State.m_ScreenBR.y)),
|
||||
};
|
||||
|
||||
// transpose bcs of column-major order of opengl
|
||||
|
@ -1580,7 +1619,7 @@ bool CCommandProcessorFragment_OpenGL2::IsTileMapAnalysisSucceeded()
|
|||
}
|
||||
}
|
||||
|
||||
//everything build up, now do the analyze steps
|
||||
// everything build up, now do the analyze steps
|
||||
bool NoError = DoAnalyzeStep(0, CheckCount, VertexCount, pFakeTexture, SingleImageSize);
|
||||
if(NoError && m_HasShaders)
|
||||
NoError &= DoAnalyzeStep(1, CheckCount, VertexCount, pFakeTexture, SingleImageSize);
|
||||
|
@ -1596,7 +1635,7 @@ bool CCommandProcessorFragment_OpenGL2::Cmd_Init(const SCommand_Init *pCommand)
|
|||
if(!CCommandProcessorFragment_OpenGL::Cmd_Init(pCommand))
|
||||
return false;
|
||||
|
||||
m_OpenGLTextureLodBIAS = g_Config.m_GfxOpenGLTextureLODBIAS;
|
||||
m_OpenGLTextureLodBIAS = g_Config.m_GfxGLTextureLODBIAS;
|
||||
|
||||
m_HasShaders = pCommand->m_pCapabilities->m_ShaderSupport;
|
||||
|
||||
|
@ -1635,7 +1674,7 @@ bool CCommandProcessorFragment_OpenGL2::Cmd_Init(const SCommand_Init *pCommand)
|
|||
m_pPrimitive3DProgram = new CGLSLPrimitiveProgram;
|
||||
m_pPrimitive3DProgramTextured = new CGLSLPrimitiveProgram;
|
||||
|
||||
CGLSLCompiler ShaderCompiler(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch, m_IsOpenGLES, m_OpenGLTextureLodBIAS / 1000.0f);
|
||||
CGLSLCompiler ShaderCompiler(g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch, m_IsOpenGLES, m_OpenGLTextureLodBIAS / 1000.0f);
|
||||
ShaderCompiler.SetHasTextureArray(pCommand->m_pCapabilities->m_2DArrayTextures);
|
||||
|
||||
if(pCommand->m_pCapabilities->m_2DArrayTextures)
|
||||
|
@ -1819,7 +1858,7 @@ void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferObject(const CCommandBuf
|
|||
{
|
||||
void *pUploadData = pCommand->m_pUploadData;
|
||||
int Index = pCommand->m_BufferIndex;
|
||||
//create necessary space
|
||||
// create necessary space
|
||||
if((size_t)Index >= m_BufferObjectIndices.size())
|
||||
{
|
||||
for(int i = m_BufferObjectIndices.size(); i < Index + 1; ++i)
|
||||
|
@ -1927,13 +1966,14 @@ void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferObject(const CCommandBuf
|
|||
void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand)
|
||||
{
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//create necessary space
|
||||
// create necessary space
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
{
|
||||
for(int i = m_BufferContainers.size(); i < Index + 1; ++i)
|
||||
{
|
||||
SBufferContainer Container;
|
||||
Container.m_ContainerInfo.m_Stride = 0;
|
||||
Container.m_ContainerInfo.m_VertBufferBindingIndex = -1;
|
||||
m_BufferContainers.push_back(Container);
|
||||
}
|
||||
}
|
||||
|
@ -1947,6 +1987,7 @@ void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferContainer(const CCommand
|
|||
}
|
||||
|
||||
BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride;
|
||||
BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex = pCommand->m_VertBufferBindingIndex;
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand)
|
||||
|
@ -1962,6 +2003,7 @@ void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferContainer(const CCommand
|
|||
}
|
||||
|
||||
BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride;
|
||||
BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex = pCommand->m_VertBufferBindingIndex;
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand)
|
||||
|
@ -1970,28 +2012,16 @@ void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferContainer(const CCommand
|
|||
|
||||
if(pCommand->m_DestroyAllBO)
|
||||
{
|
||||
for(size_t i = 0; i < BufferContainer.m_ContainerInfo.m_Attributes.size(); ++i)
|
||||
int VertBufferID = BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex;
|
||||
if(VertBufferID != -1)
|
||||
{
|
||||
int VertBufferID = BufferContainer.m_ContainerInfo.m_Attributes[i].m_VertBufferBindingIndex;
|
||||
if(VertBufferID != -1)
|
||||
if(m_HasShaders)
|
||||
{
|
||||
for(auto &Attribute : BufferContainer.m_ContainerInfo.m_Attributes)
|
||||
{
|
||||
// set all equal ids to zero to not double delete
|
||||
if(VertBufferID == Attribute.m_VertBufferBindingIndex)
|
||||
{
|
||||
Attribute.m_VertBufferBindingIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_HasShaders)
|
||||
{
|
||||
glDeleteBuffers(1, &m_BufferObjectIndices[VertBufferID].m_BufferObjectID);
|
||||
}
|
||||
|
||||
free(m_BufferObjectIndices[VertBufferID].m_pData);
|
||||
m_BufferObjectIndices[VertBufferID].m_pData = NULL;
|
||||
glDeleteBuffers(1, &m_BufferObjectIndices[VertBufferID].m_BufferObjectID);
|
||||
}
|
||||
|
||||
free(m_BufferObjectIndices[VertBufferID].m_pData);
|
||||
m_BufferObjectIndices[VertBufferID].m_pData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2025,7 +2055,7 @@ void CCommandProcessorFragment_OpenGL2::RenderBorderTileEmulation(SBufferContain
|
|||
|
||||
bool IsTextured = BufferContainer.m_ContainerInfo.m_Attributes.size() == 2;
|
||||
|
||||
SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_Attributes[0].m_VertBufferBindingIndex];
|
||||
SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex];
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
@ -2110,7 +2140,7 @@ void CCommandProcessorFragment_OpenGL2::RenderBorderTileLineEmulation(SBufferCon
|
|||
|
||||
bool IsTextured = BufferContainer.m_ContainerInfo.m_Attributes.size() == 2;
|
||||
|
||||
SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_Attributes[0].m_VertBufferBindingIndex];
|
||||
SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex];
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
@ -2173,7 +2203,7 @@ void CCommandProcessorFragment_OpenGL2::RenderBorderTileLineEmulation(SBufferCon
|
|||
void CCommandProcessorFragment_OpenGL2::Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand)
|
||||
{
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
@ -2185,7 +2215,7 @@ void CCommandProcessorFragment_OpenGL2::Cmd_RenderBorderTile(const CCommandBuffe
|
|||
void CCommandProcessorFragment_OpenGL2::Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand)
|
||||
{
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
@ -2197,7 +2227,7 @@ void CCommandProcessorFragment_OpenGL2::Cmd_RenderBorderTileLine(const CCommandB
|
|||
void CCommandProcessorFragment_OpenGL2::Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand)
|
||||
{
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
@ -2205,7 +2235,7 @@ void CCommandProcessorFragment_OpenGL2::Cmd_RenderTileLayer(const CCommandBuffer
|
|||
|
||||
if(pCommand->m_IndicesDrawNum == 0)
|
||||
{
|
||||
return; //nothing to draw
|
||||
return; // nothing to draw
|
||||
}
|
||||
|
||||
if(m_HasShaders)
|
||||
|
@ -2230,7 +2260,7 @@ void CCommandProcessorFragment_OpenGL2::Cmd_RenderTileLayer(const CCommandBuffer
|
|||
|
||||
bool IsTextured = BufferContainer.m_ContainerInfo.m_Attributes.size() == 2;
|
||||
|
||||
SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_Attributes[0].m_VertBufferBindingIndex];
|
||||
SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex];
|
||||
if(m_HasShaders)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectID);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <base/system.h>
|
||||
|
||||
#include <engine/client/backend/backend_base.h>
|
||||
#include <engine/client/backend_sdl.h>
|
||||
|
||||
class CGLSLProgram;
|
||||
|
@ -28,7 +29,7 @@ class CGLSLSpriteMultipleProgram;
|
|||
#endif
|
||||
|
||||
// takes care of opengl related rendering
|
||||
class CCommandProcessorFragment_OpenGL : public CCommandProcessorFragment_OpenGLBase
|
||||
class CCommandProcessorFragment_OpenGL : public CCommandProcessorFragment_GLBase
|
||||
{
|
||||
protected:
|
||||
struct CTexture
|
||||
|
@ -39,9 +40,9 @@ protected:
|
|||
}
|
||||
|
||||
TWGLuint m_Tex;
|
||||
TWGLuint m_Tex2DArray; //or 3D texture as fallback
|
||||
TWGLuint m_Tex2DArray; // or 3D texture as fallback
|
||||
TWGLuint m_Sampler;
|
||||
TWGLuint m_Sampler2DArray; //or 3D texture as fallback
|
||||
TWGLuint m_Sampler2DArray; // or 3D texture as fallback
|
||||
int m_LastWrapMode;
|
||||
|
||||
int m_MemSize;
|
||||
|
@ -53,7 +54,10 @@ protected:
|
|||
float m_ResizeHeight;
|
||||
};
|
||||
std::vector<CTexture> m_Textures;
|
||||
std::atomic<int> *m_pTextureMemoryUsage;
|
||||
std::atomic<uint64_t> *m_pTextureMemoryUsage;
|
||||
|
||||
uint32_t m_CanvasWidth = 0;
|
||||
uint32_t m_CanvasHeight = 0;
|
||||
|
||||
TWGLint m_MaxTexSize;
|
||||
|
||||
|
@ -65,7 +69,7 @@ protected:
|
|||
bool m_HasNPOTTextures;
|
||||
|
||||
bool m_HasShaders;
|
||||
int m_LastBlendMode; //avoid all possible opengl state changes
|
||||
int m_LastBlendMode; // avoid all possible opengl state changes
|
||||
bool m_LastClipEnable;
|
||||
|
||||
int m_OpenGLTextureLodBIAS;
|
||||
|
@ -73,7 +77,6 @@ protected:
|
|||
bool m_IsOpenGLES;
|
||||
|
||||
bool IsTexturedState(const CCommandBuffer::SState &State);
|
||||
static bool Texture2DTo3D(void *pImageBuffer, int ImageWidth, int ImageHeight, int ImageColorChannelCount, int SplitCountWidth, int SplitCountHeight, void *pTarget3DImageData, int &Target3DImageWidth, int &Target3DImageHeight);
|
||||
|
||||
bool InitOpenGL(const SCommand_Init *pCommand);
|
||||
|
||||
|
@ -81,19 +84,26 @@ protected:
|
|||
virtual bool IsNewApi() { return false; }
|
||||
void DestroyTexture(int Slot);
|
||||
|
||||
virtual bool GetPresentedImageData(uint32_t &Width, uint32_t &Height, uint32_t &Format, std::vector<uint8_t> &DstData);
|
||||
|
||||
static int TexFormatToOpenGLFormat(int TexFormat);
|
||||
static int TexFormatToImageColorChannelCount(int TexFormat);
|
||||
static void *Resize(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData);
|
||||
static size_t GLFormatToImageColorChannelCount(int GLFormat);
|
||||
|
||||
void TextureUpdate(int Slot, int X, int Y, int Width, int Height, int GLFormat, void *pTexData);
|
||||
void TextureCreate(int Slot, int Width, int Height, int PixelSize, int GLFormat, int GLStoreFormat, int Flags, void *pTexData);
|
||||
|
||||
virtual bool Cmd_Init(const SCommand_Init *pCommand);
|
||||
virtual void Cmd_Shutdown(const SCommand_Shutdown *pCommand) {}
|
||||
virtual void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand);
|
||||
virtual void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand);
|
||||
virtual void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand);
|
||||
virtual void Cmd_TextTexture_Update(const CCommandBuffer::SCommand_TextTexture_Update *pCommand);
|
||||
virtual void Cmd_TextTextures_Destroy(const CCommandBuffer::SCommand_TextTextures_Destroy *pCommand);
|
||||
virtual void Cmd_TextTextures_Create(const CCommandBuffer::SCommand_TextTextures_Create *pCommand);
|
||||
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);
|
||||
|
@ -114,7 +124,6 @@ protected:
|
|||
virtual void Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand) { dbg_assert(false, "Call of unsupported Cmd_RenderBorderTileLine"); }
|
||||
virtual void Cmd_RenderQuadLayer(const CCommandBuffer::SCommand_RenderQuadLayer *pCommand) { dbg_assert(false, "Call of unsupported Cmd_RenderQuadLayer"); }
|
||||
virtual void Cmd_RenderText(const CCommandBuffer::SCommand_RenderText *pCommand) { dbg_assert(false, "Call of unsupported Cmd_RenderText"); }
|
||||
virtual void Cmd_RenderTextStream(const CCommandBuffer::SCommand_RenderTextStream *pCommand) { dbg_assert(false, "Call of unsupported Cmd_RenderTextStream"); }
|
||||
virtual void Cmd_RenderQuadContainer(const CCommandBuffer::SCommand_RenderQuadContainer *pCommand) { dbg_assert(false, "Call of unsupported Cmd_RenderQuadContainer"); }
|
||||
virtual void Cmd_RenderQuadContainerEx(const CCommandBuffer::SCommand_RenderQuadContainerEx *pCommand) { dbg_assert(false, "Call of unsupported Cmd_RenderQuadContainerEx"); }
|
||||
virtual void Cmd_RenderQuadContainerAsSpriteMultiple(const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *pCommand) { dbg_assert(false, "Call of unsupported Cmd_RenderQuadContainerAsSpriteMultiple"); }
|
||||
|
@ -130,7 +139,6 @@ class CCommandProcessorFragment_OpenGL2 : public CCommandProcessorFragment_OpenG
|
|||
{
|
||||
struct SBufferContainer
|
||||
{
|
||||
SBufferContainer() {}
|
||||
SBufferContainerInfo m_ContainerInfo;
|
||||
};
|
||||
std::vector<SBufferContainer> m_BufferContainers;
|
||||
|
@ -202,7 +210,7 @@ protected:
|
|||
int m_TextureSlot;
|
||||
bool m_Is2DArray;
|
||||
};
|
||||
std::vector<STextureBound> m_TextureSlotBoundToUnit; //the texture index generated by loadtextureraw is stored in an index calculated by max texture units
|
||||
std::vector<STextureBound> m_TextureSlotBoundToUnit; // the texture index generated by loadtextureraw is stored in an index calculated by max texture units
|
||||
|
||||
bool IsAndUpdateTextureSlotBound(int IDX, int Slot, bool Is2DArray = false);
|
||||
|
||||
|
|
|
@ -20,10 +20,6 @@
|
|||
// ------------ CCommandProcessorFragment_OpenGL3_3
|
||||
int CCommandProcessorFragment_OpenGL3_3::TexFormatToNewOpenGLFormat(int TexFormat)
|
||||
{
|
||||
if(TexFormat == CCommandBuffer::TEXFORMAT_RGB)
|
||||
return GL_RGB;
|
||||
if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA)
|
||||
return GL_RED;
|
||||
if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA)
|
||||
return GL_RGBA;
|
||||
return GL_RGBA;
|
||||
|
@ -74,7 +70,7 @@ bool CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand
|
|||
if(!InitOpenGL(pCommand))
|
||||
return false;
|
||||
|
||||
m_OpenGLTextureLodBIAS = g_Config.m_GfxOpenGLTextureLODBIAS;
|
||||
m_OpenGLTextureLodBIAS = g_Config.m_GfxGLTextureLODBIAS;
|
||||
|
||||
m_UseMultipleTextureUnits = g_Config.m_GfxEnableTextureUnitOptimization;
|
||||
if(!m_UseMultipleTextureUnits)
|
||||
|
@ -114,7 +110,7 @@ bool CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand
|
|||
m_pSpriteProgramMultiple = new CGLSLSpriteMultipleProgram;
|
||||
m_LastProgramID = 0;
|
||||
|
||||
CGLSLCompiler ShaderCompiler(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch, m_IsOpenGLES, m_OpenGLTextureLodBIAS / 1000.0f);
|
||||
CGLSLCompiler ShaderCompiler(g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor, g_Config.m_GfxGLPatch, m_IsOpenGLES, m_OpenGLTextureLodBIAS / 1000.0f);
|
||||
|
||||
GLint CapVal;
|
||||
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &CapVal);
|
||||
|
@ -448,10 +444,10 @@ bool CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand
|
|||
if(m_UsePreinitializedVertexBuffer)
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(CCommandBuffer::SVertexTex3DStream) * CCommandBuffer::MAX_VERTICES, NULL, GL_STREAM_DRAW);
|
||||
|
||||
//query the image max size only once
|
||||
// query the image max size only once
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize);
|
||||
|
||||
//query maximum of allowed textures
|
||||
// query maximum of allowed textures
|
||||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &m_MaxTextureUnits);
|
||||
m_TextureSlotBoundToUnit.resize(m_MaxTextureUnits);
|
||||
for(int i = 0; i < m_MaxTextureUnits; ++i)
|
||||
|
@ -513,7 +509,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Shutdown(const SCommand_Shutdown *
|
|||
m_pPrimitiveExProgramTexturedRotationless->DeleteProgram();
|
||||
m_pSpriteProgramMultiple->DeleteProgram();
|
||||
|
||||
//clean up everything
|
||||
// clean up everything
|
||||
delete m_pPrimitiveProgram;
|
||||
delete m_pPrimitiveProgramTextured;
|
||||
delete m_pBorderTileProgram;
|
||||
|
@ -553,27 +549,22 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Shutdown(const SCommand_Shutdown *
|
|||
m_BufferContainers.clear();
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand)
|
||||
void CCommandProcessorFragment_OpenGL3_3::TextureUpdate(int Slot, int X, int Y, int Width, int Height, int GLFormat, void *pTexData)
|
||||
{
|
||||
if(m_UseMultipleTextureUnits)
|
||||
{
|
||||
int Slot = pCommand->m_Slot % m_MaxTextureUnits;
|
||||
//just tell, that we using this texture now
|
||||
IsAndUpdateTextureSlotBound(Slot, pCommand->m_Slot);
|
||||
glActiveTexture(GL_TEXTURE0 + Slot);
|
||||
glBindSampler(Slot, m_Textures[pCommand->m_Slot].m_Sampler);
|
||||
int SamplerSlot = Slot % m_MaxTextureUnits;
|
||||
// just tell, that we using this texture now
|
||||
IsAndUpdateTextureSlotBound(SamplerSlot, Slot);
|
||||
glActiveTexture(GL_TEXTURE0 + SamplerSlot);
|
||||
glBindSampler(SamplerSlot, m_Textures[Slot].m_Sampler);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex);
|
||||
glBindTexture(GL_TEXTURE_2D, m_Textures[Slot].m_Tex);
|
||||
|
||||
void *pTexData = pCommand->m_pData;
|
||||
int Width = pCommand->m_Width;
|
||||
int Height = pCommand->m_Height;
|
||||
int X = pCommand->m_X;
|
||||
int Y = pCommand->m_Y;
|
||||
if(m_Textures[pCommand->m_Slot].m_RescaleCount > 0)
|
||||
if(m_Textures[Slot].m_RescaleCount > 0)
|
||||
{
|
||||
for(int i = 0; i < m_Textures[pCommand->m_Slot].m_RescaleCount; ++i)
|
||||
for(int i = 0; i < m_Textures[Slot].m_RescaleCount; ++i)
|
||||
{
|
||||
Width >>= 1;
|
||||
Height >>= 1;
|
||||
|
@ -582,16 +573,20 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Update(const CCommandBuffe
|
|||
Y /= 2;
|
||||
}
|
||||
|
||||
void *pTmpData = Resize(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast<const unsigned char *>(pCommand->m_pData));
|
||||
void *pTmpData = Resize(static_cast<const unsigned char *>(pTexData), Width, Height, Width, Height, GLFormatToImageColorChannelCount(GLFormat));
|
||||
free(pTexData);
|
||||
pTexData = pTmpData;
|
||||
}
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, X, Y, Width, Height,
|
||||
TexFormatToNewOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pTexData);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, X, Y, Width, Height, GLFormat, GL_UNSIGNED_BYTE, pTexData);
|
||||
free(pTexData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand)
|
||||
{
|
||||
TextureUpdate(pCommand->m_Slot, pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height, TexFormatToOpenGLFormat(pCommand->m_Format), pCommand->m_pData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand)
|
||||
{
|
||||
int Slot = 0;
|
||||
|
@ -608,18 +603,14 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Destroy(const CCommandBuff
|
|||
DestroyTexture(pCommand->m_Slot);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand)
|
||||
void CCommandProcessorFragment_OpenGL3_3::TextureCreate(int Slot, int Width, int Height, int PixelSize, int GLFormat, int GLStoreFormat, int Flags, void *pTexData)
|
||||
{
|
||||
int Width = pCommand->m_Width;
|
||||
int Height = pCommand->m_Height;
|
||||
void *pTexData = pCommand->m_pData;
|
||||
|
||||
if(pCommand->m_Slot >= (int)m_Textures.size())
|
||||
if(Slot >= (int)m_Textures.size())
|
||||
m_Textures.resize(m_Textures.size() * 2);
|
||||
|
||||
// resample if needed
|
||||
int RescaleCount = 0;
|
||||
if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB || pCommand->m_Format == CCommandBuffer::TEXFORMAT_ALPHA)
|
||||
if(GLFormat == GL_RGBA)
|
||||
{
|
||||
if(Width > m_MaxTexSize || Height > m_MaxTexSize)
|
||||
{
|
||||
|
@ -630,64 +621,64 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffe
|
|||
++RescaleCount;
|
||||
} while(Width > m_MaxTexSize || Height > m_MaxTexSize);
|
||||
|
||||
void *pTmpData = Resize(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast<const unsigned char *>(pCommand->m_pData));
|
||||
void *pTmpData = Resize(static_cast<const unsigned char *>(pTexData), Width, Height, Width, Height, GLFormatToImageColorChannelCount(GLFormat));
|
||||
free(pTexData);
|
||||
pTexData = pTmpData;
|
||||
}
|
||||
}
|
||||
m_Textures[pCommand->m_Slot].m_Width = Width;
|
||||
m_Textures[pCommand->m_Slot].m_Height = Height;
|
||||
m_Textures[pCommand->m_Slot].m_RescaleCount = RescaleCount;
|
||||
m_Textures[Slot].m_Width = Width;
|
||||
m_Textures[Slot].m_Height = Height;
|
||||
m_Textures[Slot].m_RescaleCount = RescaleCount;
|
||||
|
||||
int Oglformat = TexFormatToNewOpenGLFormat(pCommand->m_Format);
|
||||
int StoreOglformat = TexFormatToNewOpenGLFormat(pCommand->m_StoreFormat);
|
||||
int Oglformat = GLFormat;
|
||||
int StoreOglformat = GLStoreFormat;
|
||||
if(StoreOglformat == GL_RED)
|
||||
StoreOglformat = GL_R8;
|
||||
|
||||
int Slot = 0;
|
||||
int SamplerSlot = 0;
|
||||
if(m_UseMultipleTextureUnits)
|
||||
{
|
||||
Slot = pCommand->m_Slot % m_MaxTextureUnits;
|
||||
//just tell, that we using this texture now
|
||||
IsAndUpdateTextureSlotBound(Slot, pCommand->m_Slot);
|
||||
glActiveTexture(GL_TEXTURE0 + Slot);
|
||||
m_TextureSlotBoundToUnit[Slot].m_TextureSlot = -1;
|
||||
m_TextureSlotBoundToUnit[Slot].m_Is2DArray = false;
|
||||
SamplerSlot = Slot % m_MaxTextureUnits;
|
||||
// just tell, that we using this texture now
|
||||
IsAndUpdateTextureSlotBound(SamplerSlot, Slot);
|
||||
glActiveTexture(GL_TEXTURE0 + SamplerSlot);
|
||||
m_TextureSlotBoundToUnit[SamplerSlot].m_TextureSlot = -1;
|
||||
m_TextureSlotBoundToUnit[SamplerSlot].m_Is2DArray = false;
|
||||
}
|
||||
|
||||
if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
if((Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
{
|
||||
glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex);
|
||||
glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex);
|
||||
glGenTextures(1, &m_Textures[Slot].m_Tex);
|
||||
glBindTexture(GL_TEXTURE_2D, m_Textures[Slot].m_Tex);
|
||||
|
||||
glGenSamplers(1, &m_Textures[pCommand->m_Slot].m_Sampler);
|
||||
glBindSampler(Slot, m_Textures[pCommand->m_Slot].m_Sampler);
|
||||
glGenSamplers(1, &m_Textures[Slot].m_Sampler);
|
||||
glBindSampler(SamplerSlot, m_Textures[Slot].m_Sampler);
|
||||
}
|
||||
|
||||
if(pCommand->m_Flags & CCommandBuffer::TEXFLAG_NOMIPMAPS)
|
||||
if(Flags & CCommandBuffer::TEXFLAG_NOMIPMAPS)
|
||||
{
|
||||
if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
if((Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
if((Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0)
|
||||
{
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
|
||||
#ifndef BACKEND_AS_OPENGL_ES
|
||||
if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
|
||||
glSamplerParameterf(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
|
||||
glSamplerParameterf(m_Textures[Slot].m_Sampler, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
|
||||
#endif
|
||||
|
||||
//prevent mipmap display bugs, when zooming out far
|
||||
// prevent mipmap display bugs, when zooming out far
|
||||
if(Width >= 1024 && Height >= 1024)
|
||||
{
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5.f);
|
||||
|
@ -697,29 +688,29 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffe
|
|||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
if((pCommand->m_Flags & (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE | CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER)) != 0)
|
||||
if((Flags & (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE | CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER)) != 0)
|
||||
{
|
||||
glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex2DArray);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_Textures[pCommand->m_Slot].m_Tex2DArray);
|
||||
glGenTextures(1, &m_Textures[Slot].m_Tex2DArray);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_Textures[Slot].m_Tex2DArray);
|
||||
|
||||
glGenSamplers(1, &m_Textures[pCommand->m_Slot].m_Sampler2DArray);
|
||||
glBindSampler(Slot, m_Textures[pCommand->m_Slot].m_Sampler2DArray);
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
|
||||
glGenSamplers(1, &m_Textures[Slot].m_Sampler2DArray);
|
||||
glBindSampler(SamplerSlot, m_Textures[Slot].m_Sampler2DArray);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
|
||||
|
||||
#ifndef BACKEND_AS_OPENGL_ES
|
||||
if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES)
|
||||
glSamplerParameterf(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
|
||||
glSamplerParameterf(m_Textures[Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f));
|
||||
#endif
|
||||
|
||||
int ImageColorChannels = TexFormatToImageColorChannelCount(pCommand->m_Format);
|
||||
int ImageColorChannels = GLFormatToImageColorChannelCount(GLFormat);
|
||||
|
||||
uint8_t *p3DImageData = NULL;
|
||||
|
||||
bool IsSingleLayer = (pCommand->m_Flags & CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER) != 0;
|
||||
bool IsSingleLayer = (Flags & CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER) != 0;
|
||||
|
||||
if(!IsSingleLayer)
|
||||
p3DImageData = (uint8_t *)malloc((size_t)ImageColorChannels * Width * Height);
|
||||
|
@ -735,7 +726,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffe
|
|||
dbg_msg("gfx", "3D/2D array texture was resized");
|
||||
int NewWidth = maximum<int>(HighestBit(ConvertWidth), 16);
|
||||
int NewHeight = maximum<int>(HighestBit(ConvertHeight), 16);
|
||||
uint8_t *pNewTexData = (uint8_t *)Resize(ConvertWidth, ConvertHeight, NewWidth, NewHeight, pCommand->m_Format, (const uint8_t *)pTexData);
|
||||
uint8_t *pNewTexData = (uint8_t *)Resize((const uint8_t *)pTexData, ConvertWidth, ConvertHeight, NewWidth, NewHeight, GLFormatToImageColorChannelCount(GLFormat));
|
||||
|
||||
ConvertWidth = NewWidth;
|
||||
ConvertHeight = NewHeight;
|
||||
|
@ -764,21 +755,45 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffe
|
|||
}
|
||||
|
||||
// This is the initial value for the wrap modes
|
||||
m_Textures[pCommand->m_Slot].m_LastWrapMode = CCommandBuffer::WRAP_REPEAT;
|
||||
m_Textures[Slot].m_LastWrapMode = CCommandBuffer::WRAP_REPEAT;
|
||||
|
||||
// calculate memory usage
|
||||
m_Textures[pCommand->m_Slot].m_MemSize = Width * Height * pCommand->m_PixelSize;
|
||||
m_Textures[Slot].m_MemSize = Width * Height * PixelSize;
|
||||
while(Width > 2 && Height > 2)
|
||||
{
|
||||
Width >>= 1;
|
||||
Height >>= 1;
|
||||
m_Textures[pCommand->m_Slot].m_MemSize += Width * Height * pCommand->m_PixelSize;
|
||||
m_Textures[Slot].m_MemSize += Width * Height * PixelSize;
|
||||
}
|
||||
m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) + m_Textures[pCommand->m_Slot].m_MemSize, std::memory_order_relaxed);
|
||||
m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) + m_Textures[Slot].m_MemSize, std::memory_order_relaxed);
|
||||
|
||||
free(pTexData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand)
|
||||
{
|
||||
TextureCreate(pCommand->m_Slot, pCommand->m_Width, pCommand->m_Height, pCommand->m_PixelSize, TexFormatToOpenGLFormat(pCommand->m_Format), TexFormatToOpenGLFormat(pCommand->m_StoreFormat), pCommand->m_Flags, pCommand->m_pData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_TextTexture_Update(const CCommandBuffer::SCommand_TextTexture_Update *pCommand)
|
||||
{
|
||||
TextureUpdate(pCommand->m_Slot, pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height, GL_RED, pCommand->m_pData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_TextTextures_Destroy(const CCommandBuffer::SCommand_TextTextures_Destroy *pCommand)
|
||||
{
|
||||
DestroyTexture(pCommand->m_Slot);
|
||||
DestroyTexture(pCommand->m_SlotOutline);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_TextTextures_Create(const CCommandBuffer::SCommand_TextTextures_Create *pCommand)
|
||||
{
|
||||
void *pTextData = pCommand->m_pTextData;
|
||||
void *pTextOutlineData = pCommand->m_pTextOutlineData;
|
||||
TextureCreate(pCommand->m_Slot, pCommand->m_Width, pCommand->m_Height, 1, GL_RED, GL_RED, CCommandBuffer::TEXFLAG_NOMIPMAPS, pTextData);
|
||||
TextureCreate(pCommand->m_SlotOutline, pCommand->m_Width, pCommand->m_Height, 1, GL_RED, GL_RED, CCommandBuffer::TEXFLAG_NOMIPMAPS, pTextOutlineData);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand)
|
||||
{
|
||||
if(pCommand->m_Color.r != m_ClearColor.r || pCommand->m_Color.g != m_ClearColor.g || pCommand->m_Color.b != m_ClearColor.b)
|
||||
|
@ -897,22 +912,10 @@ void CCommandProcessorFragment_OpenGL3_3::DestroyBufferContainer(int Index, bool
|
|||
// all buffer objects can deleted automatically, so the program doesn't need to deal with them (e.g. causing crashes because of driver bugs)
|
||||
if(DeleteBOs)
|
||||
{
|
||||
for(size_t i = 0; i < BufferContainer.m_ContainerInfo.m_Attributes.size(); ++i)
|
||||
int VertBufferID = BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex;
|
||||
if(VertBufferID != -1)
|
||||
{
|
||||
int VertBufferID = BufferContainer.m_ContainerInfo.m_Attributes[i].m_VertBufferBindingIndex;
|
||||
if(VertBufferID != -1)
|
||||
{
|
||||
for(auto &Attribute : BufferContainer.m_ContainerInfo.m_Attributes)
|
||||
{
|
||||
// set all equal ids to zero to not double delete
|
||||
if(VertBufferID == Attribute.m_VertBufferBindingIndex)
|
||||
{
|
||||
Attribute.m_VertBufferBindingIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
glDeleteBuffers(1, &m_BufferObjectIndices[VertBufferID]);
|
||||
}
|
||||
glDeleteBuffers(1, &m_BufferObjectIndices[VertBufferID]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -967,7 +970,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferObject(const CCommandB
|
|||
{
|
||||
void *pUploadData = pCommand->m_pUploadData;
|
||||
int Index = pCommand->m_BufferIndex;
|
||||
//create necessary space
|
||||
// create necessary space
|
||||
if((size_t)Index >= m_BufferObjectIndices.size())
|
||||
{
|
||||
for(int i = m_BufferObjectIndices.size(); i < Index + 1; ++i)
|
||||
|
@ -1032,13 +1035,14 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_DeleteBufferObject(const CCommandB
|
|||
void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand)
|
||||
{
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//create necessary space
|
||||
// create necessary space
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
{
|
||||
for(int i = m_BufferContainers.size(); i < Index + 1; ++i)
|
||||
{
|
||||
SBufferContainer Container;
|
||||
Container.m_ContainerInfo.m_Stride = 0;
|
||||
Container.m_ContainerInfo.m_VertBufferBindingIndex = -1;
|
||||
m_BufferContainers.push_back(Container);
|
||||
}
|
||||
}
|
||||
|
@ -1053,7 +1057,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferContainer(const CComma
|
|||
{
|
||||
glEnableVertexAttribArray((GLuint)i);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjectIndices[pCommand->m_Attributes[i].m_VertBufferBindingIndex]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjectIndices[pCommand->m_VertBufferBindingIndex]);
|
||||
|
||||
SBufferContainerInfo::SAttribute &Attr = pCommand->m_Attributes[i];
|
||||
|
||||
|
@ -1065,6 +1069,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferContainer(const CComma
|
|||
BufferContainer.m_ContainerInfo.m_Attributes.push_back(Attr);
|
||||
}
|
||||
|
||||
BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex = pCommand->m_VertBufferBindingIndex;
|
||||
BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride;
|
||||
}
|
||||
|
||||
|
@ -1074,7 +1079,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_UpdateBufferContainer(const CComma
|
|||
|
||||
glBindVertexArray(BufferContainer.m_VertArrayID);
|
||||
|
||||
//disable all old attributes
|
||||
// disable all old attributes
|
||||
for(size_t i = 0; i < BufferContainer.m_ContainerInfo.m_Attributes.size(); ++i)
|
||||
{
|
||||
glDisableVertexAttribArray((GLuint)i);
|
||||
|
@ -1085,7 +1090,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_UpdateBufferContainer(const CComma
|
|||
{
|
||||
glEnableVertexAttribArray((GLuint)i);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjectIndices[pCommand->m_Attributes[i].m_VertBufferBindingIndex]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjectIndices[pCommand->m_VertBufferBindingIndex]);
|
||||
SBufferContainerInfo::SAttribute &Attr = pCommand->m_Attributes[i];
|
||||
if(Attr.m_FuncType == 0)
|
||||
glVertexAttribPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, Attr.m_Normalized, pCommand->m_Stride, Attr.m_pOffset);
|
||||
|
@ -1095,6 +1100,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_UpdateBufferContainer(const CComma
|
|||
BufferContainer.m_ContainerInfo.m_Attributes.push_back(Attr);
|
||||
}
|
||||
|
||||
BufferContainer.m_ContainerInfo.m_VertBufferBindingIndex = pCommand->m_VertBufferBindingIndex;
|
||||
BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride;
|
||||
}
|
||||
|
||||
|
@ -1112,7 +1118,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_IndicesRequiredNumNotify(const CCo
|
|||
void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand)
|
||||
{
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
@ -1148,7 +1154,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTile(const CCommandBuf
|
|||
void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand)
|
||||
{
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
@ -1182,7 +1188,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTileLine(const CComman
|
|||
void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand)
|
||||
{
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
@ -1192,7 +1198,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTileLayer(const CCommandBuff
|
|||
|
||||
if(pCommand->m_IndicesDrawNum == 0)
|
||||
{
|
||||
return; //nothing to draw
|
||||
return; // nothing to draw
|
||||
}
|
||||
|
||||
CGLSLTileProgram *pProgram = NULL;
|
||||
|
@ -1223,7 +1229,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTileLayer(const CCommandBuff
|
|||
void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadLayer(const CCommandBuffer::SCommand_RenderQuadLayer *pCommand)
|
||||
{
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
@ -1233,7 +1239,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadLayer(const CCommandBuff
|
|||
|
||||
if(pCommand->m_QuadNum == 0)
|
||||
{
|
||||
return; //nothing to draw
|
||||
return; // nothing to draw
|
||||
}
|
||||
|
||||
CGLSLQuadProgram *pProgram = NULL;
|
||||
|
@ -1289,7 +1295,7 @@ void CCommandProcessorFragment_OpenGL3_3::RenderText(const CCommandBuffer::SStat
|
|||
{
|
||||
if(DrawNum == 0)
|
||||
{
|
||||
return; //nothing to draw
|
||||
return; // nothing to draw
|
||||
}
|
||||
|
||||
UseProgram(m_pTextProgram);
|
||||
|
@ -1373,7 +1379,7 @@ void CCommandProcessorFragment_OpenGL3_3::RenderText(const CCommandBuffer::SStat
|
|||
void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderText(const CCommandBuffer::SCommand_RenderText *pCommand)
|
||||
{
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
@ -1391,38 +1397,15 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderText(const CCommandBuffer::S
|
|||
RenderText(pCommand->m_State, pCommand->m_DrawNum, pCommand->m_TextTextureIndex, pCommand->m_TextOutlineTextureIndex, pCommand->m_TextureSize, pCommand->m_aTextColor, pCommand->m_aTextOutlineColor);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTextStream(const CCommandBuffer::SCommand_RenderTextStream *pCommand)
|
||||
{
|
||||
if(pCommand->m_PrimCount == 0)
|
||||
{
|
||||
return; //nothing to draw
|
||||
}
|
||||
|
||||
UploadStreamBufferData(CCommandBuffer::PRIMTYPE_QUADS, pCommand->m_pVertices, sizeof(CCommandBuffer::SVertex), pCommand->m_PrimCount);
|
||||
|
||||
glBindVertexArray(m_PrimitiveDrawVertexID[m_LastStreamBuffer]);
|
||||
if(m_LastIndexBufferBound[m_LastStreamBuffer] != m_QuadDrawIndexBufferID)
|
||||
{
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID);
|
||||
m_LastIndexBufferBound[m_LastStreamBuffer] = m_QuadDrawIndexBufferID;
|
||||
}
|
||||
|
||||
float aTextColor[4] = {1.f, 1.f, 1.f, 1.f};
|
||||
|
||||
RenderText(pCommand->m_State, pCommand->m_PrimCount * 6, pCommand->m_TextTextureIndex, pCommand->m_TextOutlineTextureIndex, pCommand->m_TextureSize, aTextColor, pCommand->m_aTextOutlineColor);
|
||||
|
||||
m_LastStreamBuffer = (m_LastStreamBuffer + 1 >= MAX_STREAM_BUFFER_COUNT ? 0 : m_LastStreamBuffer + 1);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainer(const CCommandBuffer::SCommand_RenderQuadContainer *pCommand)
|
||||
{
|
||||
if(pCommand->m_DrawNum == 0)
|
||||
{
|
||||
return; //nothing to draw
|
||||
return; // nothing to draw
|
||||
}
|
||||
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
@ -1450,11 +1433,11 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerEx(const CComma
|
|||
{
|
||||
if(pCommand->m_DrawNum == 0)
|
||||
{
|
||||
return; //nothing to draw
|
||||
return; // nothing to draw
|
||||
}
|
||||
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
@ -1515,11 +1498,11 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerAsSpriteMultipl
|
|||
{
|
||||
if(pCommand->m_DrawNum == 0 || pCommand->m_DrawCount == 0)
|
||||
{
|
||||
return; //nothing to draw
|
||||
return; // nothing to draw
|
||||
}
|
||||
|
||||
int Index = pCommand->m_BufferContainerIndex;
|
||||
//if space not there return
|
||||
// if space not there return
|
||||
if((size_t)Index >= m_BufferContainers.size())
|
||||
return;
|
||||
|
||||
|
|
|
@ -81,11 +81,17 @@ protected:
|
|||
void UploadStreamBufferData(unsigned int PrimitiveType, const void *pVertices, size_t VertSize, unsigned int PrimitiveCount, bool AsTex3D = false);
|
||||
void RenderText(const CCommandBuffer::SState &State, int DrawNum, int TextTextureIndex, int TextOutlineTextureIndex, int TextureSize, const float *pTextColor, const float *pTextOutlineColor);
|
||||
|
||||
void TextureUpdate(int Slot, int X, int Y, int Width, int Height, int GLFormat, void *pTexData);
|
||||
void TextureCreate(int Slot, int Width, int Height, int PixelSize, int GLFormat, int GLStoreFormat, int Flags, void *pTexData);
|
||||
|
||||
bool Cmd_Init(const SCommand_Init *pCommand) override;
|
||||
void Cmd_Shutdown(const SCommand_Shutdown *pCommand) override;
|
||||
void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) override;
|
||||
void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand) override;
|
||||
void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) override;
|
||||
void Cmd_TextTexture_Update(const CCommandBuffer::SCommand_TextTexture_Update *pCommand) override;
|
||||
void Cmd_TextTextures_Destroy(const CCommandBuffer::SCommand_TextTextures_Destroy *pCommand) override;
|
||||
void Cmd_TextTextures_Create(const CCommandBuffer::SCommand_TextTextures_Create *pCommand) override;
|
||||
void Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand) override;
|
||||
void Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand) override;
|
||||
void Cmd_RenderTex3D(const CCommandBuffer::SCommand_RenderTex3D *pCommand) override;
|
||||
|
@ -106,7 +112,6 @@ protected:
|
|||
void Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand) override;
|
||||
void Cmd_RenderQuadLayer(const CCommandBuffer::SCommand_RenderQuadLayer *pCommand) override;
|
||||
void Cmd_RenderText(const CCommandBuffer::SCommand_RenderText *pCommand) override;
|
||||
void Cmd_RenderTextStream(const CCommandBuffer::SCommand_RenderTextStream *pCommand) override;
|
||||
void Cmd_RenderQuadContainer(const CCommandBuffer::SCommand_RenderQuadContainer *pCommand) override;
|
||||
void Cmd_RenderQuadContainerEx(const CCommandBuffer::SCommand_RenderQuadContainerEx *pCommand) override;
|
||||
void Cmd_RenderQuadContainerAsSpriteMultiple(const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *pCommand) override;
|
||||
|
|
7060
src/engine/client/backend/vulkan/backend_vulkan.cpp
Normal file
7060
src/engine/client/backend/vulkan/backend_vulkan.cpp
Normal file
File diff suppressed because it is too large
Load diff
12
src/engine/client/backend/vulkan/backend_vulkan.h
Normal file
12
src/engine/client/backend/vulkan/backend_vulkan.h
Normal 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
|
|
@ -42,6 +42,12 @@
|
|||
#include "backend/opengles/backend_opengles3.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONF_BACKEND_VULKAN)
|
||||
#include <SDL_vulkan.h>
|
||||
|
||||
#include "backend/vulkan/backend_vulkan.h"
|
||||
#endif
|
||||
|
||||
#include "graphics_threaded.h"
|
||||
|
||||
#include <engine/shared/image_manipulation.h>
|
||||
|
@ -62,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
|
||||
|
@ -75,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())
|
||||
|
@ -94,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);
|
||||
|
@ -121,6 +129,11 @@ void CGraphicsBackend_Threaded::RunBuffer(CCommandBuffer *pBuffer)
|
|||
m_BufferSwapCond.notify_all();
|
||||
}
|
||||
|
||||
void CGraphicsBackend_Threaded::RunBufferSingleThreadedUnsafe(CCommandBuffer *pBuffer)
|
||||
{
|
||||
m_pProcessor->RunBuffer(pBuffer);
|
||||
}
|
||||
|
||||
bool CGraphicsBackend_Threaded::IsIdle() const
|
||||
{
|
||||
return !m_BufferInProcess.load(std::memory_order_relaxed);
|
||||
|
@ -129,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
|
||||
|
@ -157,22 +169,26 @@ void CCommandProcessorFragment_SDL::Cmd_Init(const SCommand_Init *pCommand)
|
|||
{
|
||||
m_GLContext = pCommand->m_GLContext;
|
||||
m_pWindow = pCommand->m_pWindow;
|
||||
SDL_GL_MakeCurrent(m_pWindow, m_GLContext);
|
||||
if(m_GLContext)
|
||||
SDL_GL_MakeCurrent(m_pWindow, m_GLContext);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_SDL::Cmd_Shutdown(const SCommand_Shutdown *pCommand)
|
||||
{
|
||||
SDL_GL_MakeCurrent(NULL, NULL);
|
||||
if(m_GLContext)
|
||||
SDL_GL_MakeCurrent(NULL, NULL);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_SDL::Cmd_Swap(const CCommandBuffer::SCommand_Swap *pCommand)
|
||||
{
|
||||
SDL_GL_SwapWindow(m_pWindow);
|
||||
if(m_GLContext)
|
||||
SDL_GL_SwapWindow(m_pWindow);
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_SDL::Cmd_VSync(const CCommandBuffer::SCommand_VSync *pCommand)
|
||||
{
|
||||
*pCommand->m_pRetOk = SDL_GL_SetSwapInterval(pCommand->m_VSync) == 0;
|
||||
if(m_GLContext)
|
||||
*pCommand->m_pRetOk = SDL_GL_SetSwapInterval(pCommand->m_VSync) == 0;
|
||||
}
|
||||
|
||||
void CCommandProcessorFragment_SDL::Cmd_WindowCreateNtf(const CCommandBuffer::SCommand_WindowCreateNtf *pCommand)
|
||||
|
@ -181,7 +197,8 @@ void CCommandProcessorFragment_SDL::Cmd_WindowCreateNtf(const CCommandBuffer::SC
|
|||
// Android destroys windows when they are not visible, so we get the new one and work with that
|
||||
// The graphic context does not need to be recreated, just unbound see @see SCommand_WindowDestroyNtf
|
||||
#ifdef CONF_PLATFORM_ANDROID
|
||||
SDL_GL_MakeCurrent(m_pWindow, m_GLContext);
|
||||
if(m_GLContext)
|
||||
SDL_GL_MakeCurrent(m_pWindow, m_GLContext);
|
||||
dbg_msg("gfx", "render surface created.");
|
||||
#endif
|
||||
}
|
||||
|
@ -191,7 +208,8 @@ void CCommandProcessorFragment_SDL::Cmd_WindowDestroyNtf(const CCommandBuffer::S
|
|||
// Unbind the graphic context from the window, so it does not get destroyed
|
||||
#ifdef CONF_PLATFORM_ANDROID
|
||||
dbg_msg("gfx", "render surface destroyed.");
|
||||
SDL_GL_MakeCurrent(NULL, NULL);
|
||||
if(m_GLContext)
|
||||
SDL_GL_MakeCurrent(NULL, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -207,19 +225,23 @@ bool CCommandProcessorFragment_SDL::RunCommand(const CCommandBuffer::SCommand *p
|
|||
case CCommandBuffer::CMD_VSYNC: Cmd_VSync(static_cast<const CCommandBuffer::SCommand_VSync *>(pBaseCommand)); break;
|
||||
case CMD_INIT: Cmd_Init(static_cast<const SCommand_Init *>(pBaseCommand)); break;
|
||||
case CMD_SHUTDOWN: Cmd_Shutdown(static_cast<const SCommand_Shutdown *>(pBaseCommand)); break;
|
||||
case CCommandProcessorFragment_GLBase::CMD_PRE_INIT: break;
|
||||
case CCommandProcessorFragment_GLBase::CMD_POST_SHUTDOWN: break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------ CCommandProcessor_SDL_OpenGL
|
||||
// ------------ CCommandProcessor_SDL_GL
|
||||
|
||||
void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer)
|
||||
void CCommandProcessor_SDL_GL::RunBuffer(CCommandBuffer *pBuffer)
|
||||
{
|
||||
m_pGLBackend->StartCommands(pBuffer->m_CommandCount, pBuffer->m_RenderCallCount);
|
||||
|
||||
for(CCommandBuffer::SCommand *pCommand = pBuffer->Head(); pCommand; pCommand = pCommand->m_pNext)
|
||||
{
|
||||
if(m_pOpenGL->RunCommand(pCommand))
|
||||
if(m_pGLBackend->RunCommand(pCommand))
|
||||
continue;
|
||||
|
||||
if(m_SDL.RunCommand(pCommand))
|
||||
|
@ -230,61 +252,69 @@ void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer)
|
|||
|
||||
dbg_msg("gfx", "unknown command %d", pCommand->m_Cmd);
|
||||
}
|
||||
|
||||
m_pGLBackend->EndCommands();
|
||||
}
|
||||
|
||||
CCommandProcessor_SDL_OpenGL::CCommandProcessor_SDL_OpenGL(EBackendType BackendType, int OpenGLMajor, int OpenGLMinor, int OpenGLPatch)
|
||||
CCommandProcessor_SDL_GL::CCommandProcessor_SDL_GL(EBackendType BackendType, int GLMajor, int GLMinor, int GLPatch)
|
||||
{
|
||||
m_BackendType = BackendType;
|
||||
|
||||
if(BackendType == BACKEND_TYPE_OPENGL_ES)
|
||||
{
|
||||
#if defined(CONF_BACKEND_OPENGL_ES) || defined(CONF_BACKEND_OPENGL_ES3)
|
||||
if(OpenGLMajor < 3)
|
||||
if(GLMajor < 3)
|
||||
{
|
||||
m_pOpenGL = new CCommandProcessorFragment_OpenGLES();
|
||||
m_pGLBackend = new CCommandProcessorFragment_OpenGLES();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pOpenGL = new CCommandProcessorFragment_OpenGLES3();
|
||||
m_pGLBackend = new CCommandProcessorFragment_OpenGLES3();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(BackendType == BACKEND_TYPE_OPENGL)
|
||||
{
|
||||
#if !defined(CONF_BACKEND_OPENGL_ES)
|
||||
if(OpenGLMajor < 2)
|
||||
if(GLMajor < 2)
|
||||
{
|
||||
m_pOpenGL = new CCommandProcessorFragment_OpenGL();
|
||||
m_pGLBackend = new CCommandProcessorFragment_OpenGL();
|
||||
}
|
||||
if(OpenGLMajor == 2)
|
||||
if(GLMajor == 2)
|
||||
{
|
||||
m_pOpenGL = new CCommandProcessorFragment_OpenGL2();
|
||||
m_pGLBackend = new CCommandProcessorFragment_OpenGL2();
|
||||
}
|
||||
if(OpenGLMajor == 3 && OpenGLMinor == 0)
|
||||
if(GLMajor == 3 && GLMinor == 0)
|
||||
{
|
||||
m_pOpenGL = new CCommandProcessorFragment_OpenGL3();
|
||||
m_pGLBackend = new CCommandProcessorFragment_OpenGL3();
|
||||
}
|
||||
else if((OpenGLMajor == 3 && OpenGLMinor == 3) || OpenGLMajor >= 4)
|
||||
else if((GLMajor == 3 && GLMinor == 3) || GLMajor >= 4)
|
||||
{
|
||||
m_pOpenGL = new CCommandProcessorFragment_OpenGL3_3();
|
||||
m_pGLBackend = new CCommandProcessorFragment_OpenGL3_3();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(BackendType == BACKEND_TYPE_VULKAN)
|
||||
{
|
||||
#if defined(CONF_BACKEND_VULKAN)
|
||||
m_pGLBackend = CreateVulkanCommandProcessorFragment();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
CCommandProcessor_SDL_OpenGL::~CCommandProcessor_SDL_OpenGL()
|
||||
CCommandProcessor_SDL_GL::~CCommandProcessor_SDL_GL()
|
||||
{
|
||||
delete m_pOpenGL;
|
||||
delete m_pGLBackend;
|
||||
}
|
||||
|
||||
// ------------ CGraphicsBackend_SDL_OpenGL
|
||||
// ------------ CGraphicsBackend_SDL_GL
|
||||
|
||||
static bool BackendInitGlew(EBackendType BackendType, int &GlewMajor, int &GlewMinor, int &GlewPatch)
|
||||
{
|
||||
if(BackendType == BACKEND_TYPE_OPENGL)
|
||||
{
|
||||
#ifndef CONF_BACKEND_OPENGL_ES
|
||||
//support graphic cards that are pretty old(and linux)
|
||||
// support graphic cards that are pretty old(and linux)
|
||||
glewExperimental = GL_TRUE;
|
||||
#ifdef CONF_GLEW_HAS_CONTEXT_INIT
|
||||
if(GLEW_OK != glewContextInit())
|
||||
|
@ -529,124 +559,182 @@ static int IsVersionSupportedGlew(EBackendType BackendType, int VersionMajor, in
|
|||
return InitError;
|
||||
}
|
||||
|
||||
EBackendType CGraphicsBackend_SDL_OpenGL::DetectBackend()
|
||||
EBackendType CGraphicsBackend_SDL_GL::DetectBackend()
|
||||
{
|
||||
#ifndef CONF_BACKEND_OPENGL_ES
|
||||
#ifdef CONF_BACKEND_OPENGL_ES3
|
||||
const char *pEnvDriver = getenv("DDNET_DRIVER");
|
||||
if(pEnvDriver && str_comp(pEnvDriver, "GLES") == 0)
|
||||
return BACKEND_TYPE_OPENGL_ES;
|
||||
else
|
||||
return BACKEND_TYPE_OPENGL;
|
||||
#else
|
||||
return BACKEND_TYPE_OPENGL;
|
||||
EBackendType RetBackendType = BACKEND_TYPE_OPENGL;
|
||||
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)
|
||||
RetBackendType = BACKEND_TYPE_VULKAN;
|
||||
else if(pEnvDriver && str_comp_nocase(pEnvDriver, "OpenGL") == 0)
|
||||
RetBackendType = BACKEND_TYPE_OPENGL;
|
||||
else if(pEnvDriver == nullptr)
|
||||
{
|
||||
// load the config backend
|
||||
const char *pConfBackend = g_Config.m_GfxBackend;
|
||||
if(str_comp_nocase(pConfBackend, "GLES") == 0)
|
||||
RetBackendType = BACKEND_TYPE_OPENGL_ES;
|
||||
else if(str_comp_nocase(pConfBackend, "Vulkan") == 0)
|
||||
RetBackendType = BACKEND_TYPE_VULKAN;
|
||||
else if(str_comp_nocase(pConfBackend, "OpenGL") == 0)
|
||||
RetBackendType = BACKEND_TYPE_OPENGL;
|
||||
}
|
||||
#if !defined(CONF_BACKEND_VULKAN)
|
||||
RetBackendType = BACKEND_TYPE_OPENGL;
|
||||
#endif
|
||||
#else
|
||||
return BACKEND_TYPE_OPENGL_ES;
|
||||
#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;
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::ClampDriverVersion(EBackendType BackendType)
|
||||
void CGraphicsBackend_SDL_GL::ClampDriverVersion(EBackendType BackendType)
|
||||
{
|
||||
if(BackendType == BACKEND_TYPE_OPENGL)
|
||||
{
|
||||
//clamp the versions to existing versions(only for OpenGL major <= 3)
|
||||
if(g_Config.m_GfxOpenGLMajor == 1)
|
||||
// clamp the versions to existing versions(only for OpenGL major <= 3)
|
||||
if(g_Config.m_GfxGLMajor == 1)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMinor = clamp(g_Config.m_GfxOpenGLMinor, 1, 5);
|
||||
if(g_Config.m_GfxOpenGLMinor == 2)
|
||||
g_Config.m_GfxOpenGLPatch = clamp(g_Config.m_GfxOpenGLPatch, 0, 1);
|
||||
g_Config.m_GfxGLMinor = clamp(g_Config.m_GfxGLMinor, 1, 5);
|
||||
if(g_Config.m_GfxGLMinor == 2)
|
||||
g_Config.m_GfxGLPatch = clamp(g_Config.m_GfxGLPatch, 0, 1);
|
||||
else
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
else if(g_Config.m_GfxOpenGLMajor == 2)
|
||||
else if(g_Config.m_GfxGLMajor == 2)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMinor = clamp(g_Config.m_GfxOpenGLMinor, 0, 1);
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMinor = clamp(g_Config.m_GfxGLMinor, 0, 1);
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
else if(g_Config.m_GfxOpenGLMajor == 3)
|
||||
else if(g_Config.m_GfxGLMajor == 3)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMinor = clamp(g_Config.m_GfxOpenGLMinor, 0, 3);
|
||||
if(g_Config.m_GfxOpenGLMinor < 3)
|
||||
g_Config.m_GfxOpenGLMinor = 0;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMinor = clamp(g_Config.m_GfxGLMinor, 0, 3);
|
||||
if(g_Config.m_GfxGLMinor < 3)
|
||||
g_Config.m_GfxGLMinor = 0;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
}
|
||||
else if(BackendType == BACKEND_TYPE_OPENGL_ES)
|
||||
{
|
||||
#if !defined(CONF_BACKEND_OPENGL_ES3)
|
||||
// Make sure GLES is set to 1.0 (which is equivalent to OpenGL 1.3), if its not set to >= 3.0(which is equivalent to OpenGL 3.3)
|
||||
if(g_Config.m_GfxOpenGLMajor < 3)
|
||||
if(g_Config.m_GfxGLMajor < 3)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = 1;
|
||||
g_Config.m_GfxOpenGLMinor = 0;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMajor = 1;
|
||||
g_Config.m_GfxGLMinor = 0;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
|
||||
// GLES also doesnt know GL_QUAD
|
||||
g_Config.m_GfxQuadAsTriangle = 1;
|
||||
}
|
||||
#else
|
||||
g_Config.m_GfxOpenGLMajor = 3;
|
||||
g_Config.m_GfxOpenGLMinor = 0;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMajor = 3;
|
||||
g_Config.m_GfxGLMinor = 0;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
#endif
|
||||
}
|
||||
else if(BackendType == BACKEND_TYPE_VULKAN)
|
||||
{
|
||||
#if defined(CONF_BACKEND_VULKAN)
|
||||
g_Config.m_GfxGLMajor = gs_BackendVulkanMajor;
|
||||
g_Config.m_GfxGLMinor = gs_BackendVulkanMinor;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool CGraphicsBackend_SDL_OpenGL::IsModernAPI(EBackendType BackendType)
|
||||
bool CGraphicsBackend_SDL_GL::IsModernAPI(EBackendType BackendType)
|
||||
{
|
||||
if(BackendType == BACKEND_TYPE_OPENGL)
|
||||
return (g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor == 3) || g_Config.m_GfxOpenGLMajor >= 4;
|
||||
return (g_Config.m_GfxGLMajor == 3 && g_Config.m_GfxGLMinor == 3) || g_Config.m_GfxGLMajor >= 4;
|
||||
else if(BackendType == BACKEND_TYPE_OPENGL_ES)
|
||||
return g_Config.m_GfxOpenGLMajor >= 3;
|
||||
return g_Config.m_GfxGLMajor >= 3;
|
||||
else if(BackendType == BACKEND_TYPE_VULKAN)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::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)
|
||||
|
@ -662,7 +750,7 @@ static void DisplayToVideoMode(CVideoMode *pVMode, SDL_DisplayMode *pMode, int H
|
|||
pVMode->m_Format = pMode->format;
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::GetVideoModes(CVideoMode *pModes, int MaxModes, int *pNumModes, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen)
|
||||
void CGraphicsBackend_SDL_GL::GetVideoModes(CVideoMode *pModes, int MaxModes, int *pNumModes, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen)
|
||||
{
|
||||
SDL_DisplayMode DesktopMode;
|
||||
int maxModes = SDL_GetNumDisplayModes(Screen);
|
||||
|
@ -726,7 +814,7 @@ void CGraphicsBackend_SDL_OpenGL::GetVideoModes(CVideoMode *pModes, int MaxModes
|
|||
*pNumModes = numModes;
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::GetCurrentVideoMode(CVideoMode &CurMode, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen)
|
||||
void CGraphicsBackend_SDL_GL::GetCurrentVideoMode(CVideoMode &CurMode, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen)
|
||||
{
|
||||
SDL_DisplayMode DPMode;
|
||||
// if "real" fullscreen, obtain the video mode for that
|
||||
|
@ -755,12 +843,12 @@ void CGraphicsBackend_SDL_OpenGL::GetCurrentVideoMode(CVideoMode &CurMode, int H
|
|||
DisplayToVideoMode(&CurMode, &DPMode, HiDPIScale, DPMode.refresh_rate);
|
||||
}
|
||||
|
||||
CGraphicsBackend_SDL_OpenGL::CGraphicsBackend_SDL_OpenGL()
|
||||
CGraphicsBackend_SDL_GL::CGraphicsBackend_SDL_GL()
|
||||
{
|
||||
mem_zero(m_aErrorString, sizeof(m_aErrorString) / sizeof(m_aErrorString[0]));
|
||||
}
|
||||
|
||||
int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWidth, int *pHeight, int *pRefreshRate, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, IStorage *pStorage)
|
||||
int CGraphicsBackend_SDL_GL::Init(const char *pName, int *pScreen, int *pWidth, int *pHeight, int *pRefreshRate, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, IStorage *pStorage)
|
||||
{
|
||||
// print sdl version
|
||||
{
|
||||
|
@ -782,23 +870,39 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
m_UseNewOpenGL = IsModernAPI(m_BackendType);
|
||||
bool UseModernGL = IsModernAPI(m_BackendType);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, g_Config.m_GfxOpenGLMajor);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, g_Config.m_GfxOpenGLMinor);
|
||||
dbg_msg("gfx", "Created OpenGL %d.%d context.", g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor);
|
||||
bool IsOpenGLFamilyBackend = m_BackendType == BACKEND_TYPE_OPENGL || m_BackendType == BACKEND_TYPE_OPENGL_ES;
|
||||
|
||||
if(IsOpenGLFamilyBackend)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, g_Config.m_GfxGLMajor);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, g_Config.m_GfxGLMinor);
|
||||
}
|
||||
|
||||
dbg_msg("gfx", "Created %s %d.%d context.", ((m_BackendType == BACKEND_TYPE_VULKAN) ? "Vulkan" : "OpenGL"), g_Config.m_GfxGLMajor, g_Config.m_GfxGLMinor);
|
||||
|
||||
if(m_BackendType == BACKEND_TYPE_OPENGL)
|
||||
{
|
||||
if(g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor == 0)
|
||||
if(g_Config.m_GfxGLMajor == 3 && g_Config.m_GfxGLMinor == 0)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
||||
}
|
||||
else if(m_UseNewOpenGL)
|
||||
else if(UseModernGL)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
}
|
||||
|
@ -858,7 +962,8 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
|
|||
}
|
||||
|
||||
// set flags
|
||||
int SdlFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS;
|
||||
int SdlFlags = SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS;
|
||||
SdlFlags |= (IsOpenGLFamilyBackend) ? SDL_WINDOW_OPENGL : SDL_WINDOW_VULKAN;
|
||||
if(Flags & IGraphicsBackend::INITFLAG_HIGHDPI)
|
||||
SdlFlags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
if(Flags & IGraphicsBackend::INITFLAG_RESIZABLE)
|
||||
|
@ -891,16 +996,19 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
|
|||
}
|
||||
|
||||
// set gl attributes
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
if(FsaaSamples)
|
||||
if(IsOpenGLFamilyBackend)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, FsaaSamples);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
if(FsaaSamples)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, FsaaSamples);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(g_Config.m_InpMouseOld)
|
||||
|
@ -918,63 +1026,86 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
|
|||
if(m_pWindow == NULL)
|
||||
{
|
||||
dbg_msg("gfx", "unable to create window: %s", SDL_GetError());
|
||||
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_SDL_WINDOW_CREATE_FAILED;
|
||||
}
|
||||
|
||||
m_GLContext = SDL_GL_CreateContext(m_pWindow);
|
||||
|
||||
if(m_GLContext == NULL)
|
||||
{
|
||||
SDL_DestroyWindow(m_pWindow);
|
||||
dbg_msg("gfx", "unable to create OpenGL context: %s", SDL_GetError());
|
||||
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_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;
|
||||
int GlewMinor = 0;
|
||||
int GlewPatch = 0;
|
||||
|
||||
if(!BackendInitGlew(m_BackendType, GlewMajor, GlewMinor, GlewPatch))
|
||||
if(IsOpenGLFamilyBackend)
|
||||
{
|
||||
SDL_GL_DeleteContext(m_GLContext);
|
||||
SDL_DestroyWindow(m_pWindow);
|
||||
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_UNKNOWN;
|
||||
m_GLContext = SDL_GL_CreateContext(m_pWindow);
|
||||
|
||||
if(m_GLContext == NULL)
|
||||
{
|
||||
SDL_DestroyWindow(m_pWindow);
|
||||
dbg_msg("gfx", "unable to create graphic context: %s", SDL_GetError());
|
||||
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_GL_CONTEXT_FAILED;
|
||||
}
|
||||
|
||||
if(!BackendInitGlew(m_BackendType, GlewMajor, GlewMinor, GlewPatch))
|
||||
{
|
||||
SDL_GL_DeleteContext(m_GLContext);
|
||||
SDL_DestroyWindow(m_pWindow);
|
||||
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
int InitError = 0;
|
||||
const char *pErrorStr = NULL;
|
||||
|
||||
InitError = IsVersionSupportedGlew(m_BackendType, g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch, GlewMajor, GlewMinor, GlewPatch);
|
||||
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);
|
||||
|
||||
SDL_GL_SetSwapInterval(Flags & IGraphicsBackend::INITFLAG_VSYNC ? 1 : 0);
|
||||
SDL_GL_MakeCurrent(NULL, NULL);
|
||||
if(IsOpenGLFamilyBackend)
|
||||
{
|
||||
SDL_GL_SetSwapInterval(Flags & IGraphicsBackend::INITFLAG_VSYNC ? 1 : 0);
|
||||
SDL_GL_MakeCurrent(NULL, NULL);
|
||||
}
|
||||
|
||||
if(InitError != 0)
|
||||
{
|
||||
SDL_GL_DeleteContext(m_GLContext);
|
||||
if(m_GLContext)
|
||||
SDL_GL_DeleteContext(m_GLContext);
|
||||
SDL_DestroyWindow(m_pWindow);
|
||||
|
||||
// try setting to glew supported version
|
||||
g_Config.m_GfxOpenGLMajor = GlewMajor;
|
||||
g_Config.m_GfxOpenGLMinor = GlewMinor;
|
||||
g_Config.m_GfxOpenGLPatch = GlewPatch;
|
||||
g_Config.m_GfxGLMajor = GlewMajor;
|
||||
g_Config.m_GfxGLMinor = GlewMinor;
|
||||
g_Config.m_GfxGLPatch = GlewPatch;
|
||||
|
||||
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED;
|
||||
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_GL_VERSION_FAILED;
|
||||
}
|
||||
|
||||
// start the command processor
|
||||
m_pProcessor = new CCommandProcessor_SDL_OpenGL(m_BackendType, g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch);
|
||||
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);
|
||||
|
||||
// issue init commands for OpenGL and SDL
|
||||
CCommandBuffer CmdBuffer(1024, 512);
|
||||
//run sdl first to have the context in the thread
|
||||
CCommandProcessorFragment_GLBase::SCommand_PreInit CmdPre;
|
||||
CmdPre.m_pWindow = m_pWindow;
|
||||
CmdPre.m_Width = *pCurrentWidth;
|
||||
CmdPre.m_Height = *pCurrentHeight;
|
||||
CmdPre.m_pVendorString = m_aVendorString;
|
||||
CmdPre.m_pVersionString = m_aVersionString;
|
||||
CmdPre.m_pRendererString = m_aRendererString;
|
||||
CmdPre.m_pGPUList = &m_GPUList;
|
||||
CmdBuffer.AddCommandUnsafe(CmdPre);
|
||||
RunBufferSingleThreadedUnsafe(&CmdBuffer);
|
||||
CmdBuffer.Reset();
|
||||
|
||||
// run sdl first to have the context in the thread
|
||||
CCommandProcessorFragment_SDL::SCommand_Init CmdSDL;
|
||||
CmdSDL.m_pWindow = m_pWindow;
|
||||
CmdSDL.m_GLContext = m_GLContext;
|
||||
|
@ -985,23 +1116,31 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
|
|||
|
||||
if(InitError == 0)
|
||||
{
|
||||
CCommandProcessorFragment_OpenGLBase::SCommand_Init CmdOpenGL;
|
||||
CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage;
|
||||
CmdOpenGL.m_pStorage = pStorage;
|
||||
CmdOpenGL.m_pCapabilities = &m_Capabilites;
|
||||
CmdOpenGL.m_pInitError = &InitError;
|
||||
CmdOpenGL.m_RequestedMajor = g_Config.m_GfxOpenGLMajor;
|
||||
CmdOpenGL.m_RequestedMinor = g_Config.m_GfxOpenGLMinor;
|
||||
CmdOpenGL.m_RequestedPatch = g_Config.m_GfxOpenGLPatch;
|
||||
CmdOpenGL.m_GlewMajor = GlewMajor;
|
||||
CmdOpenGL.m_GlewMinor = GlewMinor;
|
||||
CmdOpenGL.m_GlewPatch = GlewPatch;
|
||||
CmdOpenGL.m_pErrStringPtr = &pErrorStr;
|
||||
CmdOpenGL.m_pVendorString = m_aVendorString;
|
||||
CmdOpenGL.m_pVersionString = m_aVersionString;
|
||||
CmdOpenGL.m_pRendererString = m_aRendererString;
|
||||
CmdOpenGL.m_RequestedBackend = m_BackendType;
|
||||
CmdBuffer.AddCommandUnsafe(CmdOpenGL);
|
||||
CCommandProcessorFragment_GLBase::SCommand_Init CmdGL;
|
||||
CmdGL.m_pWindow = m_pWindow;
|
||||
CmdGL.m_Width = *pCurrentWidth;
|
||||
CmdGL.m_Height = *pCurrentHeight;
|
||||
CmdGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage;
|
||||
CmdGL.m_pBufferMemoryUsage = &m_BufferMemoryUsage;
|
||||
CmdGL.m_pStreamMemoryUsage = &m_StreamMemoryUsage;
|
||||
CmdGL.m_pStagingMemoryUsage = &m_StagingMemoryUsage;
|
||||
CmdGL.m_pGPUList = &m_GPUList;
|
||||
CmdGL.m_pReadPresentedImageDataFunc = &m_ReadPresentedImageDataFunc;
|
||||
CmdGL.m_pStorage = pStorage;
|
||||
CmdGL.m_pCapabilities = &m_Capabilites;
|
||||
CmdGL.m_pInitError = &InitError;
|
||||
CmdGL.m_RequestedMajor = g_Config.m_GfxGLMajor;
|
||||
CmdGL.m_RequestedMinor = g_Config.m_GfxGLMinor;
|
||||
CmdGL.m_RequestedPatch = g_Config.m_GfxGLPatch;
|
||||
CmdGL.m_GlewMajor = GlewMajor;
|
||||
CmdGL.m_GlewMinor = GlewMinor;
|
||||
CmdGL.m_GlewPatch = GlewPatch;
|
||||
CmdGL.m_pErrStringPtr = &pErrorStr;
|
||||
CmdGL.m_pVendorString = m_aVendorString;
|
||||
CmdGL.m_pVersionString = m_aVersionString;
|
||||
CmdGL.m_pRendererString = m_aRendererString;
|
||||
CmdGL.m_RequestedBackend = m_BackendType;
|
||||
CmdBuffer.AddCommandUnsafe(CmdGL);
|
||||
|
||||
RunBuffer(&CmdBuffer);
|
||||
WaitForIdle();
|
||||
|
@ -1013,7 +1152,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
|
|||
if(InitError != -2)
|
||||
{
|
||||
// shutdown the context, as it might have been initialized
|
||||
CCommandProcessorFragment_OpenGLBase::SCommand_Shutdown CmdGL;
|
||||
CCommandProcessorFragment_GLBase::SCommand_Shutdown CmdGL;
|
||||
CmdBuffer.AddCommandUnsafe(CmdGL);
|
||||
RunBuffer(&CmdBuffer);
|
||||
WaitForIdle();
|
||||
|
@ -1026,20 +1165,26 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
|
|||
WaitForIdle();
|
||||
CmdBuffer.Reset();
|
||||
|
||||
CCommandProcessorFragment_GLBase::SCommand_PostShutdown CmdPost;
|
||||
CmdBuffer.AddCommandUnsafe(CmdPost);
|
||||
RunBufferSingleThreadedUnsafe(&CmdBuffer);
|
||||
CmdBuffer.Reset();
|
||||
|
||||
// stop and delete the processor
|
||||
StopProcessor();
|
||||
delete m_pProcessor;
|
||||
m_pProcessor = 0;
|
||||
m_pProcessor = nullptr;
|
||||
|
||||
SDL_GL_DeleteContext(m_GLContext);
|
||||
if(m_GLContext)
|
||||
SDL_GL_DeleteContext(m_GLContext);
|
||||
SDL_DestroyWindow(m_pWindow);
|
||||
|
||||
// try setting to version string's supported version
|
||||
if(InitError == -2)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = m_Capabilites.m_ContextMajor;
|
||||
g_Config.m_GfxOpenGLMinor = m_Capabilites.m_ContextMinor;
|
||||
g_Config.m_GfxOpenGLPatch = m_Capabilites.m_ContextPatch;
|
||||
g_Config.m_GfxGLMajor = m_Capabilites.m_ContextMajor;
|
||||
g_Config.m_GfxGLMinor = m_Capabilites.m_ContextMinor;
|
||||
g_Config.m_GfxGLPatch = m_Capabilites.m_ContextPatch;
|
||||
}
|
||||
|
||||
if(pErrorStr != NULL)
|
||||
|
@ -1047,7 +1192,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
|
|||
str_copy(m_aErrorString, pErrorStr, sizeof(m_aErrorString) / sizeof(m_aErrorString[0]));
|
||||
}
|
||||
|
||||
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED;
|
||||
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_GL_VERSION_FAILED;
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -1057,6 +1202,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
|
|||
|
||||
CmdSDL2.m_Width = *pCurrentWidth;
|
||||
CmdSDL2.m_Height = *pCurrentHeight;
|
||||
CmdSDL2.m_ByResize = true;
|
||||
CmdBuffer.AddCommandUnsafe(CmdSDL2);
|
||||
RunBuffer(&CmdBuffer);
|
||||
WaitForIdle();
|
||||
|
@ -1067,11 +1213,11 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *pScreen, int *pWid
|
|||
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_NONE;
|
||||
}
|
||||
|
||||
int CGraphicsBackend_SDL_OpenGL::Shutdown()
|
||||
int CGraphicsBackend_SDL_GL::Shutdown()
|
||||
{
|
||||
// issue a shutdown command
|
||||
CCommandBuffer CmdBuffer(1024, 512);
|
||||
CCommandProcessorFragment_OpenGLBase::SCommand_Shutdown CmdGL;
|
||||
CCommandProcessorFragment_GLBase::SCommand_Shutdown CmdGL;
|
||||
CmdBuffer.AddCommandUnsafe(CmdGL);
|
||||
RunBuffer(&CmdBuffer);
|
||||
WaitForIdle();
|
||||
|
@ -1083,10 +1229,15 @@ int CGraphicsBackend_SDL_OpenGL::Shutdown()
|
|||
WaitForIdle();
|
||||
CmdBuffer.Reset();
|
||||
|
||||
CCommandProcessorFragment_GLBase::SCommand_PostShutdown CmdPost;
|
||||
CmdBuffer.AddCommandUnsafe(CmdPost);
|
||||
RunBufferSingleThreadedUnsafe(&CmdBuffer);
|
||||
CmdBuffer.Reset();
|
||||
|
||||
// stop and delete the processor
|
||||
StopProcessor();
|
||||
delete m_pProcessor;
|
||||
m_pProcessor = 0;
|
||||
m_pProcessor = nullptr;
|
||||
|
||||
SDL_GL_DeleteContext(m_GLContext);
|
||||
SDL_DestroyWindow(m_pWindow);
|
||||
|
@ -1095,22 +1246,42 @@ int CGraphicsBackend_SDL_OpenGL::Shutdown()
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CGraphicsBackend_SDL_OpenGL::MemoryUsage() const
|
||||
uint64_t CGraphicsBackend_SDL_GL::TextureMemoryUsage() const
|
||||
{
|
||||
return m_TextureMemoryUsage;
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::Minimize()
|
||||
uint64_t CGraphicsBackend_SDL_GL::BufferMemoryUsage() const
|
||||
{
|
||||
return m_BufferMemoryUsage;
|
||||
}
|
||||
|
||||
uint64_t CGraphicsBackend_SDL_GL::StreamedMemoryUsage() const
|
||||
{
|
||||
return m_StreamMemoryUsage;
|
||||
}
|
||||
|
||||
uint64_t CGraphicsBackend_SDL_GL::StagingMemoryUsage() const
|
||||
{
|
||||
return m_StagingMemoryUsage;
|
||||
}
|
||||
|
||||
const TTWGraphicsGPUList &CGraphicsBackend_SDL_GL::GetGPUs() const
|
||||
{
|
||||
return m_GPUList;
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_GL::Minimize()
|
||||
{
|
||||
SDL_MinimizeWindow(m_pWindow);
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::Maximize()
|
||||
void CGraphicsBackend_SDL_GL::Maximize()
|
||||
{
|
||||
// TODO: SDL
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing)
|
||||
void CGraphicsBackend_SDL_GL::SetWindowParams(int FullscreenMode, bool IsBorderless, bool AllowResizing)
|
||||
{
|
||||
if(FullscreenMode > 0)
|
||||
{
|
||||
|
@ -1159,7 +1330,7 @@ void CGraphicsBackend_SDL_OpenGL::SetWindowParams(int FullscreenMode, bool IsBor
|
|||
}
|
||||
}
|
||||
|
||||
bool CGraphicsBackend_SDL_OpenGL::SetWindowScreen(int Index)
|
||||
bool CGraphicsBackend_SDL_GL::SetWindowScreen(int Index)
|
||||
{
|
||||
if(Index < 0 || Index >= m_NumScreens)
|
||||
{
|
||||
|
@ -1179,7 +1350,7 @@ bool CGraphicsBackend_SDL_OpenGL::SetWindowScreen(int Index)
|
|||
return UpdateDisplayMode(Index);
|
||||
}
|
||||
|
||||
bool CGraphicsBackend_SDL_OpenGL::UpdateDisplayMode(int Index)
|
||||
bool CGraphicsBackend_SDL_GL::UpdateDisplayMode(int Index)
|
||||
{
|
||||
SDL_DisplayMode DisplayMode;
|
||||
if(SDL_GetDesktopDisplayMode(Index, &DisplayMode) < 0)
|
||||
|
@ -1194,27 +1365,27 @@ bool CGraphicsBackend_SDL_OpenGL::UpdateDisplayMode(int Index)
|
|||
return true;
|
||||
}
|
||||
|
||||
int CGraphicsBackend_SDL_OpenGL::GetWindowScreen()
|
||||
int CGraphicsBackend_SDL_GL::GetWindowScreen()
|
||||
{
|
||||
return SDL_GetWindowDisplayIndex(m_pWindow);
|
||||
}
|
||||
|
||||
int CGraphicsBackend_SDL_OpenGL::WindowActive()
|
||||
int CGraphicsBackend_SDL_GL::WindowActive()
|
||||
{
|
||||
return m_pWindow && SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_INPUT_FOCUS;
|
||||
}
|
||||
|
||||
int CGraphicsBackend_SDL_OpenGL::WindowOpen()
|
||||
int CGraphicsBackend_SDL_GL::WindowOpen()
|
||||
{
|
||||
return m_pWindow && SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_SHOWN;
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::SetWindowGrab(bool Grab)
|
||||
void CGraphicsBackend_SDL_GL::SetWindowGrab(bool Grab)
|
||||
{
|
||||
SDL_SetWindowGrab(m_pWindow, Grab ? SDL_TRUE : SDL_FALSE);
|
||||
}
|
||||
|
||||
bool CGraphicsBackend_SDL_OpenGL::ResizeWindow(int w, int h, int RefreshRate)
|
||||
bool CGraphicsBackend_SDL_GL::ResizeWindow(int w, int h, int RefreshRate)
|
||||
{
|
||||
// don't call resize events when the window is at fullscreen desktop
|
||||
if(!m_pWindow || (SDL_GetWindowFlags(m_pWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)
|
||||
|
@ -1252,12 +1423,12 @@ bool CGraphicsBackend_SDL_OpenGL::ResizeWindow(int w, int h, int RefreshRate)
|
|||
return false;
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::GetViewportSize(int &w, int &h)
|
||||
void CGraphicsBackend_SDL_GL::GetViewportSize(int &w, int &h)
|
||||
{
|
||||
SDL_GL_GetDrawableSize(m_pWindow, &w, &h);
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::NotifyWindow()
|
||||
void CGraphicsBackend_SDL_GL::NotifyWindow()
|
||||
{
|
||||
#if SDL_MAJOR_VERSION > 2 || (SDL_MAJOR_VERSION == 2 && SDL_PATCHLEVEL >= 16)
|
||||
if(SDL_FlashWindow(m_pWindow, SDL_FlashOperation::SDL_FLASH_UNTIL_FOCUSED) != 0)
|
||||
|
@ -1268,13 +1439,18 @@ void CGraphicsBackend_SDL_OpenGL::NotifyWindow()
|
|||
#endif
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::WindowDestroyNtf(uint32_t WindowID)
|
||||
void CGraphicsBackend_SDL_GL::WindowDestroyNtf(uint32_t WindowID)
|
||||
{
|
||||
}
|
||||
|
||||
void CGraphicsBackend_SDL_OpenGL::WindowCreateNtf(uint32_t WindowID)
|
||||
void CGraphicsBackend_SDL_GL::WindowCreateNtf(uint32_t WindowID)
|
||||
{
|
||||
m_pWindow = SDL_GetWindowFromID(WindowID);
|
||||
}
|
||||
|
||||
IGraphicsBackend *CreateGraphicsBackend() { return new CGraphicsBackend_SDL_OpenGL; }
|
||||
TGLBackendReadPresentedImageData &CGraphicsBackend_SDL_GL::GetReadPresentedImageDataFuncUnsafe()
|
||||
{
|
||||
return m_ReadPresentedImageDataFunc;
|
||||
}
|
||||
|
||||
IGraphicsBackend *CreateGraphicsBackend() { return new CGraphicsBackend_SDL_GL; }
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <base/detect.h>
|
||||
|
||||
#include "engine/graphics.h"
|
||||
#include "graphics_defines.h"
|
||||
|
||||
#include "blocklist_driver.h"
|
||||
|
@ -58,6 +59,7 @@ public:
|
|||
CGraphicsBackend_Threaded();
|
||||
|
||||
virtual void RunBuffer(CCommandBuffer *pBuffer);
|
||||
virtual void RunBufferSingleThreadedUnsafe(CCommandBuffer *pBuffer);
|
||||
virtual bool IsIdle() const;
|
||||
virtual void WaitForIdle();
|
||||
|
||||
|
@ -69,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;
|
||||
|
@ -89,12 +90,6 @@ public:
|
|||
bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand);
|
||||
};
|
||||
|
||||
enum EBackendType
|
||||
{
|
||||
BACKEND_TYPE_OPENGL = 0,
|
||||
BACKEND_TYPE_OPENGL_ES,
|
||||
};
|
||||
|
||||
struct SBackendCapabilites
|
||||
{
|
||||
bool m_TileBuffering;
|
||||
|
@ -109,6 +104,9 @@ struct SBackendCapabilites
|
|||
bool m_2DArrayTexturesAsExtension;
|
||||
bool m_ShaderSupport;
|
||||
|
||||
// use quads as much as possible, even if the user config says otherwise
|
||||
bool m_TrianglesAsQuads;
|
||||
|
||||
int m_ContextMajor;
|
||||
int m_ContextMinor;
|
||||
int m_ContextPatch;
|
||||
|
@ -156,75 +154,38 @@ public:
|
|||
bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand);
|
||||
};
|
||||
|
||||
class CCommandProcessorFragment_OpenGLBase
|
||||
{
|
||||
public:
|
||||
virtual ~CCommandProcessorFragment_OpenGLBase() = default;
|
||||
virtual bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand) = 0;
|
||||
|
||||
enum
|
||||
{
|
||||
CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM_OPENGL,
|
||||
CMD_SHUTDOWN = CMD_INIT + 1,
|
||||
};
|
||||
|
||||
struct SCommand_Init : public CCommandBuffer::SCommand
|
||||
{
|
||||
SCommand_Init() :
|
||||
SCommand(CMD_INIT) {}
|
||||
class IStorage *m_pStorage;
|
||||
std::atomic<int> *m_pTextureMemoryUsage;
|
||||
SBackendCapabilites *m_pCapabilities;
|
||||
int *m_pInitError;
|
||||
|
||||
const char **m_pErrStringPtr;
|
||||
|
||||
char *m_pVendorString;
|
||||
char *m_pVersionString;
|
||||
char *m_pRendererString;
|
||||
|
||||
int m_RequestedMajor;
|
||||
int m_RequestedMinor;
|
||||
int m_RequestedPatch;
|
||||
|
||||
EBackendType m_RequestedBackend;
|
||||
|
||||
int m_GlewMajor;
|
||||
int m_GlewMinor;
|
||||
int m_GlewPatch;
|
||||
};
|
||||
|
||||
struct SCommand_Shutdown : public CCommandBuffer::SCommand
|
||||
{
|
||||
SCommand_Shutdown() :
|
||||
SCommand(CMD_SHUTDOWN) {}
|
||||
};
|
||||
};
|
||||
|
||||
// command processor impelementation, uses the fragments to combine into one processor
|
||||
class CCommandProcessor_SDL_OpenGL : public CGraphicsBackend_Threaded::ICommandProcessor
|
||||
class CCommandProcessor_SDL_GL : public CGraphicsBackend_Threaded::ICommandProcessor
|
||||
{
|
||||
CCommandProcessorFragment_OpenGLBase *m_pOpenGL;
|
||||
class CCommandProcessorFragment_GLBase *m_pGLBackend;
|
||||
CCommandProcessorFragment_SDL m_SDL;
|
||||
CCommandProcessorFragment_General m_General;
|
||||
|
||||
EBackendType m_BackendType;
|
||||
|
||||
public:
|
||||
CCommandProcessor_SDL_OpenGL(EBackendType BackendType, int OpenGLMajor, int OpenGLMinor, int OpenGLPatch);
|
||||
virtual ~CCommandProcessor_SDL_OpenGL();
|
||||
CCommandProcessor_SDL_GL(EBackendType BackendType, int GLMajor, int GLMinor, int GLPatch);
|
||||
virtual ~CCommandProcessor_SDL_GL();
|
||||
virtual void RunBuffer(CCommandBuffer *pBuffer);
|
||||
};
|
||||
|
||||
static constexpr size_t gs_GPUInfoStringSize = 256;
|
||||
|
||||
// graphics backend implemented with SDL and OpenGL
|
||||
class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded
|
||||
// graphics backend implemented with SDL and the graphics library @see EBackendType
|
||||
class CGraphicsBackend_SDL_GL : public CGraphicsBackend_Threaded
|
||||
{
|
||||
SDL_Window *m_pWindow = NULL;
|
||||
SDL_GLContext m_GLContext;
|
||||
ICommandProcessor *m_pProcessor;
|
||||
std::atomic<int> m_TextureMemoryUsage;
|
||||
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};
|
||||
std::atomic<uint64_t> m_StagingMemoryUsage{0};
|
||||
|
||||
TTWGraphicsGPUList m_GPUList;
|
||||
|
||||
TGLBackendReadPresentedImageData m_ReadPresentedImageDataFunc;
|
||||
|
||||
int m_NumScreens;
|
||||
|
||||
SBackendCapabilites m_Capabilites;
|
||||
|
@ -233,8 +194,7 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded
|
|||
char m_aVersionString[gs_GPUInfoStringSize] = {};
|
||||
char m_aRendererString[gs_GPUInfoStringSize] = {};
|
||||
|
||||
bool m_UseNewOpenGL;
|
||||
EBackendType m_BackendType;
|
||||
EBackendType m_BackendType = BACKEND_TYPE_AUTO;
|
||||
|
||||
char m_aErrorString[256];
|
||||
|
||||
|
@ -242,11 +202,16 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded
|
|||
static void ClampDriverVersion(EBackendType BackendType);
|
||||
|
||||
public:
|
||||
CGraphicsBackend_SDL_OpenGL();
|
||||
CGraphicsBackend_SDL_GL();
|
||||
virtual int Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int *pRefreshRate, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, class IStorage *pStorage);
|
||||
virtual int Shutdown();
|
||||
|
||||
virtual int MemoryUsage() const;
|
||||
virtual uint64_t TextureMemoryUsage() const;
|
||||
virtual uint64_t BufferMemoryUsage() const;
|
||||
virtual uint64_t StreamedMemoryUsage() const;
|
||||
virtual uint64_t StagingMemoryUsage() const;
|
||||
|
||||
virtual const TTWGraphicsGPUList &GetGPUs() const;
|
||||
|
||||
virtual int GetNumScreens() const { return m_NumScreens; }
|
||||
|
||||
|
@ -269,9 +234,9 @@ 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 IsNewOpenGL() { return m_UseNewOpenGL; }
|
||||
virtual bool UseTrianglesAsQuad() { return m_Capabilites.m_TrianglesAsQuads; }
|
||||
virtual bool HasTileBuffering() { return m_Capabilites.m_TileBuffering; }
|
||||
virtual bool HasQuadBuffering() { return m_Capabilites.m_QuadBuffering; }
|
||||
virtual bool HasTextBuffering() { return m_Capabilites.m_TextBuffering; }
|
||||
|
@ -301,6 +266,8 @@ public:
|
|||
return m_aRendererString;
|
||||
}
|
||||
|
||||
virtual TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe();
|
||||
|
||||
static bool IsModernAPI(EBackendType BackendType);
|
||||
};
|
||||
|
||||
|
|
|
@ -1046,9 +1046,12 @@ void CClient::DebugRender()
|
|||
total = 42
|
||||
*/
|
||||
FrameTimeAvg = FrameTimeAvg * 0.9f + m_RenderFrameTime * 0.1f;
|
||||
str_format(aBuffer, sizeof(aBuffer), "ticks: %8d %8d gfxmem: %dk fps: %3d",
|
||||
str_format(aBuffer, sizeof(aBuffer), "ticks: %8d %8d gfx mem(tex/buff/stream/staging): (%" PRIu64 "k/%" PRIu64 "k/%" PRIu64 "k/%" PRIu64 "k) fps: %3d",
|
||||
m_CurGameTick[g_Config.m_ClDummy], m_PredTick[g_Config.m_ClDummy],
|
||||
Graphics()->MemoryUsage() / 1024,
|
||||
(Graphics()->TextureMemoryUsage() / 1024),
|
||||
(Graphics()->BufferMemoryUsage() / 1024),
|
||||
(Graphics()->StreamedMemoryUsage() / 1024),
|
||||
(Graphics()->StagingMemoryUsage() / 1024),
|
||||
(int)(1.0f / FrameTimeAvg + 0.5f));
|
||||
Graphics()->QuadsText(2, 2, 16, aBuffer);
|
||||
|
||||
|
@ -2482,10 +2485,8 @@ void CClient::Update()
|
|||
#if defined(CONF_VIDEORECORDER)
|
||||
if(m_DemoPlayer.IsPlaying() && IVideo::Current())
|
||||
{
|
||||
if(IVideo::Current()->FrameRendered())
|
||||
IVideo::Current()->NextVideoFrame();
|
||||
if(IVideo::Current()->AudioFrameRendered())
|
||||
IVideo::Current()->NextAudioFrameTimeline();
|
||||
IVideo::Current()->NextVideoFrame();
|
||||
IVideo::Current()->NextAudioFrameTimeline(Sound()->GetSoundMixFunc());
|
||||
}
|
||||
else if(m_ButtonRender)
|
||||
Disconnect();
|
||||
|
@ -3096,9 +3097,20 @@ void CClient::Run()
|
|||
|
||||
bool AsyncRenderOld = g_Config.m_GfxAsyncRenderOld;
|
||||
|
||||
int GfxRefreshRate = g_Config.m_GfxRefreshRate;
|
||||
|
||||
#if defined(CONF_VIDEORECORDER)
|
||||
// keep rendering synced
|
||||
if(IVideo::Current())
|
||||
{
|
||||
AsyncRenderOld = false;
|
||||
GfxRefreshRate = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(IsRenderActive &&
|
||||
(!AsyncRenderOld || m_pGraphics->IsIdle()) &&
|
||||
(!g_Config.m_GfxRefreshRate || (time_freq() / (int64_t)g_Config.m_GfxRefreshRate) <= Now - LastRenderTime))
|
||||
(!GfxRefreshRate || (time_freq() / (int64_t)g_Config.m_GfxRefreshRate) <= Now - LastRenderTime))
|
||||
{
|
||||
m_RenderFrames++;
|
||||
|
||||
|
@ -3426,7 +3438,12 @@ void CClient::Con_StartVideo(IConsole::IResult *pResult, void *pUserData)
|
|||
|
||||
if(!IVideo::Current())
|
||||
{
|
||||
new CVideo((CGraphics_Threaded *)pSelf->m_pGraphics, pSelf->Storage(), pSelf->m_pConsole, pSelf->Graphics()->ScreenWidth(), pSelf->Graphics()->ScreenHeight(), "");
|
||||
// wait for idle, so there is no data race
|
||||
pSelf->Graphics()->WaitForIdle();
|
||||
// pause the sound device while creating the video instance
|
||||
pSelf->Sound()->PauseAudioDevice();
|
||||
new CVideo((CGraphics_Threaded *)pSelf->m_pGraphics, pSelf->Sound(), pSelf->Storage(), pSelf->m_pConsole, pSelf->Graphics()->ScreenWidth(), pSelf->Graphics()->ScreenHeight(), "");
|
||||
pSelf->Sound()->UnpauseAudioDevice();
|
||||
IVideo::Current()->Start();
|
||||
bool paused = pSelf->m_DemoPlayer.Info()->m_Info.m_Paused;
|
||||
if(paused)
|
||||
|
@ -3446,7 +3463,12 @@ void CClient::StartVideo(IConsole::IResult *pResult, void *pUserData, const char
|
|||
pSelf->m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "demo_render", pVideoName);
|
||||
if(!IVideo::Current())
|
||||
{
|
||||
new CVideo((CGraphics_Threaded *)pSelf->m_pGraphics, pSelf->Storage(), pSelf->m_pConsole, pSelf->Graphics()->ScreenWidth(), pSelf->Graphics()->ScreenHeight(), pVideoName);
|
||||
// wait for idle, so there is no data race
|
||||
pSelf->Graphics()->WaitForIdle();
|
||||
// pause the sound device while creating the video instance
|
||||
pSelf->Sound()->PauseAudioDevice();
|
||||
new CVideo((CGraphics_Threaded *)pSelf->m_pGraphics, pSelf->Sound(), pSelf->Storage(), pSelf->m_pConsole, pSelf->Graphics()->ScreenWidth(), pSelf->Graphics()->ScreenHeight(), pVideoName);
|
||||
pSelf->Sound()->UnpauseAudioDevice();
|
||||
IVideo::Current()->Start();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -73,24 +73,6 @@ void CGraphics_Threaded::FlushVertices(bool KeepVertices)
|
|||
}
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::FlushTextVertices(int TextureSize, int TextTextureIndex, int TextOutlineTextureIndex, float *pOutlineTextColor)
|
||||
{
|
||||
CCommandBuffer::SCommand_RenderTextStream Cmd;
|
||||
int PrimType, PrimCount, NumVerts;
|
||||
size_t VertSize = sizeof(CCommandBuffer::SVertex);
|
||||
|
||||
Cmd.m_TextureSize = TextureSize;
|
||||
Cmd.m_TextTextureIndex = TextTextureIndex;
|
||||
Cmd.m_TextOutlineTextureIndex = TextOutlineTextureIndex;
|
||||
mem_copy(Cmd.m_aTextOutlineColor, pOutlineTextColor, sizeof(Cmd.m_aTextOutlineColor));
|
||||
|
||||
FlushVerticesImpl(false, PrimType, PrimCount, NumVerts, Cmd, VertSize);
|
||||
if(Cmd.m_pVertices != NULL)
|
||||
{
|
||||
mem_copy(Cmd.m_pVertices, m_aVertices, VertSize * NumVerts);
|
||||
}
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::FlushVerticesTex3D()
|
||||
{
|
||||
CCommandBuffer::SCommand_RenderTex3D Cmd;
|
||||
|
@ -209,9 +191,29 @@ void CGraphics_Threaded::WrapClamp()
|
|||
m_State.m_WrapMode = CCommandBuffer::WRAP_CLAMP;
|
||||
}
|
||||
|
||||
int CGraphics_Threaded::MemoryUsage() const
|
||||
uint64_t CGraphics_Threaded::TextureMemoryUsage() const
|
||||
{
|
||||
return m_pBackend->MemoryUsage();
|
||||
return m_pBackend->TextureMemoryUsage();
|
||||
}
|
||||
|
||||
uint64_t CGraphics_Threaded::BufferMemoryUsage() const
|
||||
{
|
||||
return m_pBackend->BufferMemoryUsage();
|
||||
}
|
||||
|
||||
uint64_t CGraphics_Threaded::StreamedMemoryUsage() const
|
||||
{
|
||||
return m_pBackend->StreamedMemoryUsage();
|
||||
}
|
||||
|
||||
uint64_t CGraphics_Threaded::StagingMemoryUsage() const
|
||||
{
|
||||
return m_pBackend->StagingMemoryUsage();
|
||||
}
|
||||
|
||||
const TTWGraphicsGPUList &CGraphics_Threaded::GetGPUs() const
|
||||
{
|
||||
return m_pBackend->GetGPUs();
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY)
|
||||
|
@ -284,27 +286,52 @@ int CGraphics_Threaded::UnloadTexture(CTextureHandle *pIndex)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ImageFormatToTexFormat(int Format)
|
||||
{
|
||||
if(Format == CImageInfo::FORMAT_RGB)
|
||||
return CCommandBuffer::TEXFORMAT_RGB;
|
||||
if(Format == CImageInfo::FORMAT_RGBA)
|
||||
return CCommandBuffer::TEXFORMAT_RGBA;
|
||||
if(Format == CImageInfo::FORMAT_ALPHA)
|
||||
return CCommandBuffer::TEXFORMAT_ALPHA;
|
||||
return CCommandBuffer::TEXFORMAT_RGBA;
|
||||
}
|
||||
|
||||
static int ImageFormatToPixelSize(int Format)
|
||||
{
|
||||
switch(Format)
|
||||
{
|
||||
case CImageInfo::FORMAT_RGB: return 3;
|
||||
case CImageInfo::FORMAT_ALPHA: return 1;
|
||||
case CImageInfo::FORMAT_SINGLE_COMPONENT: return 1;
|
||||
default: return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ConvertToRGBA(uint8_t *pDest, const uint8_t *pSrc, size_t SrcWidth, size_t SrcHeight, int SrcFormat)
|
||||
{
|
||||
if(SrcFormat == CImageInfo::FORMAT_RGBA)
|
||||
{
|
||||
mem_copy(pDest, pSrc, SrcWidth * SrcHeight * 4);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t SrcChannelCount = ImageFormatToPixelSize(SrcFormat);
|
||||
size_t DstChannelCount = 4;
|
||||
for(size_t Y = 0; Y < SrcHeight; ++Y)
|
||||
{
|
||||
for(size_t X = 0; X < SrcHeight; ++X)
|
||||
{
|
||||
size_t ImgOffsetSrc = (Y * SrcWidth * SrcChannelCount) + (X * SrcChannelCount);
|
||||
size_t ImgOffsetDest = (Y * SrcWidth * DstChannelCount) + (X * DstChannelCount);
|
||||
size_t CopySize = SrcChannelCount;
|
||||
if(SrcChannelCount == 3)
|
||||
{
|
||||
mem_copy(&pDest[ImgOffsetDest], &pSrc[ImgOffsetSrc], CopySize);
|
||||
pDest[ImgOffsetDest + 3] = 255;
|
||||
}
|
||||
else if(SrcChannelCount == 1)
|
||||
{
|
||||
pDest[ImgOffsetDest + 0] = 255;
|
||||
pDest[ImgOffsetDest + 1] = 255;
|
||||
pDest[ImgOffsetDest + 2] = 255;
|
||||
pDest[ImgOffsetDest + 3] = pSrc[ImgOffsetSrc];
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int CGraphics_Threaded::LoadTextureRawSub(CTextureHandle TextureID, int x, int y, int Width, int Height, int Format, const void *pData)
|
||||
{
|
||||
CCommandBuffer::SCommand_Texture_Update Cmd;
|
||||
|
@ -313,14 +340,14 @@ int CGraphics_Threaded::LoadTextureRawSub(CTextureHandle TextureID, int x, int y
|
|||
Cmd.m_Y = y;
|
||||
Cmd.m_Width = Width;
|
||||
Cmd.m_Height = Height;
|
||||
Cmd.m_Format = ImageFormatToTexFormat(Format);
|
||||
Cmd.m_Format = CCommandBuffer::TEXFORMAT_RGBA;
|
||||
|
||||
// calculate memory usage
|
||||
int MemSize = Width * Height * ImageFormatToPixelSize(Format);
|
||||
int MemSize = Width * Height * 4;
|
||||
|
||||
// copy texture data
|
||||
void *pTmpData = malloc(MemSize);
|
||||
mem_copy(pTmpData, pData, MemSize);
|
||||
ConvertToRGBA((uint8_t *)pTmpData, (const uint8_t *)pData, Width, Height, Format);
|
||||
Cmd.m_pData = pTmpData;
|
||||
|
||||
AddCmd(
|
||||
|
@ -365,7 +392,7 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadSpriteTexture(CImageInfo &From
|
|||
|
||||
bool CGraphics_Threaded::IsImageSubFullyTransparent(CImageInfo &FromImageInfo, int x, int y, int w, int h)
|
||||
{
|
||||
if(FromImageInfo.m_Format == CImageInfo::FORMAT_ALPHA || FromImageInfo.m_Format == CImageInfo::FORMAT_RGBA)
|
||||
if(FromImageInfo.m_Format == CImageInfo::FORMAT_SINGLE_COMPONENT || FromImageInfo.m_Format == CImageInfo::FORMAT_RGBA)
|
||||
{
|
||||
uint8_t *pImgData = (uint8_t *)FromImageInfo.m_pData;
|
||||
int bpp = ImageFormatToPixelSize(FromImageInfo.m_Format);
|
||||
|
@ -445,9 +472,9 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Heig
|
|||
Cmd.m_Slot = Tex;
|
||||
Cmd.m_Width = Width;
|
||||
Cmd.m_Height = Height;
|
||||
Cmd.m_PixelSize = ImageFormatToPixelSize(Format);
|
||||
Cmd.m_Format = ImageFormatToTexFormat(Format);
|
||||
Cmd.m_StoreFormat = ImageFormatToTexFormat(StoreFormat);
|
||||
Cmd.m_PixelSize = 4;
|
||||
Cmd.m_Format = CCommandBuffer::TEXFORMAT_RGBA;
|
||||
Cmd.m_StoreFormat = CCommandBuffer::TEXFORMAT_RGBA;
|
||||
|
||||
// flags
|
||||
Cmd.m_Flags = 0;
|
||||
|
@ -467,7 +494,10 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Heig
|
|||
// copy texture data
|
||||
int MemSize = Width * Height * Cmd.m_PixelSize;
|
||||
void *pTmpData = malloc(MemSize);
|
||||
mem_copy(pTmpData, pData, 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 RGBA", pTexName);
|
||||
}
|
||||
Cmd.m_pData = pTmpData;
|
||||
|
||||
AddCmd(
|
||||
|
@ -500,6 +530,103 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTexture(const char *pFilename,
|
|||
return m_InvalidTexture;
|
||||
}
|
||||
|
||||
bool CGraphics_Threaded::LoadTextTextures(int Width, int Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, void *pTextData, void *pTextOutlineData)
|
||||
{
|
||||
if(Width == 0 || Height == 0)
|
||||
return false;
|
||||
|
||||
// grab texture
|
||||
int Tex = m_FirstFreeTexture;
|
||||
if(Tex == -1)
|
||||
{
|
||||
size_t CurSize = m_TextureIndices.size();
|
||||
m_TextureIndices.resize(CurSize * 2);
|
||||
for(size_t i = 0; i < CurSize - 1; ++i)
|
||||
{
|
||||
m_TextureIndices[CurSize + i] = CurSize + i + 1;
|
||||
}
|
||||
m_TextureIndices.back() = -1;
|
||||
|
||||
Tex = CurSize;
|
||||
}
|
||||
m_FirstFreeTexture = m_TextureIndices[Tex];
|
||||
m_TextureIndices[Tex] = -1;
|
||||
|
||||
int Tex2 = m_FirstFreeTexture;
|
||||
if(Tex2 == -1)
|
||||
{
|
||||
size_t CurSize = m_TextureIndices.size();
|
||||
m_TextureIndices.resize(CurSize * 2);
|
||||
for(size_t i = 0; i < CurSize - 1; ++i)
|
||||
{
|
||||
m_TextureIndices[CurSize + i] = CurSize + i + 1;
|
||||
}
|
||||
m_TextureIndices.back() = -1;
|
||||
|
||||
Tex2 = CurSize;
|
||||
}
|
||||
m_FirstFreeTexture = m_TextureIndices[Tex2];
|
||||
m_TextureIndices[Tex2] = -1;
|
||||
|
||||
CCommandBuffer::SCommand_TextTextures_Create Cmd;
|
||||
Cmd.m_Slot = Tex;
|
||||
Cmd.m_SlotOutline = Tex2;
|
||||
Cmd.m_Width = Width;
|
||||
Cmd.m_Height = Height;
|
||||
|
||||
Cmd.m_pTextData = pTextData;
|
||||
Cmd.m_pTextOutlineData = pTextOutlineData;
|
||||
|
||||
AddCmd(
|
||||
Cmd, [] { return true; }, "failed to load text textures.");
|
||||
|
||||
TextTexture = CreateTextureHandle(Tex);
|
||||
TextOutlineTexture = CreateTextureHandle(Tex2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGraphics_Threaded::UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture)
|
||||
{
|
||||
CCommandBuffer::SCommand_TextTextures_Destroy Cmd;
|
||||
Cmd.m_Slot = TextTexture.Id();
|
||||
Cmd.m_SlotOutline = TextOutlineTexture.Id();
|
||||
AddCmd(
|
||||
Cmd, [] { return true; }, "failed to unload text textures.");
|
||||
|
||||
m_TextureIndices[TextTexture.Id()] = m_FirstFreeTexture;
|
||||
m_FirstFreeTexture = TextTexture.Id();
|
||||
|
||||
m_TextureIndices[TextOutlineTexture.Id()] = m_FirstFreeTexture;
|
||||
m_FirstFreeTexture = TextOutlineTexture.Id();
|
||||
|
||||
TextTexture.Invalidate();
|
||||
TextOutlineTexture.Invalidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGraphics_Threaded::UpdateTextTexture(CTextureHandle TextureID, int x, int y, int Width, int Height, const void *pData)
|
||||
{
|
||||
CCommandBuffer::SCommand_TextTexture_Update Cmd;
|
||||
Cmd.m_Slot = TextureID.Id();
|
||||
Cmd.m_X = x;
|
||||
Cmd.m_Y = y;
|
||||
Cmd.m_Width = Width;
|
||||
Cmd.m_Height = Height;
|
||||
|
||||
// calculate memory usage
|
||||
int MemSize = Width * Height;
|
||||
|
||||
// copy texture data
|
||||
void *pTmpData = malloc(MemSize);
|
||||
mem_copy(pTmpData, pData, MemSize);
|
||||
Cmd.m_pData = pTmpData;
|
||||
|
||||
AddCmd(
|
||||
Cmd, [] { return true; }, "failed to update text texture.");
|
||||
return true;
|
||||
}
|
||||
|
||||
int CGraphics_Threaded::LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType)
|
||||
{
|
||||
char aCompleteFilename[IO_MAX_PATH_LENGTH];
|
||||
|
@ -592,7 +719,7 @@ bool CGraphics_Threaded::CheckImageDivisibility(const char *pFileName, CImageInf
|
|||
}
|
||||
|
||||
int ColorChannelCount = 4;
|
||||
if(Img.m_Format == CImageInfo::FORMAT_ALPHA)
|
||||
if(Img.m_Format == CImageInfo::FORMAT_SINGLE_COMPONENT)
|
||||
ColorChannelCount = 1;
|
||||
else if(Img.m_Format == CImageInfo::FORMAT_RGB)
|
||||
ColorChannelCount = 3;
|
||||
|
@ -612,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];
|
||||
|
@ -660,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.");
|
||||
|
||||
|
@ -699,6 +829,8 @@ void CGraphics_Threaded::ScreenshotDirect()
|
|||
|
||||
free(Image.m_pData);
|
||||
}
|
||||
|
||||
return DidSwap;
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::TextureSet(CTextureHandle TextureID)
|
||||
|
@ -707,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.");
|
||||
}
|
||||
|
@ -735,18 +868,6 @@ void CGraphics_Threaded::QuadsEnd()
|
|||
m_Drawing = 0;
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::TextQuadsBegin()
|
||||
{
|
||||
QuadsBegin();
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::TextQuadsEnd(int TextureSize, int TextTextureIndex, int TextOutlineTextureIndex, float *pOutlineTextColor)
|
||||
{
|
||||
dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->TextQuadsEnd without begin");
|
||||
FlushTextVertices(TextureSize, TextTextureIndex, TextOutlineTextureIndex, pOutlineTextColor);
|
||||
m_Drawing = 0;
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::QuadsTex3DBegin()
|
||||
{
|
||||
QuadsBegin();
|
||||
|
@ -876,7 +997,7 @@ void CGraphics_Threaded::ChangeColorOfCurrentQuadVertices(float r, float g, floa
|
|||
|
||||
void CGraphics_Threaded::ChangeColorOfQuadVertices(int QuadOffset, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
if(g_Config.m_GfxQuadAsTriangle && !m_IsNewOpenGL)
|
||||
if(g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad)
|
||||
{
|
||||
m_aVertices[QuadOffset * 6].m_Color.r = r;
|
||||
m_aVertices[QuadOffset * 6].m_Color.g = g;
|
||||
|
@ -981,7 +1102,7 @@ void CGraphics_Threaded::QuadsTex3DDrawTL(const CQuadItem *pArray, int Num)
|
|||
int CurNumVert = m_NumVertices;
|
||||
|
||||
int VertNum = 0;
|
||||
if(g_Config.m_GfxQuadAsTriangle && !m_IsNewOpenGL)
|
||||
if(g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad)
|
||||
{
|
||||
VertNum = 6;
|
||||
}
|
||||
|
@ -1008,7 +1129,7 @@ void CGraphics_Threaded::QuadsDrawFreeform(const CFreeformItem *pArray, int Num)
|
|||
{
|
||||
dbg_assert(m_Drawing == DRAWING_QUADS || m_Drawing == DRAWING_TRIANGLES, "called Graphics()->QuadsDrawFreeform without begin");
|
||||
|
||||
if((g_Config.m_GfxQuadAsTriangle && !m_IsNewOpenGL) || m_Drawing == DRAWING_TRIANGLES)
|
||||
if((g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad) || m_Drawing == DRAWING_TRIANGLES)
|
||||
{
|
||||
for(int i = 0; i < Num; ++i)
|
||||
{
|
||||
|
@ -1103,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
|
||||
// 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");
|
||||
|
@ -1129,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"))
|
||||
|
@ -1148,10 +1269,11 @@ 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);
|
||||
|
||||
//todo max indices group check!!
|
||||
m_pCommandBuffer->AddRenderCalls(NumIndicesOffset);
|
||||
// todo max indices group check!!
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::RenderBorderTiles(int BufferContainerIndex, float *pColor, char *pIndexBufferOffset, float *pOffset, float *pDir, int JumpIndex, unsigned int DrawNum)
|
||||
|
@ -1179,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)
|
||||
|
@ -1206,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)
|
||||
|
@ -1213,7 +1339,7 @@ void CGraphics_Threaded::RenderQuadLayer(int BufferContainerIndex, SQuadRenderIn
|
|||
if(QuadNum == 0)
|
||||
return;
|
||||
|
||||
//add the VertexArrays and draw
|
||||
// add the VertexArrays and draw
|
||||
CCommandBuffer::SCommand_RenderQuadLayer Cmd;
|
||||
Cmd.m_State = m_State;
|
||||
Cmd.m_QuadNum = QuadNum;
|
||||
|
@ -1241,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)
|
||||
|
@ -1263,6 +1391,8 @@ void CGraphics_Threaded::RenderText(int BufferContainerIndex, int TextQuadNum, i
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pCommandBuffer->AddRenderCalls(1);
|
||||
}
|
||||
|
||||
int CGraphics_Threaded::CreateQuadContainer(bool AutomaticUpload)
|
||||
|
@ -1299,18 +1429,19 @@ void CGraphics_Threaded::QuadContainerUpload(int ContainerIndex)
|
|||
if(Container.m_QuadBufferObjectIndex == -1)
|
||||
{
|
||||
size_t UploadDataSize = Container.m_Quads.size() * sizeof(SQuadContainer::SQuad);
|
||||
Container.m_QuadBufferObjectIndex = CreateBufferObject(UploadDataSize, &Container.m_Quads[0]);
|
||||
Container.m_QuadBufferObjectIndex = CreateBufferObject(UploadDataSize, &Container.m_Quads[0], 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t UploadDataSize = Container.m_Quads.size() * sizeof(SQuadContainer::SQuad);
|
||||
RecreateBufferObject(Container.m_QuadBufferObjectIndex, UploadDataSize, &Container.m_Quads[0]);
|
||||
RecreateBufferObject(Container.m_QuadBufferObjectIndex, UploadDataSize, &Container.m_Quads[0], 0);
|
||||
}
|
||||
|
||||
if(Container.m_QuadBufferContainerIndex == -1)
|
||||
{
|
||||
SBufferContainerInfo Info;
|
||||
Info.m_Stride = sizeof(CCommandBuffer::SVertex);
|
||||
Info.m_VertBufferBindingIndex = Container.m_QuadBufferObjectIndex;
|
||||
|
||||
Info.m_Attributes.emplace_back();
|
||||
SBufferContainerInfo::SAttribute *pAttr = &Info.m_Attributes.back();
|
||||
|
@ -1319,7 +1450,6 @@ void CGraphics_Threaded::QuadContainerUpload(int ContainerIndex)
|
|||
pAttr->m_Normalized = false;
|
||||
pAttr->m_pOffset = 0;
|
||||
pAttr->m_Type = GRAPHICS_TYPE_FLOAT;
|
||||
pAttr->m_VertBufferBindingIndex = Container.m_QuadBufferObjectIndex;
|
||||
Info.m_Attributes.emplace_back();
|
||||
pAttr = &Info.m_Attributes.back();
|
||||
pAttr->m_DataTypeCount = 2;
|
||||
|
@ -1327,7 +1457,6 @@ void CGraphics_Threaded::QuadContainerUpload(int ContainerIndex)
|
|||
pAttr->m_Normalized = false;
|
||||
pAttr->m_pOffset = (void *)(sizeof(float) * 2);
|
||||
pAttr->m_Type = GRAPHICS_TYPE_FLOAT;
|
||||
pAttr->m_VertBufferBindingIndex = Container.m_QuadBufferObjectIndex;
|
||||
Info.m_Attributes.emplace_back();
|
||||
pAttr = &Info.m_Attributes.back();
|
||||
pAttr->m_DataTypeCount = 4;
|
||||
|
@ -1335,7 +1464,6 @@ void CGraphics_Threaded::QuadContainerUpload(int ContainerIndex)
|
|||
pAttr->m_Normalized = true;
|
||||
pAttr->m_pOffset = (void *)(sizeof(float) * 2 + sizeof(float) * 2);
|
||||
pAttr->m_Type = GRAPHICS_TYPE_UNSIGNED_BYTE;
|
||||
pAttr->m_VertBufferBindingIndex = Container.m_QuadBufferObjectIndex;
|
||||
|
||||
Container.m_QuadBufferContainerIndex = CreateBufferContainer(&Info);
|
||||
}
|
||||
|
@ -1481,6 +1609,8 @@ void CGraphics_Threaded::RenderQuadContainer(int ContainerIndex, int QuadOffset,
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pCommandBuffer->AddRenderCalls(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1558,6 +1688,8 @@ void CGraphics_Threaded::RenderQuadContainerEx(int ContainerIndex, int QuadOffse
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pCommandBuffer->AddRenderCalls(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1702,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
|
||||
|
@ -1732,7 +1867,7 @@ void *CGraphics_Threaded::AllocCommandBufferData(unsigned AllocSize)
|
|||
return pData;
|
||||
}
|
||||
|
||||
int CGraphics_Threaded::CreateBufferObject(size_t UploadDataSize, void *pUploadData, bool IsMovedPointer)
|
||||
int CGraphics_Threaded::CreateBufferObject(size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer)
|
||||
{
|
||||
int Index = -1;
|
||||
if(m_FirstFreeBufferObjectIndex == -1)
|
||||
|
@ -1751,6 +1886,7 @@ int CGraphics_Threaded::CreateBufferObject(size_t UploadDataSize, void *pUploadD
|
|||
Cmd.m_BufferIndex = Index;
|
||||
Cmd.m_DataSize = UploadDataSize;
|
||||
Cmd.m_DeletePointer = IsMovedPointer;
|
||||
Cmd.m_Flags = CreateFlags;
|
||||
|
||||
if(IsMovedPointer)
|
||||
{
|
||||
|
@ -1803,7 +1939,7 @@ int CGraphics_Threaded::CreateBufferObject(size_t UploadDataSize, void *pUploadD
|
|||
{
|
||||
size_t UpdateSize = (UploadDataSize > CMD_BUFFER_DATA_BUFFER_SIZE ? CMD_BUFFER_DATA_BUFFER_SIZE : UploadDataSize);
|
||||
|
||||
UpdateBufferObject(Index, UpdateSize, (((char *)pUploadData) + UploadDataOffset), (void *)UploadDataOffset);
|
||||
UpdateBufferObjectInternal(Index, UpdateSize, (((char *)pUploadData) + UploadDataOffset), (void *)UploadDataOffset);
|
||||
|
||||
UploadDataOffset += UpdateSize;
|
||||
UploadDataSize -= UpdateSize;
|
||||
|
@ -1814,12 +1950,13 @@ int CGraphics_Threaded::CreateBufferObject(size_t UploadDataSize, void *pUploadD
|
|||
return Index;
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, bool IsMovedPointer)
|
||||
void CGraphics_Threaded::RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer)
|
||||
{
|
||||
CCommandBuffer::SCommand_RecreateBufferObject Cmd;
|
||||
Cmd.m_BufferIndex = BufferIndex;
|
||||
Cmd.m_DataSize = UploadDataSize;
|
||||
Cmd.m_DeletePointer = IsMovedPointer;
|
||||
Cmd.m_Flags = CreateFlags;
|
||||
|
||||
if(IsMovedPointer)
|
||||
{
|
||||
|
@ -1872,7 +2009,7 @@ void CGraphics_Threaded::RecreateBufferObject(int BufferIndex, size_t UploadData
|
|||
{
|
||||
size_t UpdateSize = (UploadDataSize > CMD_BUFFER_DATA_BUFFER_SIZE ? CMD_BUFFER_DATA_BUFFER_SIZE : UploadDataSize);
|
||||
|
||||
UpdateBufferObject(BufferIndex, UpdateSize, (((char *)pUploadData) + UploadDataOffset), (void *)UploadDataOffset);
|
||||
UpdateBufferObjectInternal(BufferIndex, UpdateSize, (((char *)pUploadData) + UploadDataOffset), (void *)UploadDataOffset);
|
||||
|
||||
UploadDataOffset += UpdateSize;
|
||||
UploadDataSize -= UpdateSize;
|
||||
|
@ -1881,7 +2018,7 @@ void CGraphics_Threaded::RecreateBufferObject(int BufferIndex, size_t UploadData
|
|||
}
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::UpdateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, void *pOffset, bool IsMovedPointer)
|
||||
void CGraphics_Threaded::UpdateBufferObjectInternal(int BufferIndex, size_t UploadDataSize, void *pUploadData, void *pOffset, bool IsMovedPointer)
|
||||
{
|
||||
CCommandBuffer::SCommand_UpdateBufferObject Cmd;
|
||||
Cmd.m_BufferIndex = BufferIndex;
|
||||
|
@ -1924,7 +2061,7 @@ void CGraphics_Threaded::UpdateBufferObject(int BufferIndex, size_t UploadDataSi
|
|||
}
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::CopyBufferObject(int WriteBufferIndex, int ReadBufferIndex, size_t WriteOffset, size_t ReadOffset, size_t CopyDataSize)
|
||||
void CGraphics_Threaded::CopyBufferObjectInternal(int WriteBufferIndex, int ReadBufferIndex, size_t WriteOffset, size_t ReadOffset, size_t CopyDataSize)
|
||||
{
|
||||
CCommandBuffer::SCommand_CopyBufferObject Cmd;
|
||||
Cmd.m_WriteBufferIndex = WriteBufferIndex;
|
||||
|
@ -1978,6 +2115,7 @@ int CGraphics_Threaded::CreateBufferContainer(SBufferContainerInfo *pContainerIn
|
|||
Cmd.m_BufferContainerIndex = Index;
|
||||
Cmd.m_AttrCount = (int)pContainerInfo->m_Attributes.size();
|
||||
Cmd.m_Stride = pContainerInfo->m_Stride;
|
||||
Cmd.m_VertBufferBindingIndex = pContainerInfo->m_VertBufferBindingIndex;
|
||||
|
||||
Cmd.m_Attributes = (SBufferContainerInfo::SAttribute *)AllocCommandBufferData(Cmd.m_AttrCount * sizeof(SBufferContainerInfo::SAttribute));
|
||||
if(Cmd.m_Attributes == NULL)
|
||||
|
@ -1998,10 +2136,9 @@ int CGraphics_Threaded::CreateBufferContainer(SBufferContainerInfo *pContainerIn
|
|||
return -1;
|
||||
}
|
||||
|
||||
mem_copy(Cmd.m_Attributes, &pContainerInfo->m_Attributes[0], Cmd.m_AttrCount * sizeof(SBufferContainerInfo::SAttribute));
|
||||
mem_copy(Cmd.m_Attributes, pContainerInfo->m_Attributes.data(), Cmd.m_AttrCount * sizeof(SBufferContainerInfo::SAttribute));
|
||||
|
||||
for(auto &Attribute : pContainerInfo->m_Attributes)
|
||||
m_VertexArrayInfo[Index].m_AssociatedBufferObjectIndices.push_back(Attribute.m_VertBufferBindingIndex);
|
||||
m_VertexArrayInfo[Index].m_AssociatedBufferObjectIndex = pContainerInfo->m_VertBufferBindingIndex;
|
||||
|
||||
return Index;
|
||||
}
|
||||
|
@ -2023,36 +2160,28 @@ void CGraphics_Threaded::DeleteBufferContainer(int ContainerIndex, bool DestroyA
|
|||
if(DestroyAllBO)
|
||||
{
|
||||
// delete all associated references
|
||||
for(size_t i = 0; i < m_VertexArrayInfo[ContainerIndex].m_AssociatedBufferObjectIndices.size(); ++i)
|
||||
int BufferObjectIndex = m_VertexArrayInfo[ContainerIndex].m_AssociatedBufferObjectIndex;
|
||||
if(BufferObjectIndex != -1)
|
||||
{
|
||||
int BufferObjectIndex = m_VertexArrayInfo[ContainerIndex].m_AssociatedBufferObjectIndices[i];
|
||||
if(BufferObjectIndex != -1)
|
||||
{
|
||||
// don't delete double entries
|
||||
for(int &m_AssociatedBufferObjectIndice : m_VertexArrayInfo[ContainerIndex].m_AssociatedBufferObjectIndices)
|
||||
{
|
||||
if(BufferObjectIndex == m_AssociatedBufferObjectIndice)
|
||||
m_AssociatedBufferObjectIndice = -1;
|
||||
}
|
||||
// clear the buffer object index
|
||||
m_BufferObjectIndices[BufferObjectIndex] = m_FirstFreeBufferObjectIndex;
|
||||
m_FirstFreeBufferObjectIndex = BufferObjectIndex;
|
||||
}
|
||||
// clear the buffer object index
|
||||
m_BufferObjectIndices[BufferObjectIndex] = m_FirstFreeBufferObjectIndex;
|
||||
m_FirstFreeBufferObjectIndex = BufferObjectIndex;
|
||||
}
|
||||
}
|
||||
m_VertexArrayInfo[ContainerIndex].m_AssociatedBufferObjectIndices.clear();
|
||||
m_VertexArrayInfo[ContainerIndex].m_AssociatedBufferObjectIndex = -1;
|
||||
|
||||
// also clear the buffer object index
|
||||
m_VertexArrayInfo[ContainerIndex].m_FreeIndex = m_FirstFreeVertexArrayInfo;
|
||||
m_FirstFreeVertexArrayInfo = ContainerIndex;
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::UpdateBufferContainer(int ContainerIndex, SBufferContainerInfo *pContainerInfo)
|
||||
void CGraphics_Threaded::UpdateBufferContainerInternal(int ContainerIndex, SBufferContainerInfo *pContainerInfo)
|
||||
{
|
||||
CCommandBuffer::SCommand_UpdateBufferContainer Cmd;
|
||||
Cmd.m_BufferContainerIndex = ContainerIndex;
|
||||
Cmd.m_AttrCount = (int)pContainerInfo->m_Attributes.size();
|
||||
Cmd.m_Stride = pContainerInfo->m_Stride;
|
||||
Cmd.m_VertBufferBindingIndex = pContainerInfo->m_VertBufferBindingIndex;
|
||||
|
||||
Cmd.m_Attributes = (SBufferContainerInfo::SAttribute *)AllocCommandBufferData(Cmd.m_AttrCount * sizeof(SBufferContainerInfo::SAttribute));
|
||||
if(Cmd.m_Attributes == NULL)
|
||||
|
@ -2073,11 +2202,9 @@ void CGraphics_Threaded::UpdateBufferContainer(int ContainerIndex, SBufferContai
|
|||
return;
|
||||
}
|
||||
|
||||
mem_copy(Cmd.m_Attributes, &pContainerInfo->m_Attributes[0], Cmd.m_AttrCount * sizeof(SBufferContainerInfo::SAttribute));
|
||||
mem_copy(Cmd.m_Attributes, pContainerInfo->m_Attributes.data(), Cmd.m_AttrCount * sizeof(SBufferContainerInfo::SAttribute));
|
||||
|
||||
m_VertexArrayInfo[ContainerIndex].m_AssociatedBufferObjectIndices.clear();
|
||||
for(auto &Attribute : pContainerInfo->m_Attributes)
|
||||
m_VertexArrayInfo[ContainerIndex].m_AssociatedBufferObjectIndices.push_back(Attribute.m_VertBufferBindingIndex);
|
||||
m_VertexArrayInfo[ContainerIndex].m_AssociatedBufferObjectIndex = pContainerInfo->m_VertBufferBindingIndex;
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::IndicesNumRequiredNotify(unsigned int RequiredIndicesCount)
|
||||
|
@ -2119,17 +2246,48 @@ int CGraphics_Threaded::IssueInit()
|
|||
|
||||
int r = m_pBackend->Init("DDNet Client", &g_Config.m_GfxScreen, &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, &g_Config.m_GfxScreenRefreshRate, g_Config.m_GfxFsaaSamples, Flags, &g_Config.m_GfxDesktopWidth, &g_Config.m_GfxDesktopHeight, &m_ScreenWidth, &m_ScreenHeight, m_pStorage);
|
||||
AddBackEndWarningIfExists();
|
||||
m_IsNewOpenGL = m_pBackend->IsNewOpenGL();
|
||||
m_OpenGLTileBufferingEnabled = m_IsNewOpenGL || m_pBackend->HasTileBuffering();
|
||||
m_OpenGLQuadBufferingEnabled = m_IsNewOpenGL || m_pBackend->HasQuadBuffering();
|
||||
m_OpenGLQuadContainerBufferingEnabled = m_IsNewOpenGL || m_pBackend->HasQuadContainerBuffering();
|
||||
m_OpenGLTextBufferingEnabled = m_IsNewOpenGL || (m_OpenGLQuadContainerBufferingEnabled && m_pBackend->HasTextBuffering());
|
||||
m_OpenGLHasTextureArrays = m_IsNewOpenGL || m_pBackend->Has2DTextureArrays();
|
||||
m_GLUseTrianglesAsQuad = m_pBackend->UseTrianglesAsQuad();
|
||||
m_GLTileBufferingEnabled = m_pBackend->HasTileBuffering();
|
||||
m_GLQuadBufferingEnabled = m_pBackend->HasQuadBuffering();
|
||||
m_GLQuadContainerBufferingEnabled = m_pBackend->HasQuadContainerBuffering();
|
||||
m_GLTextBufferingEnabled = (m_GLQuadContainerBufferingEnabled && m_pBackend->HasTextBuffering());
|
||||
m_GLHasTextureArrays = m_pBackend->Has2DTextureArrays();
|
||||
m_ScreenHiDPIScale = m_ScreenWidth / (float)g_Config.m_GfxScreenWidth;
|
||||
m_ScreenRefreshRate = g_Config.m_GfxScreenRefreshRate;
|
||||
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();
|
||||
|
@ -2162,76 +2320,76 @@ int CGraphics_Threaded::InitWindow()
|
|||
return 0;
|
||||
}
|
||||
|
||||
size_t OpenGLInitTryCount = 0;
|
||||
while(ErrorCode == EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED || ErrorCode == EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED)
|
||||
size_t GLInitTryCount = 0;
|
||||
while(ErrorCode == EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_GL_CONTEXT_FAILED || ErrorCode == EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_GL_VERSION_FAILED)
|
||||
{
|
||||
if(ErrorCode == EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED)
|
||||
if(ErrorCode == EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_GL_CONTEXT_FAILED)
|
||||
{
|
||||
// try next smaller major/minor or patch version
|
||||
if(g_Config.m_GfxOpenGLMajor >= 4)
|
||||
if(g_Config.m_GfxGLMajor >= 4)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = 3;
|
||||
g_Config.m_GfxOpenGLMinor = 3;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMajor = 3;
|
||||
g_Config.m_GfxGLMinor = 3;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
else if(g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor >= 1)
|
||||
else if(g_Config.m_GfxGLMajor == 3 && g_Config.m_GfxGLMinor >= 1)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = 3;
|
||||
g_Config.m_GfxOpenGLMinor = 0;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMajor = 3;
|
||||
g_Config.m_GfxGLMinor = 0;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
else if(g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor == 0)
|
||||
else if(g_Config.m_GfxGLMajor == 3 && g_Config.m_GfxGLMinor == 0)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = 2;
|
||||
g_Config.m_GfxOpenGLMinor = 1;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMajor = 2;
|
||||
g_Config.m_GfxGLMinor = 1;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
else if(g_Config.m_GfxOpenGLMajor == 2 && g_Config.m_GfxOpenGLMinor >= 1)
|
||||
else if(g_Config.m_GfxGLMajor == 2 && g_Config.m_GfxGLMinor >= 1)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = 2;
|
||||
g_Config.m_GfxOpenGLMinor = 0;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMajor = 2;
|
||||
g_Config.m_GfxGLMinor = 0;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
else if(g_Config.m_GfxOpenGLMajor == 2 && g_Config.m_GfxOpenGLMinor == 0)
|
||||
else if(g_Config.m_GfxGLMajor == 2 && g_Config.m_GfxGLMinor == 0)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = 1;
|
||||
g_Config.m_GfxOpenGLMinor = 5;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMajor = 1;
|
||||
g_Config.m_GfxGLMinor = 5;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
else if(g_Config.m_GfxOpenGLMajor == 1 && g_Config.m_GfxOpenGLMinor == 5)
|
||||
else if(g_Config.m_GfxGLMajor == 1 && g_Config.m_GfxGLMinor == 5)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = 1;
|
||||
g_Config.m_GfxOpenGLMinor = 4;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMajor = 1;
|
||||
g_Config.m_GfxGLMinor = 4;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
else if(g_Config.m_GfxOpenGLMajor == 1 && g_Config.m_GfxOpenGLMinor == 4)
|
||||
else if(g_Config.m_GfxGLMajor == 1 && g_Config.m_GfxGLMinor == 4)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = 1;
|
||||
g_Config.m_GfxOpenGLMinor = 3;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMajor = 1;
|
||||
g_Config.m_GfxGLMinor = 3;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
else if(g_Config.m_GfxOpenGLMajor == 1 && g_Config.m_GfxOpenGLMinor == 3)
|
||||
else if(g_Config.m_GfxGLMajor == 1 && g_Config.m_GfxGLMinor == 3)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = 1;
|
||||
g_Config.m_GfxOpenGLMinor = 2;
|
||||
g_Config.m_GfxOpenGLPatch = 1;
|
||||
g_Config.m_GfxGLMajor = 1;
|
||||
g_Config.m_GfxGLMinor = 2;
|
||||
g_Config.m_GfxGLPatch = 1;
|
||||
}
|
||||
else if(g_Config.m_GfxOpenGLMajor == 1 && g_Config.m_GfxOpenGLMinor == 2)
|
||||
else if(g_Config.m_GfxGLMajor == 1 && g_Config.m_GfxGLMinor == 2)
|
||||
{
|
||||
g_Config.m_GfxOpenGLMajor = 1;
|
||||
g_Config.m_GfxOpenGLMinor = 1;
|
||||
g_Config.m_GfxOpenGLPatch = 0;
|
||||
g_Config.m_GfxGLMajor = 1;
|
||||
g_Config.m_GfxGLMinor = 1;
|
||||
g_Config.m_GfxGLPatch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// new opengl version was set by backend, try again
|
||||
// new gl version was set by backend, try again
|
||||
ErrorCode = IssueInit();
|
||||
if(ErrorCode == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(++OpenGLInitTryCount >= 9)
|
||||
if(++GLInitTryCount >= 9)
|
||||
{
|
||||
// try something else
|
||||
break;
|
||||
|
@ -2249,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;
|
||||
|
@ -2308,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;
|
||||
}
|
||||
|
||||
|
@ -2355,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;
|
||||
}
|
||||
|
@ -2370,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;
|
||||
}
|
||||
|
||||
|
@ -2406,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;
|
||||
|
||||
|
@ -2422,6 +2592,7 @@ void CGraphics_Threaded::GotResized(int w, int h, int RefreshRate)
|
|||
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"))
|
||||
|
@ -2459,6 +2630,10 @@ void CGraphics_Threaded::WindowDestroyNtf(uint32_t WindowID)
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// wait
|
||||
KickCommandBuffer();
|
||||
WaitForIdle();
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::WindowCreateNtf(uint32_t WindowID)
|
||||
|
@ -2473,6 +2648,10 @@ void CGraphics_Threaded::WindowCreateNtf(uint32_t WindowID)
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// wait
|
||||
KickCommandBuffer();
|
||||
WaitForIdle();
|
||||
}
|
||||
|
||||
int CGraphics_Threaded::WindowActive()
|
||||
|
@ -2521,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;
|
||||
|
@ -2630,6 +2811,11 @@ const char *CGraphics_Threaded::GetRendererString()
|
|||
return m_pBackend->GetRendererString();
|
||||
}
|
||||
|
||||
TGLBackendReadPresentedImageData &CGraphics_Threaded::GetReadPresentedImageDataFuncUnsafe()
|
||||
{
|
||||
return m_pBackend->GetReadPresentedImageDataFuncUnsafe();
|
||||
}
|
||||
|
||||
int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes, int Screen)
|
||||
{
|
||||
if(g_Config.m_GfxDisplayAllVideoModes)
|
||||
|
|
|
@ -60,6 +60,9 @@ class CCommandBuffer
|
|||
|
||||
public:
|
||||
CBuffer m_CmdBuffer;
|
||||
size_t m_CommandCount = 0;
|
||||
size_t m_RenderCallCount = 0;
|
||||
|
||||
CBuffer m_DataBuffer;
|
||||
|
||||
enum
|
||||
|
@ -68,15 +71,16 @@ public:
|
|||
MAX_VERTICES = 32 * 1024,
|
||||
};
|
||||
|
||||
enum
|
||||
enum ECommandBufferCMD
|
||||
{
|
||||
// commadn groups
|
||||
CMDGROUP_CORE = 0, // commands that everyone has to implement
|
||||
CMDGROUP_PLATFORM_OPENGL = 10000, // commands specific to a platform
|
||||
CMDGROUP_PLATFORM_GL = 10000, // commands specific to a platform
|
||||
CMDGROUP_PLATFORM_SDL = 20000,
|
||||
|
||||
//
|
||||
CMD_NOP = CMDGROUP_CORE,
|
||||
CMD_FIRST = CMDGROUP_CORE,
|
||||
CMD_NOP = CMD_FIRST,
|
||||
|
||||
//
|
||||
CMD_RUNBUFFER,
|
||||
|
@ -88,13 +92,16 @@ public:
|
|||
CMD_TEXTURE_CREATE,
|
||||
CMD_TEXTURE_DESTROY,
|
||||
CMD_TEXTURE_UPDATE,
|
||||
CMD_TEXT_TEXTURES_CREATE,
|
||||
CMD_TEXT_TEXTURES_DESTROY,
|
||||
CMD_TEXT_TEXTURE_UPDATE,
|
||||
|
||||
// rendering
|
||||
CMD_CLEAR,
|
||||
CMD_RENDER,
|
||||
CMD_RENDER_TEX3D,
|
||||
|
||||
//opengl 2.0+ commands (some are just emulated and only exist in opengl 3.3+)
|
||||
// opengl 2.0+ commands (some are just emulated and only exist in opengl 3.3+)
|
||||
CMD_CREATE_BUFFER_OBJECT, // create vbo
|
||||
CMD_RECREATE_BUFFER_OBJECT, // recreate vbo
|
||||
CMD_UPDATE_BUFFER_OBJECT, // update vbo
|
||||
|
@ -112,7 +119,6 @@ public:
|
|||
CMD_RENDER_BORDER_TILE_LINE, // render an amount of tiles multiple times
|
||||
CMD_RENDER_QUAD_LAYER, // render a quad layer
|
||||
CMD_RENDER_TEXT, // render text
|
||||
CMD_RENDER_TEXT_STREAM, // render text stream
|
||||
CMD_RENDER_QUAD_CONTAINER, // render a quad buffer container
|
||||
CMD_RENDER_QUAD_CONTAINER_EX, // render a quad buffer container with extended parameters
|
||||
CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE, // render a quad buffer container as sprite multiple times
|
||||
|
@ -123,20 +129,20 @@ public:
|
|||
|
||||
// misc
|
||||
CMD_VSYNC,
|
||||
CMD_SCREENSHOT,
|
||||
CMD_TRY_SWAP_AND_SCREENSHOT,
|
||||
CMD_UPDATE_VIEWPORT,
|
||||
|
||||
// in Android a window that minimizes gets destroyed
|
||||
CMD_WINDOW_CREATE_NTF,
|
||||
CMD_WINDOW_DESTROY_NTF,
|
||||
|
||||
CMD_COUNT,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TEXFORMAT_INVALID = 0,
|
||||
TEXFORMAT_RGB,
|
||||
TEXFORMAT_RGBA,
|
||||
TEXFORMAT_ALPHA,
|
||||
|
||||
TEXFLAG_NOMIPMAPS = 1,
|
||||
TEXFLAG_TO_3D_TEXTURE = (1 << 3),
|
||||
|
@ -208,6 +214,7 @@ public:
|
|||
SCommand_Clear() :
|
||||
SCommand(CMD_CLEAR) {}
|
||||
SColorf m_Color;
|
||||
bool m_ForceClear;
|
||||
};
|
||||
|
||||
struct SCommand_Signal : public SCommand
|
||||
|
@ -254,6 +261,8 @@ public:
|
|||
bool m_DeletePointer;
|
||||
void *m_pUploadData;
|
||||
size_t m_DataSize;
|
||||
|
||||
int m_Flags; // @see EBufferObjectCreateFlags
|
||||
};
|
||||
|
||||
struct SCommand_RecreateBufferObject : public SCommand
|
||||
|
@ -266,6 +275,8 @@ public:
|
|||
bool m_DeletePointer;
|
||||
void *m_pUploadData;
|
||||
size_t m_DataSize;
|
||||
|
||||
int m_Flags; // @see EBufferObjectCreateFlags
|
||||
};
|
||||
|
||||
struct SCommand_UpdateBufferObject : public SCommand
|
||||
|
@ -310,6 +321,7 @@ public:
|
|||
int m_BufferContainerIndex;
|
||||
|
||||
int m_Stride;
|
||||
int m_VertBufferBindingIndex;
|
||||
|
||||
int m_AttrCount;
|
||||
SBufferContainerInfo::SAttribute *m_Attributes;
|
||||
|
@ -323,6 +335,7 @@ public:
|
|||
int m_BufferContainerIndex;
|
||||
|
||||
int m_Stride;
|
||||
int m_VertBufferBindingIndex;
|
||||
|
||||
int m_AttrCount;
|
||||
SBufferContainerInfo::SAttribute *m_Attributes;
|
||||
|
@ -350,9 +363,9 @@ public:
|
|||
SCommand_RenderTileLayer() :
|
||||
SCommand(CMD_RENDER_TILE_LAYER) {}
|
||||
SState m_State;
|
||||
SColorf m_Color; //the color of the whole tilelayer -- already envelopped
|
||||
SColorf m_Color; // the color of the whole tilelayer -- already envelopped
|
||||
|
||||
//the char offset of all indices that should be rendered, and the amount of renders
|
||||
// the char offset of all indices that should be rendered, and the amount of renders
|
||||
char **m_pIndicesOffsets;
|
||||
unsigned int *m_pDrawCount;
|
||||
|
||||
|
@ -365,7 +378,7 @@ public:
|
|||
SCommand_RenderBorderTile() :
|
||||
SCommand(CMD_RENDER_BORDER_TILE) {}
|
||||
SState m_State;
|
||||
SColorf m_Color; //the color of the whole tilelayer -- already envelopped
|
||||
SColorf m_Color; // the color of the whole tilelayer -- already envelopped
|
||||
char *m_pIndicesOffset; // you should use the command buffer data to allocate vertices for this command
|
||||
unsigned int m_DrawNum;
|
||||
int m_BufferContainerIndex;
|
||||
|
@ -380,7 +393,7 @@ public:
|
|||
SCommand_RenderBorderTileLine() :
|
||||
SCommand(CMD_RENDER_BORDER_TILE_LINE) {}
|
||||
SState m_State;
|
||||
SColorf m_Color; //the color of the whole tilelayer -- already envelopped
|
||||
SColorf m_Color; // the color of the whole tilelayer -- already envelopped
|
||||
char *m_pIndicesOffset; // you should use the command buffer data to allocate vertices for this command
|
||||
unsigned int m_IndexDrawNum;
|
||||
unsigned int m_DrawNum;
|
||||
|
@ -419,24 +432,6 @@ public:
|
|||
float m_aTextOutlineColor[4];
|
||||
};
|
||||
|
||||
struct SCommand_RenderTextStream : public SCommand
|
||||
{
|
||||
SCommand_RenderTextStream() :
|
||||
SCommand(CMD_RENDER_TEXT_STREAM) {}
|
||||
SState m_State;
|
||||
|
||||
SVertex *m_pVertices;
|
||||
unsigned m_PrimType;
|
||||
unsigned m_PrimCount;
|
||||
|
||||
int m_TextureSize;
|
||||
|
||||
int m_TextTextureIndex;
|
||||
int m_TextOutlineTextureIndex;
|
||||
|
||||
float m_aTextOutlineColor[4];
|
||||
};
|
||||
|
||||
struct SCommand_RenderQuadContainer : public SCommand
|
||||
{
|
||||
SCommand_RenderQuadContainer() :
|
||||
|
@ -484,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
|
||||
|
@ -521,6 +517,7 @@ public:
|
|||
int m_Y;
|
||||
int m_Width;
|
||||
int m_Height;
|
||||
bool m_ByResize; // resized by an resize event.. a hint to make clear that the viewport update can be deferred if wanted
|
||||
};
|
||||
|
||||
struct SCommand_Texture_Create : public SCommand
|
||||
|
@ -565,6 +562,47 @@ public:
|
|||
int m_Slot;
|
||||
};
|
||||
|
||||
struct SCommand_TextTextures_Create : public SCommand
|
||||
{
|
||||
SCommand_TextTextures_Create() :
|
||||
SCommand(CMD_TEXT_TEXTURES_CREATE) {}
|
||||
|
||||
// texture information
|
||||
int m_Slot;
|
||||
int m_SlotOutline;
|
||||
|
||||
int m_Width;
|
||||
int m_Height;
|
||||
|
||||
void *m_pTextData;
|
||||
void *m_pTextOutlineData;
|
||||
};
|
||||
|
||||
struct SCommand_TextTextures_Destroy : public SCommand
|
||||
{
|
||||
SCommand_TextTextures_Destroy() :
|
||||
SCommand(CMD_TEXT_TEXTURES_DESTROY) {}
|
||||
|
||||
// texture information
|
||||
int m_Slot;
|
||||
int m_SlotOutline;
|
||||
};
|
||||
|
||||
struct SCommand_TextTexture_Update : public SCommand
|
||||
{
|
||||
SCommand_TextTexture_Update() :
|
||||
SCommand(CMD_TEXT_TEXTURE_UPDATE) {}
|
||||
|
||||
// texture information
|
||||
int m_Slot;
|
||||
|
||||
int m_X;
|
||||
int m_Y;
|
||||
int m_Width;
|
||||
int m_Height;
|
||||
void *m_pData; // will be freed by the command processor
|
||||
};
|
||||
|
||||
struct SCommand_WindowCreateNtf : public CCommandBuffer::SCommand
|
||||
{
|
||||
SCommand_WindowCreateNtf() :
|
||||
|
@ -611,6 +649,8 @@ public:
|
|||
m_pCmdBufferHead = pCmd;
|
||||
m_pCmdBufferTail = pCmd;
|
||||
|
||||
++m_CommandCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -624,6 +664,14 @@ public:
|
|||
m_pCmdBufferHead = m_pCmdBufferTail = nullptr;
|
||||
m_CmdBuffer.Reset();
|
||||
m_DataBuffer.Reset();
|
||||
|
||||
m_CommandCount = 0;
|
||||
m_RenderCallCount = 0;
|
||||
}
|
||||
|
||||
void AddRenderCalls(size_t RenderCallCountToAdd)
|
||||
{
|
||||
m_RenderCallCount += RenderCallCountToAdd;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -631,8 +679,8 @@ enum EGraphicsBackendErrorCodes
|
|||
{
|
||||
GRAPHICS_BACKEND_ERROR_CODE_UNKNOWN = -1,
|
||||
GRAPHICS_BACKEND_ERROR_CODE_NONE = 0,
|
||||
GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED,
|
||||
GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED,
|
||||
GRAPHICS_BACKEND_ERROR_CODE_GL_CONTEXT_FAILED,
|
||||
GRAPHICS_BACKEND_ERROR_CODE_GL_VERSION_FAILED,
|
||||
GRAPHICS_BACKEND_ERROR_CODE_SDL_INIT_FAILED,
|
||||
GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_REQUEST_FAILED,
|
||||
GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_INFO_REQUEST_FAILED,
|
||||
|
@ -660,7 +708,12 @@ public:
|
|||
virtual int Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int *pRefreshRate, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, class IStorage *pStorage) = 0;
|
||||
virtual int Shutdown() = 0;
|
||||
|
||||
virtual int MemoryUsage() const = 0;
|
||||
virtual uint64_t TextureMemoryUsage() const = 0;
|
||||
virtual uint64_t BufferMemoryUsage() const = 0;
|
||||
virtual uint64_t StreamedMemoryUsage() const = 0;
|
||||
virtual uint64_t StagingMemoryUsage() const = 0;
|
||||
|
||||
virtual const TTWGraphicsGPUList &GetGPUs() const = 0;
|
||||
|
||||
virtual void GetVideoModes(CVideoMode *pModes, int MaxModes, int *pNumModes, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen) = 0;
|
||||
virtual void GetCurrentVideoMode(CVideoMode &CurMode, int HiDPIScale, int MaxWindowWidth, int MaxWindowHeight, int Screen) = 0;
|
||||
|
@ -685,13 +738,14 @@ public:
|
|||
virtual void WindowCreateNtf(uint32_t WindowID) = 0;
|
||||
|
||||
virtual void RunBuffer(CCommandBuffer *pBuffer) = 0;
|
||||
virtual void RunBufferSingleThreadedUnsafe(CCommandBuffer *pBuffer) = 0;
|
||||
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 IsNewOpenGL() { return false; }
|
||||
virtual bool UseTrianglesAsQuad() { return false; }
|
||||
virtual bool HasTileBuffering() { return false; }
|
||||
virtual bool HasQuadBuffering() { return false; }
|
||||
virtual bool HasTextBuffering() { return false; }
|
||||
|
@ -702,6 +756,9 @@ public:
|
|||
virtual const char *GetVendorString() = 0;
|
||||
virtual const char *GetVersionString() = 0;
|
||||
virtual const char *GetRendererString() = 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
|
||||
virtual TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() = 0;
|
||||
};
|
||||
|
||||
class CGraphics_Threaded : public IEngineGraphics
|
||||
|
@ -717,12 +774,12 @@ class CGraphics_Threaded : public IEngineGraphics
|
|||
|
||||
CCommandBuffer::SState m_State;
|
||||
IGraphicsBackend *m_pBackend;
|
||||
bool m_OpenGLTileBufferingEnabled;
|
||||
bool m_OpenGLQuadBufferingEnabled;
|
||||
bool m_OpenGLTextBufferingEnabled;
|
||||
bool m_OpenGLQuadContainerBufferingEnabled;
|
||||
bool m_OpenGLHasTextureArrays;
|
||||
bool m_IsNewOpenGL;
|
||||
bool m_GLTileBufferingEnabled;
|
||||
bool m_GLQuadBufferingEnabled;
|
||||
bool m_GLTextBufferingEnabled;
|
||||
bool m_GLQuadContainerBufferingEnabled;
|
||||
bool m_GLHasTextureArrays;
|
||||
bool m_GLUseTrianglesAsQuad;
|
||||
|
||||
CCommandBuffer *m_apCommandBuffers[NUM_CMDBUFFERS];
|
||||
CCommandBuffer *m_pCommandBuffer;
|
||||
|
@ -758,12 +815,16 @@ 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() :
|
||||
m_FreeIndex(-1) {}
|
||||
// keep a reference to them, so we can free their IDs
|
||||
std::vector<int> m_AssociatedBufferObjectIndices;
|
||||
// keep a reference to it, so we can free the ID
|
||||
int m_AssociatedBufferObjectIndex;
|
||||
|
||||
int m_FreeIndex;
|
||||
};
|
||||
|
@ -858,6 +919,8 @@ class CGraphics_Threaded : public IEngineGraphics
|
|||
|
||||
void AddBackEndWarningIfExists();
|
||||
|
||||
void AdjustViewport(bool SendViewportChangeToBackend);
|
||||
|
||||
int IssueInit();
|
||||
int InitWindow();
|
||||
|
||||
|
@ -874,7 +937,12 @@ public:
|
|||
void WrapNormal() override;
|
||||
void WrapClamp() override;
|
||||
|
||||
int MemoryUsage() const override;
|
||||
uint64_t TextureMemoryUsage() const override;
|
||||
uint64_t BufferMemoryUsage() const override;
|
||||
uint64_t StreamedMemoryUsage() const override;
|
||||
uint64_t StagingMemoryUsage() const override;
|
||||
|
||||
const TTWGraphicsGPUList &GetGPUs() const override;
|
||||
|
||||
void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY) override;
|
||||
void GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY) override;
|
||||
|
@ -887,6 +955,10 @@ public:
|
|||
IGraphics::CTextureHandle LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags, const char *pTexName = NULL) override;
|
||||
int LoadTextureRawSub(IGraphics::CTextureHandle TextureID, int x, int y, int Width, int Height, int Format, const void *pData) override;
|
||||
|
||||
bool LoadTextTextures(int Width, int Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, void *pTextData, void *pTextOutlineData) override;
|
||||
bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) override;
|
||||
bool UpdateTextTexture(CTextureHandle TextureID, int x, int y, int Width, int Height, const void *pData) override;
|
||||
|
||||
CTextureHandle LoadSpriteTextureImpl(CImageInfo &FromImageInfo, int x, int y, int w, int h);
|
||||
CTextureHandle LoadSpriteTexture(CImageInfo &FromImageInfo, struct CDataSprite *pSprite) override;
|
||||
CTextureHandle LoadSpriteTexture(CImageInfo &FromImageInfo, struct client_data7::CDataSprite *pSprite) override;
|
||||
|
@ -905,16 +977,14 @@ 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;
|
||||
void TextQuadsBegin() override;
|
||||
void TextQuadsEnd(int TextureSize, int TextTextureIndex, int TextOutlineTextureIndex, float *pOutlineTextColor) override;
|
||||
void QuadsTex3DBegin() override;
|
||||
void QuadsTex3DEnd() override;
|
||||
void TrianglesBegin() override;
|
||||
|
@ -956,7 +1026,7 @@ public:
|
|||
|
||||
dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsDrawTL without begin");
|
||||
|
||||
if(g_Config.m_GfxQuadAsTriangle && !m_IsNewOpenGL)
|
||||
if(g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad)
|
||||
{
|
||||
for(int i = 0; i < Num; ++i)
|
||||
{
|
||||
|
@ -1084,7 +1154,7 @@ public:
|
|||
|
||||
if(m_Drawing == DRAWING_QUADS)
|
||||
{
|
||||
if(g_Config.m_GfxQuadAsTriangle && !m_IsNewOpenGL)
|
||||
if(g_Config.m_GfxQuadAsTriangle && !m_GLUseTrianglesAsQuad)
|
||||
{
|
||||
PrimType = CCommandBuffer::PRIMTYPE_TRIANGLES;
|
||||
PrimCount = NumVerts / 3;
|
||||
|
@ -1142,29 +1212,30 @@ public:
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pCommandBuffer->AddRenderCalls(1);
|
||||
}
|
||||
|
||||
void FlushVertices(bool KeepVertices = false) override;
|
||||
void FlushTextVertices(int TextureSize, int TextTextureIndex, int TextOutlineTextureIndex, float *pOutlineTextColor) 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;
|
||||
void RenderText(int BufferContainerIndex, int TextQuadNum, int TextureSize, int TextureTextIndex, int TextureTextOutlineIndex, float *pTextColor, float *pTextoutlineColor) override;
|
||||
|
||||
// opengl 3.3 functions
|
||||
int CreateBufferObject(size_t UploadDataSize, void *pUploadData, bool IsMovedPointer = false) override;
|
||||
void RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, bool IsMovedPointer = false) override;
|
||||
void UpdateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, void *pOffset, bool IsMovedPointer = false) override;
|
||||
void CopyBufferObject(int WriteBufferIndex, int ReadBufferIndex, size_t WriteOffset, size_t ReadOffset, size_t CopyDataSize) override;
|
||||
// modern GL functions
|
||||
int CreateBufferObject(size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) override;
|
||||
void RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) override;
|
||||
void UpdateBufferObjectInternal(int BufferIndex, size_t UploadDataSize, void *pUploadData, void *pOffset, bool IsMovedPointer = false);
|
||||
void CopyBufferObjectInternal(int WriteBufferIndex, int ReadBufferIndex, size_t WriteOffset, size_t ReadOffset, size_t CopyDataSize);
|
||||
void DeleteBufferObject(int BufferIndex) override;
|
||||
|
||||
int CreateBufferContainer(SBufferContainerInfo *pContainerInfo) override;
|
||||
// destroying all buffer objects means, that all referenced VBOs are destroyed automatically, so the user does not need to save references to them
|
||||
void DeleteBufferContainer(int ContainerIndex, bool DestroyAllBO = true) override;
|
||||
void UpdateBufferContainer(int ContainerIndex, SBufferContainerInfo *pContainerInfo) override;
|
||||
void UpdateBufferContainerInternal(int ContainerIndex, SBufferContainerInfo *pContainerInfo);
|
||||
void IndicesNumRequiredNotify(unsigned int RequiredIndicesCount) override;
|
||||
|
||||
int GetNumScreens() const override;
|
||||
|
@ -1207,17 +1278,19 @@ 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_OpenGLTileBufferingEnabled; }
|
||||
bool IsQuadBufferingEnabled() override { return m_OpenGLQuadBufferingEnabled; }
|
||||
bool IsTextBufferingEnabled() override { return m_OpenGLTextBufferingEnabled; }
|
||||
bool IsQuadContainerBufferingEnabled() override { return m_OpenGLQuadContainerBufferingEnabled; }
|
||||
bool HasTextureArrays() override { return m_OpenGLHasTextureArrays; }
|
||||
bool IsTileBufferingEnabled() override { return m_GLTileBufferingEnabled; }
|
||||
bool IsQuadBufferingEnabled() override { return m_GLQuadBufferingEnabled; }
|
||||
bool IsTextBufferingEnabled() override { return m_GLTextBufferingEnabled; }
|
||||
bool IsQuadContainerBufferingEnabled() override { return m_GLQuadContainerBufferingEnabled; }
|
||||
bool HasTextureArrays() override { return m_GLHasTextureArrays; }
|
||||
|
||||
const char *GetVendorString() override;
|
||||
const char *GetVersionString() override;
|
||||
const char *GetRendererString() override;
|
||||
|
||||
TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() override;
|
||||
};
|
||||
|
||||
extern IGraphicsBackend *CreateGraphicsBackend();
|
||||
|
|
|
@ -28,7 +28,13 @@ public:
|
|||
void WrapNormal() override{};
|
||||
void WrapClamp() override{};
|
||||
|
||||
int MemoryUsage() const override { return 0; }
|
||||
uint64_t TextureMemoryUsage() const override { return 0; }
|
||||
uint64_t BufferMemoryUsage() const override { return 0; }
|
||||
uint64_t StreamedMemoryUsage() const override { return 0; }
|
||||
uint64_t StagingMemoryUsage() const override { return 0; }
|
||||
|
||||
TTWGraphicsGPUList m_FakeGPUList;
|
||||
const TTWGraphicsGPUList &GetGPUs() const override { return m_FakeGPUList; }
|
||||
|
||||
void MapScreen(float TopLeftX, float TopLeftY, float BottomRightX, float BottomRightY) override{};
|
||||
void GetScreen(float *pTopLeftX, float *pTopLeftY, float *pBottomRightX, float *pBottomRightY) override
|
||||
|
@ -47,11 +53,20 @@ public:
|
|||
IGraphics::CTextureHandle LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags, const char *pTexName = NULL) override { return CreateTextureHandle(0); }
|
||||
int LoadTextureRawSub(IGraphics::CTextureHandle TextureID, int x, int y, int Width, int Height, int Format, const void *pData) override { return 0; }
|
||||
|
||||
CTextureHandle LoadSpriteTextureImpl(CImageInfo &FromImageInfo, int x, int y, int w, int h) { return CreateTextureHandle(0); }
|
||||
CTextureHandle LoadSpriteTexture(CImageInfo &FromImageInfo, struct CDataSprite *pSprite) override { return CreateTextureHandle(0); }
|
||||
CTextureHandle LoadSpriteTexture(CImageInfo &FromImageInfo, struct client_data7::CDataSprite *pSprite) override { return CreateTextureHandle(0); }
|
||||
bool LoadTextTextures(int Width, int Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, void *pTextData, void *pTextOutlineData) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) override { return false; }
|
||||
bool UpdateTextTexture(CTextureHandle TextureID, int x, int y, int Width, int Height, const void *pData) override { return false; }
|
||||
|
||||
bool IsImageSubFullyTransparent(CImageInfo &FromImageInfo, int x, int y, int w, int h) override { return false; }
|
||||
CTextureHandle LoadSpriteTexture(CImageInfo &FromImageInfo, struct CDataSprite *pSprite) override { return CreateTextureHandle(0); };
|
||||
CTextureHandle LoadSpriteTexture(CImageInfo &FromImageInfo, struct client_data7::CDataSprite *pSprite) override { return CreateTextureHandle(0); };
|
||||
|
||||
bool IsImageSubFullyTransparent(CImageInfo &FromImageInfo, int x, int y, int w, int h) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool IsSpriteTextureFullyTransparent(CImageInfo &FromImageInfo, struct client_data7::CDataSprite *pSprite) override { return false; }
|
||||
|
||||
// simple uncompressed RGBA loaders
|
||||
|
@ -67,12 +82,10 @@ 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{};
|
||||
void TextQuadsBegin() override{};
|
||||
void TextQuadsEnd(int TextureSize, int TextTextureIndex, int TextOutlineTextureIndex, float *pOutlineTextColor) override{};
|
||||
void QuadsTex3DBegin() override{};
|
||||
void QuadsTex3DEnd() override{};
|
||||
void TrianglesBegin() override{};
|
||||
|
@ -123,26 +136,22 @@ public:
|
|||
void RenderQuadContainerAsSpriteMultiple(int ContainerIndex, int QuadOffset, int DrawCount, SRenderSpriteInfo *pRenderInfo) override{};
|
||||
|
||||
void FlushVertices(bool KeepVertices = false) override{};
|
||||
void FlushTextVertices(int TextureSize, int TextTextureIndex, int TextOutlineTextureIndex, float *pOutlineTextColor) 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{};
|
||||
void RenderText(int BufferContainerIndex, int TextQuadNum, int TextureSize, int TextureTextIndex, int TextureTextOutlineIndex, float *pTextColor, float *pTextoutlineColor) override{};
|
||||
|
||||
// opengl 3.3 functions
|
||||
int CreateBufferObject(size_t UploadDataSize, void *pUploadData, bool IsMovedPointer = false) override { return 0; }
|
||||
void RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, bool IsMovedPointer = false) override{};
|
||||
void UpdateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, void *pOffset, bool IsMovedPointer = false) override{};
|
||||
void CopyBufferObject(int WriteBufferIndex, int ReadBufferIndex, size_t WriteOffset, size_t ReadOffset, size_t CopyDataSize) override{};
|
||||
// modern GL functions
|
||||
int CreateBufferObject(size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) override { return 0; };
|
||||
void RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) override{};
|
||||
void DeleteBufferObject(int BufferIndex) override{};
|
||||
|
||||
int CreateBufferContainer(SBufferContainerInfo *pContainerInfo) override { return 0; }
|
||||
// destroying all buffer objects means, that all referenced VBOs are destroyed automatically, so the user does not need to save references to them
|
||||
void DeleteBufferContainer(int ContainerIndex, bool DestroyAllBO = true) override{};
|
||||
void UpdateBufferContainer(int ContainerIndex, SBufferContainerInfo *pContainerInfo) override{};
|
||||
void IndicesNumRequiredNotify(unsigned int RequiredIndicesCount) override{};
|
||||
|
||||
int GetNumScreens() const override { return 0; }
|
||||
|
@ -185,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; }
|
||||
|
@ -193,9 +202,15 @@ public:
|
|||
bool IsQuadContainerBufferingEnabled() override { return false; }
|
||||
bool HasTextureArrays() override { return false; }
|
||||
|
||||
const char *GetVendorString() override { return "headless"; }
|
||||
const char *GetVersionString() override { return "headless"; }
|
||||
const char *GetRendererString() override { return "headless"; }
|
||||
const char *GetVendorString() override
|
||||
{
|
||||
return "headless";
|
||||
};
|
||||
const char *GetVersionString() override { return "headless"; };
|
||||
const char *GetRendererString() override { return "headless"; };
|
||||
|
||||
TGLBackendReadPresentedImageData m_FakeGetPresentedImageDataFunc;
|
||||
TGLBackendReadPresentedImageData &GetReadPresentedImageDataFuncUnsafe() override { return m_FakeGetPresentedImageDataFunc; };
|
||||
};
|
||||
|
||||
#endif // ENGINE_CLIENT_GRAPHICS_THREADED_NULL_H
|
||||
|
|
|
@ -80,7 +80,7 @@ static std::atomic<int> m_SoundVolume{100};
|
|||
|
||||
static int m_NextVoice = 0;
|
||||
static int *m_pMixBuffer = 0; // buffer only used by the thread callback function
|
||||
static unsigned m_MaxFrames = 0;
|
||||
static uint32_t m_MaxFrames = 0;
|
||||
|
||||
static const void *s_pWVBuffer = 0x0;
|
||||
static int s_WVBufferPosition = 0;
|
||||
|
@ -109,8 +109,8 @@ static int IntAbs(int i)
|
|||
static void Mix(short *pFinalOut, unsigned Frames)
|
||||
{
|
||||
int MasterVol;
|
||||
mem_zero(m_pMixBuffer, m_MaxFrames * 2 * sizeof(int));
|
||||
Frames = minimum(Frames, m_MaxFrames);
|
||||
mem_zero(m_pMixBuffer, Frames * 2 * sizeof(int));
|
||||
|
||||
// acquire lock while we are mixing
|
||||
m_SoundLock.lock();
|
||||
|
@ -284,9 +284,13 @@ static void SdlCallback(void *pUnused, Uint8 *pStream, int Len)
|
|||
(void)pUnused;
|
||||
#if defined(CONF_VIDEORECORDER)
|
||||
if(!(IVideo::Current() && g_Config.m_ClVideoSndEnable))
|
||||
Mix((short *)pStream, Len / 2 / 2);
|
||||
{
|
||||
Mix((short *)pStream, Len / sizeof(int16_t) / 2);
|
||||
}
|
||||
else
|
||||
IVideo::Current()->NextAudioFrame(Mix);
|
||||
{
|
||||
mem_zero(pStream, Len);
|
||||
}
|
||||
#else
|
||||
Mix((short *)pStream, Len / 2 / 2);
|
||||
#endif
|
||||
|
@ -331,6 +335,9 @@ int CSound::Init()
|
|||
dbg_msg("client/sound", "sound init successful using audio driver '%s'", SDL_GetCurrentAudioDriver());
|
||||
|
||||
m_MaxFrames = FormatOut.samples * 2;
|
||||
#if defined(CONF_VIDEORECORDER)
|
||||
m_MaxFrames = maximum<uint32_t>(m_MaxFrames, 1024 * 2); // make the buffer bigger just in case
|
||||
#endif
|
||||
m_pMixBuffer = (int *)calloc(m_MaxFrames * 2, sizeof(int));
|
||||
|
||||
SDL_PauseAudioDevice(m_Device, 0);
|
||||
|
@ -353,10 +360,6 @@ int CSound::Update()
|
|||
std::unique_lock<std::mutex> Lock(m_SoundLock);
|
||||
m_SoundVolume = WantedVolume;
|
||||
}
|
||||
//#if defined(CONF_VIDEORECORDER)
|
||||
// if(IVideo::Current() && g_Config.m_ClVideoSndEnable)
|
||||
// IVideo::Current()->NextAudioFrame(Mix);
|
||||
//#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -985,4 +988,19 @@ void CSound::StopVoice(CVoiceHandle Voice)
|
|||
}
|
||||
}
|
||||
|
||||
ISoundMixFunc CSound::GetSoundMixFunc()
|
||||
{
|
||||
return Mix;
|
||||
}
|
||||
|
||||
void CSound::PauseAudioDevice()
|
||||
{
|
||||
SDL_PauseAudioDevice(m_Device, 1);
|
||||
}
|
||||
|
||||
void CSound::UnpauseAudioDevice()
|
||||
{
|
||||
SDL_PauseAudioDevice(m_Device, 0);
|
||||
}
|
||||
|
||||
IEngineSound *CreateEngineSound() { return new CSound; }
|
||||
|
|
|
@ -57,6 +57,10 @@ public:
|
|||
virtual void Stop(int SampleID);
|
||||
virtual void StopAll();
|
||||
virtual void StopVoice(CVoiceHandle Voice);
|
||||
|
||||
virtual ISoundMixFunc GetSoundMixFunc();
|
||||
virtual void PauseAudioDevice();
|
||||
virtual void UnpauseAudioDevice();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -131,7 +131,7 @@ public:
|
|||
|
||||
IGraphics::CTextureHandle m_aTextures[2];
|
||||
// keep the full texture, because opengl doesn't provide texture copying
|
||||
unsigned char *m_TextureData[2];
|
||||
uint8_t *m_TextureData[2];
|
||||
|
||||
// width and height are the same
|
||||
int m_CurTextureDimensions[2];
|
||||
|
@ -179,6 +179,8 @@ struct STextContainer
|
|||
bool m_HasCursor;
|
||||
bool m_HasSelection;
|
||||
|
||||
bool m_SingleTimeUse;
|
||||
|
||||
void Reset()
|
||||
{
|
||||
m_pFont = NULL;
|
||||
|
@ -199,6 +201,8 @@ struct STextContainer
|
|||
|
||||
m_HasCursor = false;
|
||||
m_HasSelection = false;
|
||||
|
||||
m_SingleTimeUse = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -315,35 +319,23 @@ class CTextRender : public IEngineTextRender
|
|||
}
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle InitTexture(int Width, int Height, void *pUploadData = NULL)
|
||||
void InitTextures(int Width, int Height, IGraphics::CTextureHandle (&aTextures)[2], uint8_t *(&aTextureData)[2])
|
||||
{
|
||||
void *pMem = NULL;
|
||||
if(pUploadData)
|
||||
{
|
||||
pMem = pUploadData;
|
||||
}
|
||||
else
|
||||
{
|
||||
pMem = calloc((size_t)Width * Height, 1);
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle Texture = Graphics()->LoadTextureRaw(Width, Height, CImageInfo::FORMAT_ALPHA, pMem, CImageInfo::FORMAT_ALPHA, IGraphics::TEXLOAD_NOMIPMAPS | IGraphics::TEXLOAD_NO_COMPRESSION);
|
||||
|
||||
if(!pUploadData)
|
||||
free(pMem);
|
||||
|
||||
return Texture;
|
||||
size_t NewTextureSize = (size_t)Width * (size_t)Height * 1;
|
||||
void *pTmpTextData = malloc(NewTextureSize);
|
||||
void *pTmpTextOutlineData = malloc(NewTextureSize);
|
||||
mem_copy(pTmpTextData, aTextureData[0], NewTextureSize);
|
||||
mem_copy(pTmpTextOutlineData, aTextureData[1], NewTextureSize);
|
||||
Graphics()->LoadTextTextures(Width, Height, aTextures[0], aTextures[1], pTmpTextData, pTmpTextOutlineData);
|
||||
}
|
||||
|
||||
void UnloadTexture(IGraphics::CTextureHandle Index)
|
||||
void UnloadTextures(IGraphics::CTextureHandle (&aTextures)[2])
|
||||
{
|
||||
Graphics()->UnloadTexture(&Index);
|
||||
Graphics()->UnloadTextTextures(aTextures[0], aTextures[1]);
|
||||
}
|
||||
|
||||
void IncreaseFontTexture(CFont *pFont, int TextureIndex)
|
||||
void IncreaseFontTextureImpl(CFont *pFont, int TextureIndex, int NewDimensions)
|
||||
{
|
||||
int NewDimensions = pFont->m_CurTextureDimensions[TextureIndex] * 2;
|
||||
|
||||
unsigned char *pTmpTexBuffer = new unsigned char[NewDimensions * NewDimensions];
|
||||
mem_zero(pTmpTexBuffer, (size_t)NewDimensions * NewDimensions * sizeof(unsigned char));
|
||||
|
||||
|
@ -354,8 +346,6 @@ class CTextRender : public IEngineTextRender
|
|||
pTmpTexBuffer[x + y * NewDimensions] = pFont->m_TextureData[TextureIndex][x + y * pFont->m_CurTextureDimensions[TextureIndex]];
|
||||
}
|
||||
}
|
||||
UnloadTexture(pFont->m_aTextures[TextureIndex]);
|
||||
pFont->m_aTextures[TextureIndex] = InitTexture(NewDimensions, NewDimensions, pTmpTexBuffer);
|
||||
|
||||
delete[] pFont->m_TextureData[TextureIndex];
|
||||
pFont->m_TextureData[TextureIndex] = pTmpTexBuffer;
|
||||
|
@ -363,6 +353,17 @@ class CTextRender : public IEngineTextRender
|
|||
pFont->m_TextureSkyline[TextureIndex].m_CurHeightOfPixelColumn.resize(NewDimensions, 0);
|
||||
}
|
||||
|
||||
void IncreaseFontTexture(CFont *pFont)
|
||||
{
|
||||
int NewDimensions = pFont->m_CurTextureDimensions[0] * 2;
|
||||
UnloadTextures(pFont->m_aTextures);
|
||||
|
||||
IncreaseFontTextureImpl(pFont, 0, NewDimensions);
|
||||
IncreaseFontTextureImpl(pFont, 1, NewDimensions);
|
||||
|
||||
InitTextures(NewDimensions, NewDimensions, pFont->m_aTextures, pFont->m_TextureData);
|
||||
}
|
||||
|
||||
int AdjustOutlineThicknessToFontSize(int OutlineThickness, int FontSize)
|
||||
{
|
||||
if(FontSize > 48)
|
||||
|
@ -381,7 +382,7 @@ class CTextRender : public IEngineTextRender
|
|||
pFont->m_TextureData[TextureIndex][x + PosX + ((y + PosY) * pFont->m_CurTextureDimensions[TextureIndex])] = pData[x + y * Width];
|
||||
}
|
||||
}
|
||||
Graphics()->LoadTextureRawSub(pFont->m_aTextures[TextureIndex], PosX, PosY, Width, Height, CImageInfo::FORMAT_ALPHA, pData);
|
||||
Graphics()->UpdateTextTexture(pFont->m_aTextures[TextureIndex], PosX, PosY, Width, Height, pData);
|
||||
}
|
||||
|
||||
// 128k * 2 of data used for rendering glyphs
|
||||
|
@ -547,7 +548,7 @@ class CTextRender : public IEngineTextRender
|
|||
// upload the glyph
|
||||
while(!GetCharacterSpace(pFont, 0, (int)Width, (int)Height, X, Y))
|
||||
{
|
||||
IncreaseFontTexture(pFont, 0);
|
||||
IncreaseFontTexture(pFont);
|
||||
}
|
||||
UploadGlyph(pFont, 0, X, Y, (int)Width, (int)Height, ms_aGlyphData);
|
||||
|
||||
|
@ -555,7 +556,7 @@ class CTextRender : public IEngineTextRender
|
|||
|
||||
while(!GetCharacterSpace(pFont, 1, (int)Width, (int)Height, X, Y))
|
||||
{
|
||||
IncreaseFontTexture(pFont, 1);
|
||||
IncreaseFontTexture(pFont);
|
||||
}
|
||||
UploadGlyph(pFont, 1, X, Y, (int)Width, (int)Height, ms_aGlyphDataOutlined);
|
||||
}
|
||||
|
@ -665,6 +666,7 @@ public:
|
|||
m_FirstFreeTextContainerIndex = -1;
|
||||
|
||||
m_DefaultTextContainerInfo.m_Stride = sizeof(STextCharQuadVertex);
|
||||
m_DefaultTextContainerInfo.m_VertBufferBindingIndex = -1;
|
||||
|
||||
m_DefaultTextContainerInfo.m_Attributes.emplace_back();
|
||||
SBufferContainerInfo::SAttribute *pAttr = &m_DefaultTextContainerInfo.m_Attributes.back();
|
||||
|
@ -673,7 +675,6 @@ public:
|
|||
pAttr->m_Normalized = false;
|
||||
pAttr->m_pOffset = 0;
|
||||
pAttr->m_Type = GRAPHICS_TYPE_FLOAT;
|
||||
pAttr->m_VertBufferBindingIndex = -1;
|
||||
m_DefaultTextContainerInfo.m_Attributes.emplace_back();
|
||||
pAttr = &m_DefaultTextContainerInfo.m_Attributes.back();
|
||||
pAttr->m_DataTypeCount = 2;
|
||||
|
@ -681,7 +682,6 @@ public:
|
|||
pAttr->m_Normalized = false;
|
||||
pAttr->m_pOffset = (void *)(sizeof(float) * 2);
|
||||
pAttr->m_Type = GRAPHICS_TYPE_FLOAT;
|
||||
pAttr->m_VertBufferBindingIndex = -1;
|
||||
m_DefaultTextContainerInfo.m_Attributes.emplace_back();
|
||||
pAttr = &m_DefaultTextContainerInfo.m_Attributes.back();
|
||||
pAttr->m_DataTypeCount = 4;
|
||||
|
@ -689,7 +689,6 @@ public:
|
|||
pAttr->m_Normalized = true;
|
||||
pAttr->m_pOffset = (void *)(sizeof(float) * 2 + sizeof(float) * 2);
|
||||
pAttr->m_Type = GRAPHICS_TYPE_UNSIGNED_BYTE;
|
||||
pAttr->m_VertBufferBindingIndex = -1;
|
||||
|
||||
IStorage *pStorage = Kernel()->RequestInterface<IStorage>();
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
|
@ -727,8 +726,7 @@ public:
|
|||
pFont->m_TextureData[1] = new unsigned char[pFont->m_CurTextureDimensions[1] * pFont->m_CurTextureDimensions[1]];
|
||||
mem_zero(pFont->m_TextureData[1], (size_t)pFont->m_CurTextureDimensions[1] * pFont->m_CurTextureDimensions[1] * sizeof(unsigned char));
|
||||
|
||||
pFont->m_aTextures[0] = InitTexture(pFont->m_CurTextureDimensions[0], pFont->m_CurTextureDimensions[0]);
|
||||
pFont->m_aTextures[1] = InitTexture(pFont->m_CurTextureDimensions[1], pFont->m_CurTextureDimensions[1]);
|
||||
InitTextures(pFont->m_CurTextureDimensions[0], pFont->m_CurTextureDimensions[0], pFont->m_aTextures, pFont->m_TextureData);
|
||||
|
||||
pFont->m_TextureSkyline[0].m_CurHeightOfPixelColumn.resize(pFont->m_CurTextureDimensions[0], 0);
|
||||
pFont->m_TextureSkyline[1].m_CurHeightOfPixelColumn.resize(pFont->m_CurTextureDimensions[1], 0);
|
||||
|
@ -906,7 +904,10 @@ public:
|
|||
|
||||
virtual void TextEx(CTextCursor *pCursor, const char *pText, int Length)
|
||||
{
|
||||
int OldRenderFlags = m_RenderFlags;
|
||||
m_RenderFlags |= TEXT_RENDER_FLAG_ONE_TIME_USE;
|
||||
int TextCont = CreateTextContainer(pCursor, pText, Length);
|
||||
m_RenderFlags = OldRenderFlags;
|
||||
if(TextCont != -1)
|
||||
{
|
||||
if((pCursor->m_Flags & TEXTFLAG_RENDER) != 0)
|
||||
|
@ -936,6 +937,8 @@ public:
|
|||
STextContainer &TextContainer = GetTextContainer(ContainerIndex);
|
||||
TextContainer.m_pFont = pFont;
|
||||
|
||||
TextContainer.m_SingleTimeUse = (m_RenderFlags & TEXT_RENDER_FLAG_ONE_TIME_USE) != 0;
|
||||
|
||||
CFontSizeData *pSizeData = NULL;
|
||||
|
||||
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
|
||||
|
@ -1405,7 +1408,7 @@ public:
|
|||
|
||||
if(TextContainer.m_StringInfo.m_QuadBufferObjectIndex != -1 && (TextContainer.m_RenderFlags & TEXT_RENDER_FLAG_NO_AUTOMATIC_QUAD_UPLOAD) == 0)
|
||||
{
|
||||
Graphics()->RecreateBufferObject(TextContainer.m_StringInfo.m_QuadBufferObjectIndex, DataSize, pUploadData);
|
||||
Graphics()->RecreateBufferObject(TextContainer.m_StringInfo.m_QuadBufferObjectIndex, DataSize, pUploadData, TextContainer.m_SingleTimeUse ? IGraphics::EBufferObjectCreateFlags::BUFFER_OBJECT_CREATE_FLAGS_ONE_TIME_USE_BIT : 0);
|
||||
Graphics()->IndicesNumRequiredNotify(TextContainer.m_StringInfo.m_QuadNum * 6);
|
||||
}
|
||||
}
|
||||
|
@ -1524,11 +1527,10 @@ public:
|
|||
{
|
||||
STextContainer &TextContainer = GetTextContainer(TextContainerIndex);
|
||||
size_t DataSize = TextContainer.m_StringInfo.m_CharacterQuads.size() * sizeof(STextCharQuad);
|
||||
void *pUploadData = &TextContainer.m_StringInfo.m_CharacterQuads[0];
|
||||
TextContainer.m_StringInfo.m_QuadBufferObjectIndex = Graphics()->CreateBufferObject(DataSize, pUploadData);
|
||||
void *pUploadData = TextContainer.m_StringInfo.m_CharacterQuads.data();
|
||||
TextContainer.m_StringInfo.m_QuadBufferObjectIndex = Graphics()->CreateBufferObject(DataSize, pUploadData, TextContainer.m_SingleTimeUse ? IGraphics::EBufferObjectCreateFlags::BUFFER_OBJECT_CREATE_FLAGS_ONE_TIME_USE_BIT : 0);
|
||||
|
||||
for(auto &Attribute : m_DefaultTextContainerInfo.m_Attributes)
|
||||
Attribute.m_VertBufferBindingIndex = TextContainer.m_StringInfo.m_QuadBufferObjectIndex;
|
||||
m_DefaultTextContainerInfo.m_VertBufferBindingIndex = TextContainer.m_StringInfo.m_QuadBufferObjectIndex;
|
||||
|
||||
TextContainer.m_StringInfo.m_QuadBufferContainerIndex = Graphics()->CreateBufferContainer(&m_DefaultTextContainerInfo);
|
||||
Graphics()->IndicesNumRequiredNotify(TextContainer.m_StringInfo.m_QuadNum * 6);
|
||||
|
@ -1920,7 +1922,7 @@ public:
|
|||
k = 0;
|
||||
|
||||
mem_zero(pFont->m_TextureData[j], (size_t)pFont->m_CurTextureDimensions[j] * pFont->m_CurTextureDimensions[j] * sizeof(unsigned char));
|
||||
Graphics()->LoadTextureRawSub(pFont->m_aTextures[j], 0, 0, pFont->m_CurTextureDimensions[j], pFont->m_CurTextureDimensions[j], CImageInfo::FORMAT_ALPHA, pFont->m_TextureData[j]);
|
||||
Graphics()->UpdateTextTexture(pFont->m_aTextures[j], 0, 0, pFont->m_CurTextureDimensions[j], pFont->m_CurTextureDimensions[j], pFont->m_TextureData[j]);
|
||||
}
|
||||
|
||||
pFont->InitFontSizes();
|
||||
|
|
|
@ -4,34 +4,28 @@
|
|||
#include <engine/shared/config.h>
|
||||
#include <engine/storage.h>
|
||||
|
||||
#include "video.h"
|
||||
#include <engine/client/graphics_threaded.h>
|
||||
#include <engine/sound.h>
|
||||
|
||||
#ifndef CONF_BACKEND_OPENGL_ES
|
||||
#include <GL/glew.h>
|
||||
#else
|
||||
#include <GLES3/gl3.h>
|
||||
#endif
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "video.h"
|
||||
|
||||
// This code is mostly stolen from https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/muxing.c
|
||||
|
||||
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
|
||||
|
||||
const size_t FORMAT_NCHANNELS = 3;
|
||||
const size_t FORMAT_GL_NCHANNELS = 4;
|
||||
LOCK g_WriteLock = 0;
|
||||
|
||||
CVideo::CVideo(CGraphics_Threaded *pGraphics, IStorage *pStorage, IConsole *pConsole, int Width, int Height, const char *pName) :
|
||||
CVideo::CVideo(CGraphics_Threaded *pGraphics, ISound *pSound, IStorage *pStorage, IConsole *pConsole, int Width, int Height, const char *pName) :
|
||||
m_pGraphics(pGraphics),
|
||||
m_pStorage(pStorage),
|
||||
m_pConsole(pConsole),
|
||||
m_VideoStream(),
|
||||
m_AudioStream()
|
||||
m_pSound(pSound)
|
||||
{
|
||||
m_pPixels = 0;
|
||||
|
||||
m_pFormatContext = 0;
|
||||
m_pFormat = 0;
|
||||
m_pRGB = 0;
|
||||
m_pOptDict = 0;
|
||||
|
||||
m_VideoCodec = 0;
|
||||
|
@ -45,17 +39,14 @@ CVideo::CVideo(CGraphics_Threaded *pGraphics, IStorage *pStorage, IConsole *pCon
|
|||
|
||||
m_Recording = false;
|
||||
m_Started = false;
|
||||
m_ProcessingVideoFrame = false;
|
||||
m_ProcessingAudioFrame = false;
|
||||
m_ProcessingVideoFrame = 0;
|
||||
m_ProcessingAudioFrame = 0;
|
||||
|
||||
m_NextFrame = false;
|
||||
m_NextAudioFrame = false;
|
||||
|
||||
// TODO:
|
||||
m_HasAudio = g_Config.m_ClVideoSndEnable;
|
||||
|
||||
m_SndBufferSize = g_Config.m_SndBufferSize;
|
||||
|
||||
dbg_assert(ms_pCurrentVideo == 0, "ms_pCurrentVideo is NOT set to NULL while creating a new Video.");
|
||||
|
||||
ms_TickTime = time_freq() / m_FPS;
|
||||
|
@ -71,6 +62,12 @@ CVideo::~CVideo()
|
|||
|
||||
void CVideo::Start()
|
||||
{
|
||||
// wait for the graphic thread to idle
|
||||
m_pGraphics->WaitForIdle();
|
||||
|
||||
m_AudioStream = {};
|
||||
m_VideoStream = {};
|
||||
|
||||
char aDate[20];
|
||||
str_timestamp(aDate, sizeof(aDate));
|
||||
char aBuf[256];
|
||||
|
@ -101,10 +98,20 @@ void CVideo::Start()
|
|||
|
||||
m_pFormat = m_pFormatContext->oformat;
|
||||
|
||||
size_t NVals = FORMAT_NCHANNELS * m_Width * m_Height;
|
||||
m_VideoThreads = std::thread::hardware_concurrency() + 2;
|
||||
// audio gets a bit less
|
||||
m_AudioThreads = (std::thread::hardware_concurrency() / 2) + 2;
|
||||
m_CurVideoThreadIndex = 0;
|
||||
m_CurAudioThreadIndex = 0;
|
||||
|
||||
size_t GLNVals = FORMAT_GL_NCHANNELS * m_Width * m_Height;
|
||||
m_pPixels = (uint8_t *)malloc(GLNVals * sizeof(TWGLubyte));
|
||||
m_pRGB = (uint8_t *)malloc(NVals * sizeof(uint8_t));
|
||||
m_vPixelHelper.resize(m_VideoThreads);
|
||||
for(size_t i = 0; i < m_VideoThreads; ++i)
|
||||
{
|
||||
m_vPixelHelper[i].resize(GLNVals * sizeof(uint8_t));
|
||||
}
|
||||
|
||||
m_vBuffer.resize(m_AudioThreads);
|
||||
|
||||
/* Add the audio and video streams using the default format codecs
|
||||
* and initialize the codecs. */
|
||||
|
@ -128,6 +135,30 @@ void CVideo::Start()
|
|||
dbg_msg("video_recorder", "No audio.");
|
||||
}
|
||||
|
||||
m_vVideoThreads.resize(m_VideoThreads);
|
||||
for(size_t i = 0; i < m_VideoThreads; ++i)
|
||||
{
|
||||
m_vVideoThreads[i] = std::make_unique<SVideoRecorderThread>();
|
||||
}
|
||||
for(size_t i = 0; i < m_VideoThreads; ++i)
|
||||
{
|
||||
std::unique_lock<std::mutex> Lock(m_vVideoThreads[i]->m_Mutex);
|
||||
m_vVideoThreads[i]->m_Thread = std::thread([this, i]() { RunVideoThread(i == 0 ? (m_VideoThreads - 1) : (i - 1), i); });
|
||||
m_vVideoThreads[i]->m_Cond.wait(Lock, [this, i]() -> bool { return m_vVideoThreads[i]->m_Started; });
|
||||
}
|
||||
|
||||
m_vAudioThreads.resize(m_AudioThreads);
|
||||
for(size_t i = 0; i < m_AudioThreads; ++i)
|
||||
{
|
||||
m_vAudioThreads[i] = std::make_unique<SAudioRecorderThread>();
|
||||
}
|
||||
for(size_t i = 0; i < m_AudioThreads; ++i)
|
||||
{
|
||||
std::unique_lock<std::mutex> Lock(m_vAudioThreads[i]->m_Mutex);
|
||||
m_vAudioThreads[i]->m_Thread = std::thread([this, i]() { RunAudioThread(i == 0 ? (m_AudioThreads - 1) : (i - 1), i); });
|
||||
m_vAudioThreads[i]->m_Cond.wait(Lock, [this, i]() -> bool { return m_vAudioThreads[i]->m_Started; });
|
||||
}
|
||||
|
||||
/* Now that all the parameters are set, we can open the audio and
|
||||
* video codecs and allocate the necessary encode buffers. */
|
||||
if(!OpenVideo())
|
||||
|
@ -153,13 +184,21 @@ void CVideo::Start()
|
|||
}
|
||||
}
|
||||
|
||||
if(!m_VideoStream.pSwsCtx)
|
||||
m_VideoStream.m_vpSwsCtxs.reserve(m_VideoThreads);
|
||||
|
||||
for(size_t i = 0; i < m_VideoThreads; ++i)
|
||||
{
|
||||
m_VideoStream.pSwsCtx = sws_getCachedContext(
|
||||
m_VideoStream.pSwsCtx,
|
||||
m_VideoStream.pEnc->width, m_VideoStream.pEnc->height, AV_PIX_FMT_RGB24,
|
||||
m_VideoStream.pEnc->width, m_VideoStream.pEnc->height, AV_PIX_FMT_YUV420P,
|
||||
0, 0, 0, 0);
|
||||
if(m_VideoStream.m_vpSwsCtxs.size() <= i)
|
||||
m_VideoStream.m_vpSwsCtxs.emplace_back(nullptr);
|
||||
|
||||
if(!m_VideoStream.m_vpSwsCtxs[i])
|
||||
{
|
||||
m_VideoStream.m_vpSwsCtxs[i] = sws_getCachedContext(
|
||||
m_VideoStream.m_vpSwsCtxs[i],
|
||||
m_VideoStream.pEnc->width, m_VideoStream.pEnc->height, AV_PIX_FMT_RGBA,
|
||||
m_VideoStream.pEnc->width, m_VideoStream.pEnc->height, AV_PIX_FMT_YUV420P,
|
||||
0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the stream header, if any. */
|
||||
|
@ -185,11 +224,37 @@ void CVideo::Pause(bool Pause)
|
|||
|
||||
void CVideo::Stop()
|
||||
{
|
||||
m_Recording = false;
|
||||
m_pGraphics->WaitForIdle();
|
||||
|
||||
while(m_ProcessingVideoFrame || m_ProcessingAudioFrame)
|
||||
for(size_t i = 0; i < m_VideoThreads; ++i)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> Lock(m_vVideoThreads[i]->m_Mutex);
|
||||
m_vVideoThreads[i]->m_Finished = true;
|
||||
m_vVideoThreads[i]->m_Cond.notify_all();
|
||||
}
|
||||
|
||||
m_vVideoThreads[i]->m_Thread.join();
|
||||
}
|
||||
m_vVideoThreads.clear();
|
||||
|
||||
for(size_t i = 0; i < m_AudioThreads; ++i)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> Lock(m_vAudioThreads[i]->m_Mutex);
|
||||
m_vAudioThreads[i]->m_Finished = true;
|
||||
m_vAudioThreads[i]->m_Cond.notify_all();
|
||||
}
|
||||
|
||||
m_vAudioThreads[i]->m_Thread.join();
|
||||
}
|
||||
m_vAudioThreads.clear();
|
||||
|
||||
while(m_ProcessingVideoFrame > 0 || m_ProcessingAudioFrame > 0)
|
||||
thread_sleep(10);
|
||||
|
||||
m_Recording = false;
|
||||
|
||||
FinishFrames(&m_VideoStream);
|
||||
|
||||
if(m_HasAudio)
|
||||
|
@ -209,11 +274,11 @@ void CVideo::Stop()
|
|||
if(m_pFormatContext)
|
||||
avformat_free_context(m_pFormatContext);
|
||||
|
||||
free(m_pRGB);
|
||||
|
||||
free(m_pPixels);
|
||||
ISound *volatile pSound = m_pSound;
|
||||
|
||||
pSound->PauseAudioDevice();
|
||||
delete ms_pCurrentVideo;
|
||||
pSound->UnpauseAudioDevice();
|
||||
}
|
||||
|
||||
void CVideo::NextVideoFrameThread()
|
||||
|
@ -223,19 +288,52 @@ void CVideo::NextVideoFrameThread()
|
|||
// #ifdef CONF_PLATFORM_MACOS
|
||||
// CAutoreleasePool AutoreleasePool;
|
||||
// #endif
|
||||
m_Vseq += 1;
|
||||
if(m_Vseq >= 2)
|
||||
m_VSeq += 1;
|
||||
if(m_VSeq >= 2)
|
||||
{
|
||||
m_ProcessingVideoFrame = true;
|
||||
m_VideoStream.pFrame->pts = (int64_t)m_VideoStream.pEnc->frame_number;
|
||||
m_ProcessingVideoFrame.fetch_add(1);
|
||||
|
||||
size_t NextVideoThreadIndex = m_CurVideoThreadIndex + 1;
|
||||
if(NextVideoThreadIndex == m_VideoThreads)
|
||||
NextVideoThreadIndex = 0;
|
||||
|
||||
// always wait for the next video thread too, to prevent a dead lock
|
||||
|
||||
{
|
||||
auto *pVideoThread = m_vVideoThreads[NextVideoThreadIndex].get();
|
||||
std::unique_lock<std::mutex> Lock(pVideoThread->m_Mutex);
|
||||
|
||||
if(pVideoThread->m_HasVideoFrame)
|
||||
{
|
||||
pVideoThread->m_Cond.wait(Lock, [&pVideoThread]() -> bool { return !pVideoThread->m_HasVideoFrame; });
|
||||
}
|
||||
}
|
||||
|
||||
//dbg_msg("video_recorder", "vframe: %d", m_VideoStream.pEnc->frame_number);
|
||||
|
||||
ReadRGBFromGL();
|
||||
FillVideoFrame();
|
||||
lock_wait(g_WriteLock);
|
||||
WriteFrame(&m_VideoStream);
|
||||
lock_unlock(g_WriteLock);
|
||||
m_ProcessingVideoFrame = false;
|
||||
// after reading the graphic libraries' frame buffer, go threaded
|
||||
{
|
||||
auto *pVideoThread = m_vVideoThreads[m_CurVideoThreadIndex].get();
|
||||
std::unique_lock<std::mutex> Lock(pVideoThread->m_Mutex);
|
||||
|
||||
if(pVideoThread->m_HasVideoFrame)
|
||||
{
|
||||
pVideoThread->m_Cond.wait(Lock, [&pVideoThread]() -> bool { return !pVideoThread->m_HasVideoFrame; });
|
||||
}
|
||||
|
||||
ReadRGBFromGL(m_CurVideoThreadIndex);
|
||||
|
||||
pVideoThread->m_HasVideoFrame = true;
|
||||
{
|
||||
std::unique_lock<std::mutex> LockParent(pVideoThread->m_VideoFillMutex);
|
||||
pVideoThread->m_VideoFrameToFill = m_VSeq;
|
||||
}
|
||||
pVideoThread->m_Cond.notify_all();
|
||||
}
|
||||
|
||||
++m_CurVideoThreadIndex;
|
||||
if(m_CurVideoThreadIndex == m_VideoThreads)
|
||||
m_CurVideoThreadIndex = 0;
|
||||
}
|
||||
|
||||
m_NextFrame = false;
|
||||
|
@ -266,129 +364,220 @@ void CVideo::NextVideoFrame()
|
|||
}
|
||||
}
|
||||
|
||||
void CVideo::NextAudioFrameTimeline()
|
||||
void CVideo::NextAudioFrameTimeline(ISoundMixFunc Mix)
|
||||
{
|
||||
if(m_Recording && m_HasAudio)
|
||||
{
|
||||
//if(m_Vframe * m_AudioStream.pEnc->sample_rate / m_FPS >= m_AudioStream.pEnc->frame_number*m_AudioStream.pEnc->frame_size)
|
||||
if(m_VideoStream.pEnc->frame_number * (double)m_AudioStream.pEnc->sample_rate / m_FPS >= (double)m_AudioStream.pEnc->frame_number * m_AudioStream.pEnc->frame_size)
|
||||
//if(m_VideoStream.pEnc->frame_number * (double)m_AudioStream.pEnc->sample_rate / m_FPS >= (double)m_AudioStream.pEnc->frame_number * m_AudioStream.pEnc->frame_size)
|
||||
double SamplesPerFrame = (double)m_AudioStream.pEnc->sample_rate / m_FPS;
|
||||
while(m_AudioStream.m_SamplesFrameCount >= m_AudioStream.m_SamplesCount)
|
||||
{
|
||||
m_NextAudioFrame = true;
|
||||
NextAudioFrame(Mix);
|
||||
}
|
||||
m_AudioStream.m_SamplesFrameCount += SamplesPerFrame;
|
||||
}
|
||||
}
|
||||
|
||||
void CVideo::NextAudioFrame(void (*Mix)(short *pFinalOut, unsigned Frames))
|
||||
void CVideo::NextAudioFrame(ISoundMixFunc Mix)
|
||||
{
|
||||
if(m_NextAudioFrame && m_Recording && m_HasAudio)
|
||||
if(m_Recording && m_HasAudio)
|
||||
{
|
||||
m_ProcessingAudioFrame = true;
|
||||
//dbg_msg("video_recorder", "video_frame: %lf", (double)(m_Vframe/m_FPS));
|
||||
//if((double)(m_Vframe/m_FPS) < m_AudioStream.pEnc->frame_number*m_AudioStream.pEnc->frame_size/m_AudioStream.pEnc->sample_rate)
|
||||
//return;
|
||||
Mix(m_aBuffer, ALEN);
|
||||
//m_AudioStream.pFrame->pts = m_AudioStream.pEnc->frame_number;
|
||||
//dbg_msg("video_recorder", "aframe: %d", m_AudioStream.pEnc->frame_number);
|
||||
m_ASeq += 1;
|
||||
|
||||
// memcpy(m_AudioStream.pTmpFrame->data[0], pData, sizeof(int16_t) * m_SndBufferSize * 2);
|
||||
//
|
||||
// for(int i = 0; i < m_SndBufferSize; i++)
|
||||
// {
|
||||
// dbg_msg("video_recorder", "test: %d %d", ((int16_t*)pData)[i*2], ((int16_t*)pData)[i*2 + 1]);
|
||||
// }
|
||||
m_ProcessingAudioFrame.fetch_add(1);
|
||||
|
||||
int DstNbSamples;
|
||||
size_t NextAudioThreadIndex = m_CurAudioThreadIndex + 1;
|
||||
if(NextAudioThreadIndex == m_AudioThreads)
|
||||
NextAudioThreadIndex = 0;
|
||||
|
||||
av_samples_fill_arrays(
|
||||
(uint8_t **)m_AudioStream.pTmpFrame->data,
|
||||
0, // pointer to linesize (int*)
|
||||
(const uint8_t *)m_aBuffer,
|
||||
2, // channels
|
||||
m_AudioStream.pTmpFrame->nb_samples,
|
||||
AV_SAMPLE_FMT_S16,
|
||||
0 // align
|
||||
);
|
||||
// always wait for the next Audio thread too, to prevent a dead lock
|
||||
|
||||
DstNbSamples = av_rescale_rnd(
|
||||
swr_get_delay(
|
||||
m_AudioStream.pSwrCtx,
|
||||
m_AudioStream.pEnc->sample_rate) +
|
||||
m_AudioStream.pTmpFrame->nb_samples,
|
||||
|
||||
m_AudioStream.pEnc->sample_rate,
|
||||
m_AudioStream.pEnc->sample_rate, AV_ROUND_UP);
|
||||
|
||||
// dbg_msg("video_recorder", "DstNbSamples: %d", DstNbSamples);
|
||||
// fwrite(m_aBuffer, sizeof(short), 2048, m_dbgfile);
|
||||
|
||||
int Ret = av_frame_make_writable(m_AudioStream.pFrame);
|
||||
if(Ret < 0)
|
||||
{
|
||||
dbg_msg("video_recorder", "Error making frame writable");
|
||||
return;
|
||||
auto *pAudioThread = m_vAudioThreads[NextAudioThreadIndex].get();
|
||||
std::unique_lock<std::mutex> Lock(pAudioThread->m_Mutex);
|
||||
|
||||
if(pAudioThread->m_HasAudioFrame)
|
||||
{
|
||||
pAudioThread->m_Cond.wait(Lock, [&pAudioThread]() -> bool { return !pAudioThread->m_HasAudioFrame; });
|
||||
}
|
||||
}
|
||||
|
||||
/* convert to destination format */
|
||||
Ret = swr_convert(
|
||||
m_AudioStream.pSwrCtx,
|
||||
m_AudioStream.pFrame->data,
|
||||
m_AudioStream.pFrame->nb_samples,
|
||||
(const uint8_t **)m_AudioStream.pTmpFrame->data,
|
||||
m_AudioStream.pTmpFrame->nb_samples);
|
||||
|
||||
if(Ret < 0)
|
||||
// after reading the graphic libraries' frame buffer, go threaded
|
||||
{
|
||||
dbg_msg("video_recorder", "Error while converting");
|
||||
return;
|
||||
auto *pAudioThread = m_vAudioThreads[m_CurAudioThreadIndex].get();
|
||||
|
||||
std::unique_lock<std::mutex> Lock(pAudioThread->m_Mutex);
|
||||
|
||||
if(pAudioThread->m_HasAudioFrame)
|
||||
{
|
||||
pAudioThread->m_Cond.wait(Lock, [&pAudioThread]() -> bool { return !pAudioThread->m_HasAudioFrame; });
|
||||
}
|
||||
|
||||
Mix(m_vBuffer[m_CurAudioThreadIndex].m_aBuffer, ALEN / 2); // two channels
|
||||
|
||||
int64_t DstNbSamples = av_rescale_rnd(
|
||||
swr_get_delay(m_AudioStream.m_vpSwrCtxs[m_CurAudioThreadIndex], m_AudioStream.pEnc->sample_rate) +
|
||||
m_AudioStream.m_vpFrames[m_CurAudioThreadIndex]->nb_samples,
|
||||
m_AudioStream.pEnc->sample_rate,
|
||||
m_AudioStream.pEnc->sample_rate, AV_ROUND_UP);
|
||||
|
||||
pAudioThread->m_SampleCountStart = m_AudioStream.m_SamplesCount;
|
||||
m_AudioStream.m_SamplesCount += DstNbSamples;
|
||||
|
||||
pAudioThread->m_HasAudioFrame = true;
|
||||
{
|
||||
std::unique_lock<std::mutex> LockParent(pAudioThread->m_AudioFillMutex);
|
||||
pAudioThread->m_AudioFrameToFill = m_ASeq;
|
||||
}
|
||||
pAudioThread->m_Cond.notify_all();
|
||||
}
|
||||
|
||||
// frame = ost->frame;
|
||||
//
|
||||
m_AudioStream.pFrame->pts = av_rescale_q(m_AudioStream.SamplesCount, AVRational{1, m_AudioStream.pEnc->sample_rate}, m_AudioStream.pEnc->time_base);
|
||||
m_AudioStream.SamplesCount += DstNbSamples;
|
||||
|
||||
// dbg_msg("video_recorder", "prewrite----");
|
||||
lock_wait(g_WriteLock);
|
||||
WriteFrame(&m_AudioStream);
|
||||
lock_unlock(g_WriteLock);
|
||||
|
||||
m_ProcessingAudioFrame = false;
|
||||
m_NextAudioFrame = false;
|
||||
++m_CurAudioThreadIndex;
|
||||
if(m_CurAudioThreadIndex == m_AudioThreads)
|
||||
m_CurAudioThreadIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CVideo::FillAudioFrame()
|
||||
void CVideo::RunAudioThread(size_t ParentThreadIndex, size_t ThreadIndex)
|
||||
{
|
||||
}
|
||||
auto *pThreadData = m_vAudioThreads[ThreadIndex].get();
|
||||
auto *pParentThreadData = m_vAudioThreads[ParentThreadIndex].get();
|
||||
std::unique_lock<std::mutex> Lock(pThreadData->m_Mutex);
|
||||
pThreadData->m_Started = true;
|
||||
pThreadData->m_Cond.notify_all();
|
||||
|
||||
void CVideo::FillVideoFrame()
|
||||
{
|
||||
const int InLinesize[1] = {3 * m_VideoStream.pEnc->width};
|
||||
sws_scale(m_VideoStream.pSwsCtx, (const uint8_t *const *)&m_pRGB, InLinesize, 0,
|
||||
m_VideoStream.pEnc->height, m_VideoStream.pFrame->data, m_VideoStream.pFrame->linesize);
|
||||
}
|
||||
|
||||
void CVideo::ReadRGBFromGL()
|
||||
{
|
||||
/* Get RGBA to align to 32 bits instead of just 24 for RGB. May be faster for FFmpeg. */
|
||||
glReadBuffer(GL_FRONT);
|
||||
GLint Alignment;
|
||||
glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(0, 0, m_Width, m_Height, GL_RGBA, GL_UNSIGNED_BYTE, m_pPixels);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, Alignment);
|
||||
for(int i = 0; i < m_Height; i++)
|
||||
while(!pThreadData->m_Finished)
|
||||
{
|
||||
for(int j = 0; j < m_Width; j++)
|
||||
pThreadData->m_Cond.wait(Lock, [&pThreadData]() -> bool { return pThreadData->m_HasAudioFrame || pThreadData->m_Finished; });
|
||||
pThreadData->m_Cond.notify_all();
|
||||
|
||||
if(pThreadData->m_HasAudioFrame)
|
||||
{
|
||||
size_t CurGL = FORMAT_GL_NCHANNELS * (m_Width * (m_Height - i - 1) + j);
|
||||
size_t CurRGB = FORMAT_NCHANNELS * (m_Width * i + j);
|
||||
for(int k = 0; k < (int)FORMAT_NCHANNELS; k++)
|
||||
m_pRGB[CurRGB + k] = m_pPixels[CurGL + k];
|
||||
FillAudioFrame(ThreadIndex);
|
||||
// check if we need to wait for the parent to finish
|
||||
{
|
||||
std::unique_lock<std::mutex> LockParent(pParentThreadData->m_AudioFillMutex);
|
||||
if(pParentThreadData->m_AudioFrameToFill != 0 && pThreadData->m_AudioFrameToFill >= pParentThreadData->m_AudioFrameToFill)
|
||||
{
|
||||
// wait for the parent to finish its frame
|
||||
pParentThreadData->m_AudioFillCond.wait(LockParent, [&pParentThreadData]() -> bool { return pParentThreadData->m_AudioFrameToFill == 0; });
|
||||
}
|
||||
}
|
||||
{
|
||||
std::unique_lock<std::mutex> LockAudio(pThreadData->m_AudioFillMutex);
|
||||
|
||||
lock_wait(g_WriteLock);
|
||||
m_AudioStream.m_vpFrames[ThreadIndex]->pts = av_rescale_q(pThreadData->m_SampleCountStart, AVRational{1, m_AudioStream.pEnc->sample_rate}, m_AudioStream.pEnc->time_base);
|
||||
WriteFrame(&m_AudioStream, ThreadIndex);
|
||||
lock_unlock(g_WriteLock);
|
||||
|
||||
pThreadData->m_AudioFrameToFill = 0;
|
||||
pThreadData->m_AudioFillCond.notify_all();
|
||||
pThreadData->m_Cond.notify_all();
|
||||
}
|
||||
m_ProcessingAudioFrame.fetch_sub(1);
|
||||
|
||||
pThreadData->m_HasAudioFrame = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CVideo::FillAudioFrame(size_t ThreadIndex)
|
||||
{
|
||||
av_samples_fill_arrays(
|
||||
(uint8_t **)m_AudioStream.m_vpTmpFrames[ThreadIndex]->data,
|
||||
0, // pointer to linesize (int*)
|
||||
(const uint8_t *)m_vBuffer[ThreadIndex].m_aBuffer,
|
||||
2, // channels
|
||||
m_AudioStream.m_vpTmpFrames[ThreadIndex]->nb_samples,
|
||||
AV_SAMPLE_FMT_S16,
|
||||
0 // align
|
||||
);
|
||||
|
||||
// dbg_msg("video_recorder", "DstNbSamples: %d", DstNbSamples);
|
||||
// fwrite(m_aBuffer, sizeof(short), 2048, m_dbgfile);
|
||||
|
||||
int Ret = av_frame_make_writable(m_AudioStream.m_vpFrames[ThreadIndex]);
|
||||
if(Ret < 0)
|
||||
{
|
||||
dbg_msg("video_recorder", "Error making frame writable");
|
||||
return;
|
||||
}
|
||||
|
||||
/* convert to destination format */
|
||||
Ret = swr_convert(
|
||||
m_AudioStream.m_vpSwrCtxs[ThreadIndex],
|
||||
m_AudioStream.m_vpFrames[ThreadIndex]->data,
|
||||
m_AudioStream.m_vpFrames[ThreadIndex]->nb_samples,
|
||||
(const uint8_t **)m_AudioStream.m_vpTmpFrames[ThreadIndex]->data,
|
||||
m_AudioStream.m_vpTmpFrames[ThreadIndex]->nb_samples);
|
||||
|
||||
if(Ret < 0)
|
||||
{
|
||||
dbg_msg("video_recorder", "Error while converting");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CVideo::RunVideoThread(size_t ParentThreadIndex, size_t ThreadIndex)
|
||||
{
|
||||
auto *pThreadData = m_vVideoThreads[ThreadIndex].get();
|
||||
auto *pParentThreadData = m_vVideoThreads[ParentThreadIndex].get();
|
||||
std::unique_lock<std::mutex> Lock(pThreadData->m_Mutex);
|
||||
pThreadData->m_Started = true;
|
||||
pThreadData->m_Cond.notify_all();
|
||||
|
||||
while(!pThreadData->m_Finished)
|
||||
{
|
||||
pThreadData->m_Cond.wait(Lock, [&pThreadData]() -> bool { return pThreadData->m_HasVideoFrame || pThreadData->m_Finished; });
|
||||
pThreadData->m_Cond.notify_all();
|
||||
|
||||
if(pThreadData->m_HasVideoFrame)
|
||||
{
|
||||
FillVideoFrame(ThreadIndex);
|
||||
// check if we need to wait for the parent to finish
|
||||
{
|
||||
std::unique_lock<std::mutex> LockParent(pParentThreadData->m_VideoFillMutex);
|
||||
if(pParentThreadData->m_VideoFrameToFill != 0 && pThreadData->m_VideoFrameToFill >= pParentThreadData->m_VideoFrameToFill)
|
||||
{
|
||||
// wait for the parent to finish its frame
|
||||
pParentThreadData->m_VideoFillCond.wait(LockParent, [&pParentThreadData]() -> bool { return pParentThreadData->m_VideoFrameToFill == 0; });
|
||||
}
|
||||
}
|
||||
{
|
||||
std::unique_lock<std::mutex> LockVideo(pThreadData->m_VideoFillMutex);
|
||||
lock_wait(g_WriteLock);
|
||||
m_VideoStream.m_vpFrames[ThreadIndex]->pts = (int64_t)m_VideoStream.pEnc->frame_number;
|
||||
WriteFrame(&m_VideoStream, ThreadIndex);
|
||||
lock_unlock(g_WriteLock);
|
||||
|
||||
pThreadData->m_VideoFrameToFill = 0;
|
||||
pThreadData->m_VideoFillCond.notify_all();
|
||||
pThreadData->m_Cond.notify_all();
|
||||
}
|
||||
m_ProcessingVideoFrame.fetch_sub(1);
|
||||
|
||||
pThreadData->m_HasVideoFrame = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CVideo::FillVideoFrame(size_t ThreadIndex)
|
||||
{
|
||||
const int InLinesize[1] = {4 * m_VideoStream.pEnc->width};
|
||||
auto *pRGBAData = m_vPixelHelper[ThreadIndex].data();
|
||||
sws_scale(m_VideoStream.m_vpSwsCtxs[ThreadIndex], (const uint8_t *const *)&pRGBAData, InLinesize, 0,
|
||||
m_VideoStream.pEnc->height, m_VideoStream.m_vpFrames[ThreadIndex]->data, m_VideoStream.m_vpFrames[ThreadIndex]->linesize);
|
||||
}
|
||||
|
||||
void CVideo::ReadRGBFromGL(size_t ThreadIndex)
|
||||
{
|
||||
uint32_t Width;
|
||||
uint32_t Height;
|
||||
uint32_t Format;
|
||||
m_pGraphics->GetReadPresentedImageDataFuncUnsafe()(Width, Height, Format, m_vPixelHelper[ThreadIndex]);
|
||||
}
|
||||
|
||||
AVFrame *CVideo::AllocPicture(enum AVPixelFormat PixFmt, int Width, int Height)
|
||||
{
|
||||
AVFrame *pPicture;
|
||||
|
@ -461,25 +650,39 @@ bool CVideo::OpenVideo()
|
|||
return false;
|
||||
}
|
||||
|
||||
m_VideoStream.m_vpFrames.clear();
|
||||
m_VideoStream.m_vpFrames.reserve(m_VideoThreads);
|
||||
|
||||
/* allocate and init a re-usable frame */
|
||||
m_VideoStream.pFrame = AllocPicture(c->pix_fmt, c->width, c->height);
|
||||
if(!m_VideoStream.pFrame)
|
||||
for(size_t i = 0; i < m_VideoThreads; ++i)
|
||||
{
|
||||
dbg_msg("video_recorder", "Could not allocate video frame");
|
||||
return false;
|
||||
m_VideoStream.m_vpFrames.emplace_back(nullptr);
|
||||
m_VideoStream.m_vpFrames[i] = AllocPicture(c->pix_fmt, c->width, c->height);
|
||||
if(!m_VideoStream.m_vpFrames[i])
|
||||
{
|
||||
dbg_msg("video_recorder", "Could not allocate video frame");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the output format is not YUV420P, then a temporary YUV420P
|
||||
* picture is needed too. It is then converted to the required
|
||||
* output format. */
|
||||
m_VideoStream.pTmpFrame = NULL;
|
||||
m_VideoStream.m_vpTmpFrames.clear();
|
||||
m_VideoStream.m_vpTmpFrames.reserve(m_VideoThreads);
|
||||
|
||||
if(c->pix_fmt != AV_PIX_FMT_YUV420P)
|
||||
{
|
||||
m_VideoStream.pTmpFrame = AllocPicture(AV_PIX_FMT_YUV420P, c->width, c->height);
|
||||
if(!m_VideoStream.pTmpFrame)
|
||||
/* allocate and init a re-usable frame */
|
||||
for(size_t i = 0; i < m_VideoThreads; ++i)
|
||||
{
|
||||
dbg_msg("video_recorder", "Could not allocate temporary picture");
|
||||
return false;
|
||||
m_VideoStream.m_vpTmpFrames.emplace_back(nullptr);
|
||||
m_VideoStream.m_vpTmpFrames[i] = AllocPicture(AV_PIX_FMT_YUV420P, c->width, c->height);
|
||||
if(!m_VideoStream.m_vpTmpFrames[i])
|
||||
{
|
||||
dbg_msg("video_recorder", "Could not allocate temporary video frame");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -490,7 +693,7 @@ bool CVideo::OpenVideo()
|
|||
dbg_msg("video_recorder", "Could not copy the stream parameters");
|
||||
return false;
|
||||
}
|
||||
m_Vseq = 0;
|
||||
m_VSeq = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -521,9 +724,31 @@ bool CVideo::OpenAudio()
|
|||
else
|
||||
NbSamples = c->frame_size;
|
||||
|
||||
m_AudioStream.pFrame = AllocAudioFrame(c->sample_fmt, c->channel_layout, c->sample_rate, NbSamples);
|
||||
m_AudioStream.m_vpFrames.clear();
|
||||
m_AudioStream.m_vpFrames.reserve(m_AudioThreads);
|
||||
|
||||
m_AudioStream.pTmpFrame = AllocAudioFrame(AV_SAMPLE_FMT_S16, AV_CH_LAYOUT_STEREO, g_Config.m_SndRate, m_SndBufferSize * 2);
|
||||
m_AudioStream.m_vpTmpFrames.clear();
|
||||
m_AudioStream.m_vpTmpFrames.reserve(m_AudioThreads);
|
||||
|
||||
/* allocate and init a re-usable frame */
|
||||
for(size_t i = 0; i < m_AudioThreads; ++i)
|
||||
{
|
||||
m_AudioStream.m_vpFrames.emplace_back(nullptr);
|
||||
m_AudioStream.m_vpFrames[i] = AllocAudioFrame(c->sample_fmt, c->channel_layout, c->sample_rate, NbSamples);
|
||||
if(!m_AudioStream.m_vpFrames[i])
|
||||
{
|
||||
dbg_msg("video_recorder", "Could not allocate audio frame");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_AudioStream.m_vpTmpFrames.emplace_back(nullptr);
|
||||
m_AudioStream.m_vpTmpFrames[i] = AllocAudioFrame(AV_SAMPLE_FMT_S16, AV_CH_LAYOUT_STEREO, g_Config.m_SndRate, NbSamples);
|
||||
if(!m_AudioStream.m_vpTmpFrames[i])
|
||||
{
|
||||
dbg_msg("video_recorder", "Could not allocate audio frame");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy the stream parameters to the muxer */
|
||||
Ret = avcodec_parameters_from_context(m_AudioStream.pSt->codecpar, c);
|
||||
|
@ -534,28 +759,34 @@ bool CVideo::OpenAudio()
|
|||
}
|
||||
|
||||
/* create resampler context */
|
||||
m_AudioStream.pSwrCtx = swr_alloc();
|
||||
if(!m_AudioStream.pSwrCtx)
|
||||
m_AudioStream.m_vpSwrCtxs.clear();
|
||||
m_AudioStream.m_vpSwrCtxs.reserve(m_AudioThreads);
|
||||
for(size_t i = 0; i < m_AudioThreads; ++i)
|
||||
{
|
||||
dbg_msg("video_recorder", "Could not allocate resampler context");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* set options */
|
||||
av_opt_set_int(m_AudioStream.pSwrCtx, "in_channel_count", 2, 0);
|
||||
av_opt_set_int(m_AudioStream.pSwrCtx, "in_sample_rate", g_Config.m_SndRate, 0);
|
||||
av_opt_set_sample_fmt(m_AudioStream.pSwrCtx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
|
||||
av_opt_set_int(m_AudioStream.pSwrCtx, "out_channel_count", c->channels, 0);
|
||||
av_opt_set_int(m_AudioStream.pSwrCtx, "out_sample_rate", c->sample_rate, 0);
|
||||
av_opt_set_sample_fmt(m_AudioStream.pSwrCtx, "out_sample_fmt", c->sample_fmt, 0);
|
||||
|
||||
/* initialize the resampling context */
|
||||
if(swr_init(m_AudioStream.pSwrCtx) < 0)
|
||||
{
|
||||
dbg_msg("video_recorder", "Failed to initialize the resampling context");
|
||||
return false;
|
||||
m_AudioStream.m_vpSwrCtxs[i] = swr_alloc();
|
||||
if(!m_AudioStream.m_vpSwrCtxs[i])
|
||||
{
|
||||
dbg_msg("video_recorder", "Could not allocate resampler context");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* set options */
|
||||
av_opt_set_int(m_AudioStream.m_vpSwrCtxs[i], "in_channel_count", 2, 0);
|
||||
av_opt_set_int(m_AudioStream.m_vpSwrCtxs[i], "in_sample_rate", g_Config.m_SndRate, 0);
|
||||
av_opt_set_sample_fmt(m_AudioStream.m_vpSwrCtxs[i], "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
|
||||
av_opt_set_int(m_AudioStream.m_vpSwrCtxs[i], "out_channel_count", c->channels, 0);
|
||||
av_opt_set_int(m_AudioStream.m_vpSwrCtxs[i], "out_sample_rate", c->sample_rate, 0);
|
||||
av_opt_set_sample_fmt(m_AudioStream.m_vpSwrCtxs[i], "out_sample_fmt", c->sample_fmt, 0);
|
||||
|
||||
/* initialize the resampling context */
|
||||
if(swr_init(m_AudioStream.m_vpSwrCtxs[i]) < 0)
|
||||
{
|
||||
dbg_msg("video_recorder", "Failed to initialize the resampling context");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_ASeq = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -591,18 +822,8 @@ bool CVideo::AddStream(OutputStream *pStream, AVFormatContext *pOC, const AVCode
|
|||
switch((*ppCodec)->type)
|
||||
{
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
|
||||
// m_MixingRate = g_Config.m_SndRate;
|
||||
//
|
||||
// // Set 16-bit stereo audio at 22Khz
|
||||
// Format.freq = g_Config.m_SndRate;
|
||||
// Format.format = AUDIO_S16;
|
||||
// Format.channels = 2;
|
||||
// Format.samples = g_Config.m_SndBufferSize;
|
||||
|
||||
c->sample_fmt = (*ppCodec)->sample_fmts ? (*ppCodec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
|
||||
c->bit_rate = g_Config.m_SndRate * 2 * 16;
|
||||
c->frame_size = m_SndBufferSize;
|
||||
c->sample_rate = g_Config.m_SndRate;
|
||||
if((*ppCodec)->supported_samplerates)
|
||||
{
|
||||
|
@ -610,7 +831,10 @@ bool CVideo::AddStream(OutputStream *pStream, AVFormatContext *pOC, const AVCode
|
|||
for(int i = 0; (*ppCodec)->supported_samplerates[i]; i++)
|
||||
{
|
||||
if((*ppCodec)->supported_samplerates[i] == g_Config.m_SndRate)
|
||||
{
|
||||
c->sample_rate = g_Config.m_SndRate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
c->channels = 2;
|
||||
|
@ -670,7 +894,7 @@ bool CVideo::AddStream(OutputStream *pStream, AVFormatContext *pOC, const AVCode
|
|||
return true;
|
||||
}
|
||||
|
||||
void CVideo::WriteFrame(OutputStream *pStream)
|
||||
void CVideo::WriteFrame(OutputStream *pStream, size_t ThreadIndex)
|
||||
{
|
||||
int RetRecv = 0;
|
||||
|
||||
|
@ -684,7 +908,7 @@ void CVideo::WriteFrame(OutputStream *pStream)
|
|||
pPacket->data = 0;
|
||||
pPacket->size = 0;
|
||||
|
||||
avcodec_send_frame(pStream->pEnc, pStream->pFrame);
|
||||
avcodec_send_frame(pStream->pEnc, pStream->m_vpFrames[ThreadIndex]);
|
||||
do
|
||||
{
|
||||
RetRecv = avcodec_receive_packet(pStream->pEnc, pPacket);
|
||||
|
@ -761,10 +985,21 @@ void CVideo::FinishFrames(OutputStream *pStream)
|
|||
void CVideo::CloseStream(OutputStream *pStream)
|
||||
{
|
||||
avcodec_free_context(&pStream->pEnc);
|
||||
av_frame_free(&pStream->pFrame);
|
||||
av_frame_free(&pStream->pTmpFrame);
|
||||
sws_freeContext(pStream->pSwsCtx);
|
||||
swr_free(&pStream->pSwrCtx);
|
||||
for(auto *pFrame : pStream->m_vpFrames)
|
||||
av_frame_free(&pFrame);
|
||||
pStream->m_vpFrames.clear();
|
||||
|
||||
for(auto *pFrame : pStream->m_vpTmpFrames)
|
||||
av_frame_free(&pFrame);
|
||||
pStream->m_vpTmpFrames.clear();
|
||||
|
||||
for(auto *pSwsContext : pStream->m_vpSwsCtxs)
|
||||
sws_freeContext(pSwsContext);
|
||||
pStream->m_vpSwsCtxs.clear();
|
||||
|
||||
for(auto *pSwrContext : pStream->m_vpSwrCtxs)
|
||||
swr_free(&pSwrContext);
|
||||
pStream->m_vpSwrCtxs.clear();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,12 @@ extern "C" {
|
|||
|
||||
#include <engine/shared/demo.h>
|
||||
#include <engine/shared/video.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#define ALEN 2048
|
||||
|
||||
extern LOCK g_WriteLock;
|
||||
|
@ -23,24 +29,25 @@ extern LOCK g_WriteLock;
|
|||
// a wrapper around a single output AVStream
|
||||
typedef struct OutputStream
|
||||
{
|
||||
AVStream *pSt;
|
||||
AVCodecContext *pEnc;
|
||||
AVStream *pSt = nullptr;
|
||||
AVCodecContext *pEnc = nullptr;
|
||||
|
||||
/* pts of the next frame that will be generated */
|
||||
int64_t NextPts;
|
||||
int SamplesCount;
|
||||
int64_t NextPts = 0;
|
||||
int64_t m_SamplesCount = 0;
|
||||
int64_t m_SamplesFrameCount = 0;
|
||||
|
||||
AVFrame *pFrame;
|
||||
AVFrame *pTmpFrame;
|
||||
std::vector<AVFrame *> m_vpFrames;
|
||||
std::vector<AVFrame *> m_vpTmpFrames;
|
||||
|
||||
struct SwsContext *pSwsCtx;
|
||||
struct SwrContext *pSwrCtx;
|
||||
std::vector<struct SwsContext *> m_vpSwsCtxs;
|
||||
std::vector<struct SwrContext *> m_vpSwrCtxs;
|
||||
} OutputStream;
|
||||
|
||||
class CVideo : public IVideo
|
||||
{
|
||||
public:
|
||||
CVideo(class CGraphics_Threaded *pGraphics, class IStorage *pStorage, class IConsole *pConsole, int width, int height, const char *name);
|
||||
CVideo(class CGraphics_Threaded *pGraphics, class ISound *pSound, class IStorage *pStorage, class IConsole *pConsole, int width, int height, const char *name);
|
||||
~CVideo();
|
||||
|
||||
virtual void Start();
|
||||
|
@ -50,28 +57,28 @@ public:
|
|||
|
||||
virtual void NextVideoFrame();
|
||||
virtual void NextVideoFrameThread();
|
||||
virtual bool FrameRendered() { return !m_NextFrame; }
|
||||
|
||||
virtual void NextAudioFrame(void (*Mix)(short *pFinalOut, unsigned Frames));
|
||||
virtual void NextAudioFrameTimeline();
|
||||
virtual bool AudioFrameRendered() { return !m_NextAudioFrame; }
|
||||
virtual void NextAudioFrame(ISoundMixFunc Mix);
|
||||
virtual void NextAudioFrameTimeline(ISoundMixFunc Mix);
|
||||
|
||||
static IVideo *Current() { return IVideo::ms_pCurrentVideo; }
|
||||
|
||||
static void Init() { av_log_set_level(AV_LOG_DEBUG); }
|
||||
|
||||
private:
|
||||
void FillVideoFrame();
|
||||
void ReadRGBFromGL();
|
||||
void RunVideoThread(size_t ParentThreadIndex, size_t ThreadIndex);
|
||||
void FillVideoFrame(size_t ThreadIndex);
|
||||
void ReadRGBFromGL(size_t ThreadIndex);
|
||||
|
||||
void FillAudioFrame();
|
||||
void RunAudioThread(size_t ParentThreadIndex, size_t ThreadIndex);
|
||||
void FillAudioFrame(size_t ThreadIndex);
|
||||
|
||||
bool OpenVideo();
|
||||
bool OpenAudio();
|
||||
AVFrame *AllocPicture(enum AVPixelFormat PixFmt, int Width, int Height);
|
||||
AVFrame *AllocAudioFrame(enum AVSampleFormat SampleFmt, uint64_t ChannelLayout, int SampleRate, int NbSamples);
|
||||
|
||||
void WriteFrame(OutputStream *pStream) REQUIRES(g_WriteLock);
|
||||
void WriteFrame(OutputStream *pStream, size_t ThreadIndex) REQUIRES(g_WriteLock);
|
||||
void FinishFrames(OutputStream *pStream);
|
||||
void CloseStream(OutputStream *pStream);
|
||||
|
||||
|
@ -79,30 +86,74 @@ private:
|
|||
|
||||
class CGraphics_Threaded *m_pGraphics;
|
||||
class IStorage *m_pStorage;
|
||||
class IConsole *m_pConsole;
|
||||
class ISound *m_pSound;
|
||||
|
||||
int m_Width;
|
||||
int m_Height;
|
||||
char m_Name[256];
|
||||
//FILE *m_dbgfile;
|
||||
int m_Vseq;
|
||||
short m_aBuffer[ALEN * 2];
|
||||
int m_Vframe;
|
||||
uint64_t m_VSeq = 0;
|
||||
uint64_t m_ASeq = 0;
|
||||
uint64_t m_Vframe;
|
||||
|
||||
int m_FPS;
|
||||
|
||||
bool m_Started;
|
||||
bool m_Recording;
|
||||
|
||||
bool m_ProcessingVideoFrame;
|
||||
bool m_ProcessingAudioFrame;
|
||||
size_t m_VideoThreads = 2;
|
||||
size_t m_CurVideoThreadIndex = 0;
|
||||
size_t m_AudioThreads = 2;
|
||||
size_t m_CurAudioThreadIndex = 0;
|
||||
|
||||
bool m_NextFrame;
|
||||
bool m_NextAudioFrame;
|
||||
struct SVideoRecorderThread
|
||||
{
|
||||
std::thread m_Thread;
|
||||
std::mutex m_Mutex;
|
||||
std::condition_variable m_Cond;
|
||||
|
||||
bool m_Started = false;
|
||||
bool m_Finished = false;
|
||||
bool m_HasVideoFrame = false;
|
||||
|
||||
std::mutex m_VideoFillMutex;
|
||||
std::condition_variable m_VideoFillCond;
|
||||
uint64_t m_VideoFrameToFill = 0;
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<SVideoRecorderThread>> m_vVideoThreads;
|
||||
|
||||
struct SAudioRecorderThread
|
||||
{
|
||||
std::thread m_Thread;
|
||||
std::mutex m_Mutex;
|
||||
std::condition_variable m_Cond;
|
||||
|
||||
bool m_Started = false;
|
||||
bool m_Finished = false;
|
||||
bool m_HasAudioFrame = false;
|
||||
|
||||
std::mutex m_AudioFillMutex;
|
||||
std::condition_variable m_AudioFillCond;
|
||||
uint64_t m_AudioFrameToFill = 0;
|
||||
int64_t m_SampleCountStart = 0;
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<SAudioRecorderThread>> m_vAudioThreads;
|
||||
|
||||
std::atomic<int32_t> m_ProcessingVideoFrame;
|
||||
std::atomic<int32_t> m_ProcessingAudioFrame;
|
||||
|
||||
std::atomic<bool> m_NextFrame;
|
||||
|
||||
bool m_HasAudio;
|
||||
|
||||
TWGLubyte *m_pPixels;
|
||||
struct SVideoSoundBuffer
|
||||
{
|
||||
int16_t m_aBuffer[ALEN * 2];
|
||||
};
|
||||
std::vector<SVideoSoundBuffer> m_vBuffer;
|
||||
std::vector<std::vector<uint8_t>> m_vPixelHelper;
|
||||
|
||||
OutputStream m_VideoStream;
|
||||
OutputStream m_AudioStream;
|
||||
|
@ -114,10 +165,6 @@ private:
|
|||
|
||||
AVFormatContext *m_pFormatContext;
|
||||
const AVOutputFormat *m_pFormat;
|
||||
|
||||
uint8_t *m_pRGB;
|
||||
|
||||
int m_SndBufferSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
struct SBufferContainerInfo
|
||||
{
|
||||
int m_Stride;
|
||||
int m_VertBufferBindingIndex;
|
||||
|
||||
// the attributes of the container
|
||||
struct SAttribute
|
||||
|
@ -32,8 +33,6 @@ struct SBufferContainerInfo
|
|||
|
||||
//0: float, 1:integer
|
||||
unsigned int m_FuncType;
|
||||
|
||||
int m_VertBufferBindingIndex;
|
||||
};
|
||||
std::vector<SAttribute> m_Attributes;
|
||||
};
|
||||
|
@ -43,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
|
||||
|
@ -69,7 +70,7 @@ public:
|
|||
FORMAT_AUTO = -1,
|
||||
FORMAT_RGB = 0,
|
||||
FORMAT_RGBA = 1,
|
||||
FORMAT_ALPHA = 2,
|
||||
FORMAT_SINGLE_COMPONENT = 2,
|
||||
};
|
||||
|
||||
/* Variable: width
|
||||
|
@ -152,19 +153,51 @@ 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
|
||||
{
|
||||
struct STWGraphicGPUItem
|
||||
{
|
||||
char m_Name[256];
|
||||
bool m_IsDiscreteGPU;
|
||||
};
|
||||
std::vector<STWGraphicGPUItem> m_GPUs;
|
||||
STWGraphicGPUItem m_AutoGPU;
|
||||
};
|
||||
|
||||
typedef STWGraphicGPU TTWGraphicsGPUList;
|
||||
|
||||
typedef std::function<void(void *)> WINDOW_RESIZE_FUNC;
|
||||
|
||||
namespace client_data7 {
|
||||
struct CDataSprite; // NOLINT(bugprone-forward-declaration-namespace)
|
||||
}
|
||||
|
||||
typedef std::function<bool(uint32_t &Width, uint32_t &Height, uint32_t &Format, std::vector<uint8_t> &DstData)> TGLBackendReadPresentedImageData;
|
||||
|
||||
class IGraphics : public IInterface
|
||||
{
|
||||
MACRO_INTERFACE("graphics", 0)
|
||||
|
@ -221,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;
|
||||
|
@ -235,7 +269,13 @@ public:
|
|||
virtual void BlendAdditive() = 0;
|
||||
virtual void WrapNormal() = 0;
|
||||
virtual void WrapClamp() = 0;
|
||||
virtual int MemoryUsage() const = 0;
|
||||
|
||||
virtual uint64_t TextureMemoryUsage() const = 0;
|
||||
virtual uint64_t BufferMemoryUsage() const = 0;
|
||||
virtual uint64_t StreamedMemoryUsage() const = 0;
|
||||
virtual uint64_t StagingMemoryUsage() const = 0;
|
||||
|
||||
virtual const TTWGraphicsGPUList &GetGPUs() const = 0;
|
||||
|
||||
virtual int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) = 0;
|
||||
virtual void FreePNG(CImageInfo *pImg) = 0;
|
||||
|
@ -256,6 +296,11 @@ public:
|
|||
virtual void TextureSet(CTextureHandle Texture) = 0;
|
||||
void TextureClear() { TextureSet(CTextureHandle()); }
|
||||
|
||||
// pTextData & pTextOutlineData are automatically free'd
|
||||
virtual bool LoadTextTextures(int Width, int Height, CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture, void *pTextData, void *pTextOutlineData) = 0;
|
||||
virtual bool UnloadTextTextures(CTextureHandle &TextTexture, CTextureHandle &TextOutlineTexture) = 0;
|
||||
virtual bool UpdateTextTexture(CTextureHandle TextureID, int x, int y, int Width, int Height, const void *pData) = 0;
|
||||
|
||||
virtual CTextureHandle LoadSpriteTexture(CImageInfo &FromImageInfo, struct CDataSprite *pSprite) = 0;
|
||||
virtual CTextureHandle LoadSpriteTexture(CImageInfo &FromImageInfo, struct client_data7::CDataSprite *pSprite) = 0;
|
||||
|
||||
|
@ -263,31 +308,35 @@ public:
|
|||
virtual bool IsSpriteTextureFullyTransparent(CImageInfo &FromImageInfo, struct client_data7::CDataSprite *pSprite) = 0;
|
||||
|
||||
virtual void FlushVertices(bool KeepVertices = false) = 0;
|
||||
virtual void FlushTextVertices(int TextureSize, int TextTextureIndex, int TextOutlineTextureIndex, float *pOutlineTextColor) = 0;
|
||||
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;
|
||||
virtual void RenderText(int BufferContainerIndex, int TextQuadNum, int TextureSize, int TextureTextIndex, int TextureTextOutlineIndex, float *pTextColor, float *pTextoutlineColor) = 0;
|
||||
|
||||
// opengl 3.3 functions
|
||||
|
||||
enum EBufferObjectCreateFlags
|
||||
{
|
||||
// tell the backend that the buffer only needs to be valid for the span of one frame. Buffer size is not allowed to be bigger than GL_SVertex * MAX_VERTICES
|
||||
BUFFER_OBJECT_CREATE_FLAGS_ONE_TIME_USE_BIT = 1 << 0,
|
||||
};
|
||||
|
||||
// if a pointer is passed as moved pointer, it requires to be allocated with malloc()
|
||||
virtual int CreateBufferObject(size_t UploadDataSize, void *pUploadData, bool IsMovedPointer = false) = 0;
|
||||
virtual void RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, bool IsMovedPointer = false) = 0;
|
||||
virtual void UpdateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, void *pOffset, bool IsMovedPointer = false) = 0;
|
||||
virtual void CopyBufferObject(int WriteBufferIndex, int ReadBufferIndex, size_t WriteOffset, size_t ReadOffset, size_t CopyDataSize) = 0;
|
||||
virtual int CreateBufferObject(size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) = 0;
|
||||
virtual void RecreateBufferObject(int BufferIndex, size_t UploadDataSize, void *pUploadData, int CreateFlags, bool IsMovedPointer = false) = 0;
|
||||
virtual void DeleteBufferObject(int BufferIndex) = 0;
|
||||
|
||||
virtual int CreateBufferContainer(struct SBufferContainerInfo *pContainerInfo) = 0;
|
||||
// destroying all buffer objects means, that all referenced VBOs are destroyed automatically, so the user does not need to save references to them
|
||||
virtual void DeleteBufferContainer(int ContainerIndex, bool DestroyAllBO = true) = 0;
|
||||
virtual void UpdateBufferContainer(int ContainerIndex, struct SBufferContainerInfo *pContainerInfo) = 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;
|
||||
|
@ -312,8 +361,6 @@ public:
|
|||
|
||||
virtual void QuadsBegin() = 0;
|
||||
virtual void QuadsEnd() = 0;
|
||||
virtual void TextQuadsBegin() = 0;
|
||||
virtual void TextQuadsEnd(int TextureSize, int TextTextureIndex, int TextOutlineTextureIndex, float *pOutlineTextColor) = 0;
|
||||
virtual void QuadsTex3DBegin() = 0;
|
||||
virtual void QuadsTex3DEnd() = 0;
|
||||
virtual void TrianglesBegin() = 0;
|
||||
|
@ -413,6 +460,10 @@ public:
|
|||
virtual void SetWindowGrab(bool Grab) = 0;
|
||||
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;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -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, 1, CFGFLAG_CLIENT, "Show OpenGL warnings and errors, if the GPU supports it")
|
||||
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)")
|
||||
|
@ -307,8 +307,8 @@ MACRO_CONFIG_INT(ClShowOthersAlpha, cl_show_others_alpha, 40, 0, 100, CFGFLAG_CL
|
|||
MACRO_CONFIG_INT(ClOverlayEntities, cl_overlay_entities, 0, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Overlay game tiles with a percentage of opacity")
|
||||
MACRO_CONFIG_INT(ClShowQuads, cl_show_quads, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show quads")
|
||||
MACRO_CONFIG_INT(ClZoomBackgroundLayers, cl_zoom_background_layers, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Zoom background layers")
|
||||
MACRO_CONFIG_COL(ClBackgroundColor, cl_background_color, 128, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background color") //0 0 128
|
||||
MACRO_CONFIG_COL(ClBackgroundEntitiesColor, cl_background_entities_color, 128, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background (entities) color") //0 0 128
|
||||
MACRO_CONFIG_COL(ClBackgroundColor, cl_background_color, 128, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background color") // 0 0 128
|
||||
MACRO_CONFIG_COL(ClBackgroundEntitiesColor, cl_background_entities_color, 128, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background (entities) color") // 0 0 128
|
||||
MACRO_CONFIG_STR(ClBackgroundEntities, cl_background_entities, 100, "", CFGFLAG_CLIENT | CFGFLAG_SAVE, "Background (entities)")
|
||||
MACRO_CONFIG_STR(ClRunOnJoin, cl_run_on_join, 100, "", CFGFLAG_CLIENT | CFGFLAG_SAVE | CFGFLAG_INSENSITIVE, "Command to run when joining a server")
|
||||
|
||||
|
@ -401,22 +401,26 @@ MACRO_CONFIG_INT(ClDemoSliceEnd, cl_demo_slice_end, -1, 0, 0, CFGFLAG_SAVE | CFG
|
|||
MACRO_CONFIG_INT(ClDemoShowSpeed, cl_demo_show_speed, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Show speed meter on change")
|
||||
MACRO_CONFIG_INT(ClDemoKeyboardShortcuts, cl_demo_keyboard_shortcuts, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Enable keyboard shortcuts in demo player")
|
||||
|
||||
// opengl
|
||||
// graphic library
|
||||
#ifndef CONF_ARCH_IA32
|
||||
MACRO_CONFIG_INT(GfxOpenGLMajor, gfx_opengl_major, 3, 1, 10, CFGFLAG_SAVE | CFGFLAG_CLIENT, "OpenGL major version")
|
||||
MACRO_CONFIG_INT(GfxGLMajor, gfx_gl_major, 3, 1, 10, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Graphic library major version")
|
||||
#else
|
||||
MACRO_CONFIG_INT(GfxOpenGLMajor, gfx_opengl_major, 1, 1, 10, CFGFLAG_SAVE | CFGFLAG_CLIENT, "OpenGL major version")
|
||||
MACRO_CONFIG_INT(GfxGLMajor, gfx_gl_major, 1, 1, 10, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Graphic library major version")
|
||||
#endif
|
||||
MACRO_CONFIG_INT(GfxOpenGLMinor, gfx_opengl_minor, 0, 0, 10, CFGFLAG_SAVE | CFGFLAG_CLIENT, "OpenGL minor version")
|
||||
MACRO_CONFIG_INT(GfxOpenGLPatch, gfx_opengl_patch, 0, 0, 10, CFGFLAG_SAVE | CFGFLAG_CLIENT, "OpenGL patch version")
|
||||
MACRO_CONFIG_INT(GfxGLMinor, gfx_gl_minor, 0, 0, 10, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Graphic library minor version")
|
||||
MACRO_CONFIG_INT(GfxGLPatch, gfx_gl_patch, 0, 0, 10, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Graphic library patch version")
|
||||
|
||||
// float multiplied with 1000
|
||||
MACRO_CONFIG_INT(GfxOpenGLTextureLODBIAS, gfx_opengl_texture_lod_bias, -500, -15000, 15000, CFGFLAG_SAVE | CFGFLAG_CLIENT, "The lod bias for OpenGL texture sampling multiplied by 1000")
|
||||
MACRO_CONFIG_INT(GfxGLTextureLODBIAS, gfx_gl_texture_lod_bias, -500, -15000, 15000, CFGFLAG_SAVE | CFGFLAG_CLIENT, "The lod bias for graphic library texture sampling multiplied by 1000")
|
||||
|
||||
MACRO_CONFIG_INT(Gfx3DTextureAnalysisDone, gfx_3d_texture_analysis_done, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Analyzed, if sampling 3D/2D array textures was correct")
|
||||
MACRO_CONFIG_STR(Gfx3DTextureAnalysisRenderer, gfx_3d_texture_analysis_renderer, 128, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The renderer on which the analysis was performed")
|
||||
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, "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.")
|
||||
#if !defined(CONF_PLATFORM_MACOS)
|
||||
MACRO_CONFIG_INT(GfxEnableTextureUnitOptimization, gfx_enable_texture_unit_optimization, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Use multiple texture units, instead of only one.")
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <base/system.h>
|
||||
|
||||
typedef void (*ISoundMixFunc)(short *pFinalOut, unsigned Frames);
|
||||
|
||||
class IVideo
|
||||
{
|
||||
public:
|
||||
|
@ -14,12 +16,10 @@ public:
|
|||
virtual bool IsRecording() = 0;
|
||||
|
||||
virtual void NextVideoFrame() = 0;
|
||||
virtual bool FrameRendered() = 0;
|
||||
virtual void NextVideoFrameThread() = 0;
|
||||
|
||||
virtual void NextAudioFrame(void (*Mix)(short *pFinalOut, unsigned Frames)) = 0;
|
||||
virtual bool AudioFrameRendered() = 0;
|
||||
virtual void NextAudioFrameTimeline() = 0;
|
||||
virtual void NextAudioFrameTimeline(ISoundMixFunc Mix) = 0;
|
||||
|
||||
static IVideo *Current() { return ms_pCurrentVideo; }
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "kernel.h"
|
||||
|
||||
#include <engine/shared/video.h>
|
||||
|
||||
class ISound : public IInterface
|
||||
{
|
||||
MACRO_INTERFACE("sound", 0)
|
||||
|
@ -86,6 +88,11 @@ public:
|
|||
virtual void StopAll() = 0;
|
||||
virtual void StopVoice(CVoiceHandle Voice) = 0;
|
||||
|
||||
virtual ISoundMixFunc GetSoundMixFunc() = 0;
|
||||
// useful for thread synchronization
|
||||
virtual void PauseAudioDevice() = 0;
|
||||
virtual void UnpauseAudioDevice() = 0;
|
||||
|
||||
protected:
|
||||
inline CVoiceHandle CreateVoiceHandle(int Index, int Age)
|
||||
{
|
||||
|
|
|
@ -33,6 +33,8 @@ enum ETextRenderFlags
|
|||
TEXT_RENDER_FLAG_NO_FIRST_CHARACTER_X_BEARING = 1 << 6,
|
||||
TEXT_RENDER_FLAG_NO_LAST_CHARACTER_ADVANCE = 1 << 7,
|
||||
TEXT_RENDER_FLAG_NO_AUTOMATIC_QUAD_UPLOAD = 1 << 8,
|
||||
// text is only rendered once and then discarded (a hint for buffer creation)
|
||||
TEXT_RENDER_FLAG_ONE_TIME_USE = 1 << 9,
|
||||
};
|
||||
|
||||
enum
|
||||
|
|
|
@ -553,9 +553,13 @@ void CHud::RenderTextInfo()
|
|||
CTextCursor Cursor;
|
||||
TextRender()->SetCursor(&Cursor, m_Width - 10 - s_TextWidth[DigitIndex], 5, 12, TEXTFLAG_RENDER);
|
||||
Cursor.m_LineWidth = -1;
|
||||
auto OldFlags = TextRender()->GetRenderFlags();
|
||||
TextRender()->SetRenderFlags(OldFlags | TEXT_RENDER_FLAG_ONE_TIME_USE);
|
||||
if(m_FPSTextContainerIndex == -1)
|
||||
m_FPSTextContainerIndex = TextRender()->CreateTextContainer(&Cursor, "0");
|
||||
TextRender()->RecreateTextContainerSoft(&Cursor, m_FPSTextContainerIndex, aBuf);
|
||||
else
|
||||
TextRender()->RecreateTextContainerSoft(&Cursor, m_FPSTextContainerIndex, aBuf);
|
||||
TextRender()->SetRenderFlags(OldFlags);
|
||||
STextRenderColor TColor;
|
||||
TColor.m_R = 1.f;
|
||||
TColor.m_G = 1.f;
|
||||
|
|
|
@ -189,7 +189,9 @@ IGraphics::CTextureHandle CMapImages::GetEntities(EMapImageEntityLayerType Entit
|
|||
bool GameTypeHasTeleLayer = HasTeleLayer(EntitiesModType) || WasUnknwon;
|
||||
bool GameTypeHasTuneLayer = HasTuneLayer(EntitiesModType) || WasUnknwon;
|
||||
|
||||
int TextureLoadFlag = Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
|
||||
int TextureLoadFlag = 0;
|
||||
if(Graphics()->IsTileBufferingEnabled())
|
||||
TextureLoadFlag = (Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE) | IGraphics::TEXLOAD_NO_2D_TEXTURE;
|
||||
|
||||
CImageInfo ImgInfo;
|
||||
bool ImagePNGLoaded = false;
|
||||
|
@ -223,7 +225,7 @@ IGraphics::CTextureHandle CMapImages::GetEntities(EMapImageEntityLayerType Entit
|
|||
if(ImagePNGLoaded && ImgInfo.m_Width > 0 && ImgInfo.m_Height > 0)
|
||||
{
|
||||
int ColorChannelCount = 4;
|
||||
if(ImgInfo.m_Format == CImageInfo::FORMAT_ALPHA)
|
||||
if(ImgInfo.m_Format == CImageInfo::FORMAT_SINGLE_COMPONENT)
|
||||
ColorChannelCount = 1;
|
||||
else if(ImgInfo.m_Format == CImageInfo::FORMAT_RGB)
|
||||
ColorChannelCount = 3;
|
||||
|
|
|
@ -839,11 +839,12 @@ void CMapLayers::OnMapLoad()
|
|||
}
|
||||
|
||||
// first create the buffer object
|
||||
int BufferObjectIndex = Graphics()->CreateBufferObject(UploadDataSize, pUploadData, true);
|
||||
int BufferObjectIndex = Graphics()->CreateBufferObject(UploadDataSize, pUploadData, 0, true);
|
||||
|
||||
// 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;
|
||||
|
@ -851,7 +852,6 @@ void CMapLayers::OnMapLoad()
|
|||
pAttr->m_Normalized = false;
|
||||
pAttr->m_pOffset = 0;
|
||||
pAttr->m_FuncType = 0;
|
||||
pAttr->m_VertBufferBindingIndex = BufferObjectIndex;
|
||||
if(DoTextureCoords)
|
||||
{
|
||||
ContainerInfo.m_Attributes.emplace_back();
|
||||
|
@ -861,7 +861,6 @@ void CMapLayers::OnMapLoad()
|
|||
pAttr->m_Normalized = false;
|
||||
pAttr->m_pOffset = (void *)(sizeof(vec2));
|
||||
pAttr->m_FuncType = 0;
|
||||
pAttr->m_VertBufferBindingIndex = BufferObjectIndex;
|
||||
}
|
||||
|
||||
Visuals.m_BufferContainerIndex = Graphics()->CreateBufferContainer(&ContainerInfo);
|
||||
|
@ -944,10 +943,11 @@ void CMapLayers::OnMapLoad()
|
|||
else
|
||||
pUploadData = &tmpQuads[0];
|
||||
// create the buffer object
|
||||
int BufferObjectIndex = Graphics()->CreateBufferObject(UploadDataSize, pUploadData);
|
||||
int BufferObjectIndex = Graphics()->CreateBufferObject(UploadDataSize, pUploadData, 0);
|
||||
// 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;
|
||||
|
@ -955,7 +955,6 @@ void CMapLayers::OnMapLoad()
|
|||
pAttr->m_Normalized = false;
|
||||
pAttr->m_pOffset = 0;
|
||||
pAttr->m_FuncType = 0;
|
||||
pAttr->m_VertBufferBindingIndex = BufferObjectIndex;
|
||||
ContainerInfo.m_Attributes.emplace_back();
|
||||
pAttr = &ContainerInfo.m_Attributes.back();
|
||||
pAttr->m_DataTypeCount = 4;
|
||||
|
@ -963,7 +962,6 @@ void CMapLayers::OnMapLoad()
|
|||
pAttr->m_Normalized = true;
|
||||
pAttr->m_pOffset = (void *)(sizeof(float) * 4);
|
||||
pAttr->m_FuncType = 0;
|
||||
pAttr->m_VertBufferBindingIndex = BufferObjectIndex;
|
||||
if(Textured)
|
||||
{
|
||||
ContainerInfo.m_Attributes.emplace_back();
|
||||
|
@ -973,7 +971,6 @@ void CMapLayers::OnMapLoad()
|
|||
pAttr->m_Normalized = false;
|
||||
pAttr->m_pOffset = (void *)(sizeof(float) * 4 + sizeof(unsigned char) * 4);
|
||||
pAttr->m_FuncType = 0;
|
||||
pAttr->m_VertBufferBindingIndex = BufferObjectIndex;
|
||||
}
|
||||
|
||||
pQLayerVisuals->m_BufferContainerIndex = Graphics()->CreateBufferContainer(&ContainerInfo);
|
||||
|
@ -1406,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++];
|
||||
|
@ -1414,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);
|
||||
}
|
||||
|
|
|
@ -24,13 +24,18 @@
|
|||
#include <game/client/ui.h>
|
||||
#include <game/localization.h>
|
||||
|
||||
#include "base/system.h"
|
||||
#include "binds.h"
|
||||
#include "camera.h"
|
||||
#include "countryflags.h"
|
||||
#include "menus.h"
|
||||
#include "skins.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <array>
|
||||
|
||||
CMenusKeyBinder CMenus::m_Binder;
|
||||
|
||||
|
@ -1097,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_GfxOpenGLVersion = 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;
|
||||
|
||||
|
@ -1182,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);
|
||||
|
@ -1211,12 +1216,12 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
|
|||
int NumScreens = Graphics()->GetNumScreens();
|
||||
MainView.HSplitTop(20.0f, &Button, &MainView);
|
||||
int Screen_MouseButton = DoButton_CheckBox_Number(&g_Config.m_GfxScreen, Localize("Screen"), g_Config.m_GfxScreen, &Button);
|
||||
if(Screen_MouseButton == 1) //inc
|
||||
if(Screen_MouseButton == 1) // inc
|
||||
{
|
||||
Client()->SwitchWindowScreen((g_Config.m_GfxScreen + 1) % NumScreens);
|
||||
s_NumNodes = Graphics()->GetVideoModes(s_aModes, MAX_RESOLUTIONS, g_Config.m_GfxScreen);
|
||||
}
|
||||
else if(Screen_MouseButton == 2) //dec
|
||||
else if(Screen_MouseButton == 2) // dec
|
||||
{
|
||||
Client()->SwitchWindowScreen((g_Config.m_GfxScreen - 1 + NumScreens) % NumScreens);
|
||||
s_NumNodes = Graphics()->GetVideoModes(s_aModes, MAX_RESOLUTIONS, g_Config.m_GfxScreen);
|
||||
|
@ -1226,12 +1231,12 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
|
|||
MainView.HSplitTop(20.0f, &Button, &MainView);
|
||||
str_format(aBuf, sizeof(aBuf), "%s (%s)", Localize("FSAA samples"), Localize("may cause delay"));
|
||||
int GfxFsaaSamples_MouseButton = DoButton_CheckBox_Number(&g_Config.m_GfxFsaaSamples, aBuf, g_Config.m_GfxFsaaSamples, &Button);
|
||||
if(GfxFsaaSamples_MouseButton == 1) //inc
|
||||
if(GfxFsaaSamples_MouseButton == 1) // inc
|
||||
{
|
||||
g_Config.m_GfxFsaaSamples = (g_Config.m_GfxFsaaSamples + 1) % 17;
|
||||
CheckSettings = true;
|
||||
}
|
||||
else if(GfxFsaaSamples_MouseButton == 2) //dec
|
||||
else if(GfxFsaaSamples_MouseButton == 2) // dec
|
||||
{
|
||||
g_Config.m_GfxFsaaSamples = (g_Config.m_GfxFsaaSamples - 1 + 17) % 17;
|
||||
CheckSettings = true;
|
||||
|
@ -1241,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 IsNewOpenGL = 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_GfxOpenGLMajor, Localize("Use modern OpenGL"), IsNewOpenGL, &Button))
|
||||
{
|
||||
CheckSettings = true;
|
||||
if(IsNewOpenGL)
|
||||
{
|
||||
Graphics()->GetDriverVersion(GRAPHICS_DRIVER_AGE_TYPE_DEFAULT, g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch);
|
||||
IsNewOpenGL = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Graphics()->GetDriverVersion(GRAPHICS_DRIVER_AGE_TYPE_MODERN, g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch);
|
||||
IsNewOpenGL = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(IsNewOpenGL)
|
||||
{
|
||||
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))
|
||||
{
|
||||
|
@ -1288,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_GfxOpenGLVersion == (int)IsNewOpenGL &&
|
||||
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)
|
||||
|
@ -1314,7 +1269,208 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
|
|||
MainView.HSplitTop(20.0f, &Text, &MainView);
|
||||
//text.VSplitLeft(15.0f, 0, &text);
|
||||
UI()->DoLabelScaled(&Text, Localize("UI Color"), 14.0f, TEXTALIGN_LEFT);
|
||||
RenderHSLScrollbars(&MainView, &g_Config.m_UiColor, true);
|
||||
CUIRect HSLBar = MainView;
|
||||
RenderHSLScrollbars(&HSLBar, &g_Config.m_UiColor, true);
|
||||
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("Graphics cards"), 16.0f, TEXTALIGN_CENTER);
|
||||
|
||||
static float s_ScrollValueDropGPU = 0;
|
||||
static int s_GPUDropDownState = 0;
|
||||
|
||||
static std::vector<std::unique_ptr<int>> vGPUIDs;
|
||||
static std::vector<const void *> vGPUIDPtrs;
|
||||
static std::vector<const char *> vGPUIDNames;
|
||||
|
||||
size_t GPUCount = GPUList.m_GPUs.size() + 1;
|
||||
vGPUIDs.resize(GPUCount);
|
||||
vGPUIDPtrs.resize(GPUCount);
|
||||
vGPUIDNames.resize(GPUCount);
|
||||
|
||||
char aCurDeviceName[256 + 4];
|
||||
|
||||
int OldSelectedGPU = -1;
|
||||
for(size_t i = 0; i < GPUCount; ++i)
|
||||
{
|
||||
if(vGPUIDs[i].get() == nullptr)
|
||||
vGPUIDs[i] = std::make_unique<int>();
|
||||
vGPUIDPtrs[i] = vGPUIDs[i].get();
|
||||
if(i == 0)
|
||||
{
|
||||
str_format(aCurDeviceName, sizeof(aCurDeviceName), "%s(%s)", Localize("auto"), GPUList.m_AutoGPU.m_Name);
|
||||
vGPUIDNames[i] = aCurDeviceName;
|
||||
if(str_comp("auto", g_Config.m_GfxGPUName) == 0)
|
||||
{
|
||||
OldSelectedGPU = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vGPUIDNames[i] = GPUList.m_GPUs[i - 1].m_Name;
|
||||
if(str_comp(GPUList.m_GPUs[i - 1].m_Name, g_Config.m_GfxGPUName) == 0)
|
||||
{
|
||||
OldSelectedGPU = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int s_GPUCount = 0;
|
||||
s_GPUCount = GPUCount;
|
||||
|
||||
const int NewGPU = RenderDropDown(s_GPUDropDownState, &MainView, OldSelectedGPU, vGPUIDPtrs.data(), vGPUIDNames.data(), s_GPUCount, &s_GPUCount, s_ScrollValueDropGPU);
|
||||
if(OldSelectedGPU != NewGPU)
|
||||
{
|
||||
if(NewGPU == 0)
|
||||
str_copy(g_Config.m_GfxGPUName, "auto", sizeof(g_Config.m_GfxGPUName));
|
||||
else
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
@ -6031,7 +6031,10 @@ void CEditor::Reset(bool CreateDefault)
|
|||
|
||||
// create default layers
|
||||
if(CreateDefault)
|
||||
m_Map.CreateDefault(m_EntitiesTexture);
|
||||
{
|
||||
m_EditorWasUsedBefore = true;
|
||||
m_Map.CreateDefault(GetEntitiesTexture());
|
||||
}
|
||||
|
||||
SelectGameLayer();
|
||||
m_lSelectedQuads.clear();
|
||||
|
@ -6141,7 +6144,7 @@ void CEditorMap::MakeGameLayer(CLayer *pLayer)
|
|||
{
|
||||
m_pGameLayer = (CLayerGame *)pLayer;
|
||||
m_pGameLayer->m_pEditor = m_pEditor;
|
||||
m_pGameLayer->m_Texture = m_pEditor->m_EntitiesTexture;
|
||||
m_pGameLayer->m_Texture = m_pEditor->GetEntitiesTexture();
|
||||
}
|
||||
|
||||
void CEditorMap::MakeGameGroup(CLayerGroup *pGroup)
|
||||
|
@ -6207,6 +6210,60 @@ void CEditorMap::CreateDefault(IGraphics::CTextureHandle EntitiesTexture)
|
|||
m_pTuneLayer = 0x0;
|
||||
}
|
||||
|
||||
int CEditor::GetTextureUsageFlag()
|
||||
{
|
||||
return Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle CEditor::GetFrontTexture()
|
||||
{
|
||||
int TextureLoadFlag = GetTextureUsageFlag();
|
||||
|
||||
if(!m_FrontTexture.IsValid())
|
||||
m_FrontTexture = Graphics()->LoadTexture("editor/front.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
return m_FrontTexture;
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle CEditor::GetTeleTexture()
|
||||
{
|
||||
int TextureLoadFlag = GetTextureUsageFlag();
|
||||
if(!m_TeleTexture.IsValid())
|
||||
m_TeleTexture = Graphics()->LoadTexture("editor/tele.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
return m_TeleTexture;
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle CEditor::GetSpeedupTexture()
|
||||
{
|
||||
int TextureLoadFlag = GetTextureUsageFlag();
|
||||
if(!m_SpeedupTexture.IsValid())
|
||||
m_SpeedupTexture = Graphics()->LoadTexture("editor/speedup.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
return m_SpeedupTexture;
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle CEditor::GetSwitchTexture()
|
||||
{
|
||||
int TextureLoadFlag = GetTextureUsageFlag();
|
||||
if(!m_SwitchTexture.IsValid())
|
||||
m_SwitchTexture = Graphics()->LoadTexture("editor/switch.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
return m_SwitchTexture;
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle CEditor::GetTuneTexture()
|
||||
{
|
||||
int TextureLoadFlag = GetTextureUsageFlag();
|
||||
if(!m_TuneTexture.IsValid())
|
||||
m_TuneTexture = Graphics()->LoadTexture("editor/tune.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
return m_TuneTexture;
|
||||
}
|
||||
|
||||
IGraphics::CTextureHandle CEditor::GetEntitiesTexture()
|
||||
{
|
||||
int TextureLoadFlag = GetTextureUsageFlag();
|
||||
if(!m_EntitiesTexture.IsValid())
|
||||
m_EntitiesTexture = Graphics()->LoadTexture("editor/entities/DDNet.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
return m_EntitiesTexture;
|
||||
}
|
||||
|
||||
void CEditor::Init()
|
||||
{
|
||||
m_pInput = Kernel()->RequestInterface<IInput>();
|
||||
|
@ -6227,14 +6284,6 @@ void CEditor::Init()
|
|||
m_CheckerTexture = Graphics()->LoadTexture("editor/checker.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);
|
||||
m_BackgroundTexture = Graphics()->LoadTexture("editor/background.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);
|
||||
m_CursorTexture = Graphics()->LoadTexture("editor/cursor.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);
|
||||
int TextureLoadFlag = Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
|
||||
m_EntitiesTexture = Graphics()->LoadTexture("editor/entities/DDNet.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
|
||||
m_FrontTexture = Graphics()->LoadTexture("editor/front.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
m_TeleTexture = Graphics()->LoadTexture("editor/tele.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
m_SpeedupTexture = Graphics()->LoadTexture("editor/speedup.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
m_SwitchTexture = Graphics()->LoadTexture("editor/switch.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
m_TuneTexture = Graphics()->LoadTexture("editor/tune.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
|
||||
m_TilesetPicker.m_pEditor = this;
|
||||
m_TilesetPicker.MakePalette();
|
||||
|
@ -6246,7 +6295,7 @@ void CEditor::Init()
|
|||
|
||||
m_Brush.m_pMap = &m_Map;
|
||||
|
||||
Reset();
|
||||
Reset(false);
|
||||
m_Map.m_Modified = false;
|
||||
|
||||
ms_PickerColor = ColorHSVA(1.0f, 0.0f, 0.0f);
|
||||
|
@ -6274,6 +6323,12 @@ void CEditor::UpdateAndRender()
|
|||
static float s_MouseX = 0.0f;
|
||||
static float s_MouseY = 0.0f;
|
||||
|
||||
if(!m_EditorWasUsedBefore)
|
||||
{
|
||||
m_EditorWasUsedBefore = true;
|
||||
Reset();
|
||||
}
|
||||
|
||||
if(m_Animate)
|
||||
m_AnimateTime = (time_get() - m_AnimateStart) / (float)time_freq();
|
||||
else
|
||||
|
@ -6369,33 +6424,33 @@ void CEditorMap::MakeTeleLayer(CLayer *pLayer)
|
|||
{
|
||||
m_pTeleLayer = (CLayerTele *)pLayer;
|
||||
m_pTeleLayer->m_pEditor = m_pEditor;
|
||||
m_pTeleLayer->m_Texture = m_pEditor->m_TeleTexture;
|
||||
m_pTeleLayer->m_Texture = m_pEditor->GetTeleTexture();
|
||||
}
|
||||
|
||||
void CEditorMap::MakeSpeedupLayer(CLayer *pLayer)
|
||||
{
|
||||
m_pSpeedupLayer = (CLayerSpeedup *)pLayer;
|
||||
m_pSpeedupLayer->m_pEditor = m_pEditor;
|
||||
m_pSpeedupLayer->m_Texture = m_pEditor->m_SpeedupTexture;
|
||||
m_pSpeedupLayer->m_Texture = m_pEditor->GetSpeedupTexture();
|
||||
}
|
||||
|
||||
void CEditorMap::MakeFrontLayer(CLayer *pLayer)
|
||||
{
|
||||
m_pFrontLayer = (CLayerFront *)pLayer;
|
||||
m_pFrontLayer->m_pEditor = m_pEditor;
|
||||
m_pFrontLayer->m_Texture = m_pEditor->m_FrontTexture;
|
||||
m_pFrontLayer->m_Texture = m_pEditor->GetFrontTexture();
|
||||
}
|
||||
|
||||
void CEditorMap::MakeSwitchLayer(CLayer *pLayer)
|
||||
{
|
||||
m_pSwitchLayer = (CLayerSwitch *)pLayer;
|
||||
m_pSwitchLayer->m_pEditor = m_pEditor;
|
||||
m_pSwitchLayer->m_Texture = m_pEditor->m_SwitchTexture;
|
||||
m_pSwitchLayer->m_Texture = m_pEditor->GetSwitchTexture();
|
||||
}
|
||||
|
||||
void CEditorMap::MakeTuneLayer(CLayer *pLayer)
|
||||
{
|
||||
m_pTuneLayer = (CLayerTune *)pLayer;
|
||||
m_pTuneLayer->m_pEditor = m_pEditor;
|
||||
m_pTuneLayer->m_Texture = m_pEditor->m_TuneTexture;
|
||||
m_pTuneLayer->m_Texture = m_pEditor->GetTuneTexture();
|
||||
}
|
||||
|
|
|
@ -641,6 +641,18 @@ class CEditor : public IEditor
|
|||
CUI m_UI;
|
||||
CUIEx m_UIEx;
|
||||
|
||||
bool m_EditorWasUsedBefore = false;
|
||||
|
||||
IGraphics::CTextureHandle m_EntitiesTexture;
|
||||
|
||||
IGraphics::CTextureHandle m_FrontTexture;
|
||||
IGraphics::CTextureHandle m_TeleTexture;
|
||||
IGraphics::CTextureHandle m_SpeedupTexture;
|
||||
IGraphics::CTextureHandle m_SwitchTexture;
|
||||
IGraphics::CTextureHandle m_TuneTexture;
|
||||
|
||||
int GetTextureUsageFlag();
|
||||
|
||||
public:
|
||||
class IInput *Input() { return m_pInput; }
|
||||
class IClient *Client() { return m_pClient; }
|
||||
|
@ -924,7 +936,8 @@ public:
|
|||
IGraphics::CTextureHandle m_CheckerTexture;
|
||||
IGraphics::CTextureHandle m_BackgroundTexture;
|
||||
IGraphics::CTextureHandle m_CursorTexture;
|
||||
IGraphics::CTextureHandle m_EntitiesTexture;
|
||||
|
||||
IGraphics::CTextureHandle GetEntitiesTexture();
|
||||
|
||||
CLayerGroup m_Brush;
|
||||
CLayerTiles m_TilesetPicker;
|
||||
|
@ -1134,11 +1147,12 @@ public:
|
|||
|
||||
// DDRace
|
||||
|
||||
IGraphics::CTextureHandle m_FrontTexture;
|
||||
IGraphics::CTextureHandle m_TeleTexture;
|
||||
IGraphics::CTextureHandle m_SpeedupTexture;
|
||||
IGraphics::CTextureHandle m_SwitchTexture;
|
||||
IGraphics::CTextureHandle m_TuneTexture;
|
||||
IGraphics::CTextureHandle GetFrontTexture();
|
||||
IGraphics::CTextureHandle GetTeleTexture();
|
||||
IGraphics::CTextureHandle GetSpeedupTexture();
|
||||
IGraphics::CTextureHandle GetSwitchTexture();
|
||||
IGraphics::CTextureHandle GetTuneTexture();
|
||||
|
||||
static int PopupTele(CEditor *pEditor, CUIRect View, void *pContext);
|
||||
static int PopupSpeedup(CEditor *pEditor, CUIRect View, void *pContext);
|
||||
static int PopupSwitch(CEditor *pEditor, CUIRect View, void *pContext);
|
||||
|
|
|
@ -1880,8 +1880,9 @@ int CEditor::PopupEntities(CEditor *pEditor, CUIRect View, void *pContext)
|
|||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "editor/entities/%s.png", Name);
|
||||
|
||||
pEditor->Graphics()->UnloadTexture(&pEditor->m_EntitiesTexture);
|
||||
int TextureLoadFlag = pEditor->Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
|
||||
if(pEditor->m_EntitiesTexture.IsValid())
|
||||
pEditor->Graphics()->UnloadTexture(&pEditor->m_EntitiesTexture);
|
||||
int TextureLoadFlag = pEditor->GetTextureUsageFlag();
|
||||
pEditor->m_EntitiesTexture = pEditor->Graphics()->LoadTexture(aBuf, IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
|
||||
g_UiNumPopups--;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue