feat(webgl): Add WEBGL_GAL implementation (compiles, not yet rendering)

Copy and adapt OpenGL GAL to WebGL:
- Copy all OpenGL GAL source files to tests/gal-regression/wasm/webgl/
- Rename classes from OPENGL_* to WEBGL_*
- Add kiglew.h with WebGL2/GLES3 headers and GLEW stubs
- Add webgl_antialiasing.h/cpp adapted for WEBGL_COMPOSITOR
- Add shader generator (generate_shaders.py) for WASM build
- Update Makefile with all KiCad dependencies (C++20, GLM, clipper2, etc.)

Build produces 544KB JS + 4.9MB WASM. Tests run but render blank
(expected - GL context initialization needs WebGL adaptation).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Viktor Vaczi 2026-01-07 21:04:42 +01:00
commit c381fdb85c
60 changed files with 27839 additions and 16 deletions

View file

@ -1,7 +1,7 @@
# Makefile for GAL WebGL Test (WASM)
#
# Uses direct em++ calls like tests/apps/Makefile.wasm
# Avoids emcmake/cmake which require Python 3.10+
# Builds WEBGL_GAL (ported from OPENGL_GAL) using wxWidgets WASM build.
# Uses LEGACY_GL_EMULATION for legacy OpenGL compatibility.
#
# Usage:
# make # Build
@ -10,32 +10,104 @@
CXX = em++
# Paths relative to this Makefile
PROJECT_ROOT = ../../..
KICAD_ROOT = $(PROJECT_ROOT)/kicad
WX_BUILD = $(PROJECT_ROOT)/build-wasm/wxwidgets-universal
TOOLS_ROOT = $(PROJECT_ROOT)/wxwidgets/build/wasm
# Output directory
OUTPUT_DIR = ../../apps/gal-webgl
# wx-config for wxWidgets WASM
WXCONFIG = $(WX_BUILD)/wx-config
WX_CXXFLAGS := $(shell $(WXCONFIG) --cxxflags)
WX_LDFLAGS := $(shell $(WXCONFIG) --libs base,core,gl)
# Sysroot (contains boost, etc.)
SYSROOT = $(PROJECT_ROOT)/build-wasm/sysroot
# KiCad include paths
# Note: -I../native provides stub files (config.h, kicad_stubs.h, etc.)
KICAD_INCLUDES = -I../native \
-Igenerated \
-I$(KICAD_ROOT)/include \
-I$(KICAD_ROOT)/include/gal \
-I$(KICAD_ROOT)/include/gal/opengl \
-I$(KICAD_ROOT)/common \
-I$(KICAD_ROOT)/libs/kimath/include \
-I$(KICAD_ROOT)/libs/kiplatform/include \
-I$(KICAD_ROOT)/libs/core/include \
-I$(KICAD_ROOT)/thirdparty/glm \
-I$(KICAD_ROOT)/thirdparty/nlohmann_json \
-I$(KICAD_ROOT)/thirdparty/thread-pool \
-I$(KICAD_ROOT)/thirdparty/clipper2/Clipper2Lib/include \
-I$(SYSROOT)/include \
-Iwebgl
# Debug or Release build
ifdef DEBUG
CXXFLAGS = -g -O0
OPT_FLAGS = -g -O0
DEBUG_LDFLAGS = -g -gsource-map
else
CXXFLAGS = -O2
OPT_FLAGS = -O2
DEBUG_LDFLAGS =
endif
# Emscripten flags for WebGL 2.0
EM_FLAGS = -sUSE_WEBGL2=1 \
-sFULL_ES3=1 \
-sALLOW_MEMORY_GROWTH=1 \
-sEXPORTED_FUNCTIONS=['_main','_runScenario','_getTotalScenarios','_getCurrentScenario','_getCanvasWidth','_getCanvasHeight'] \
-sEXPORTED_RUNTIME_METHODS=['ccall','cwrap'] \
-sMODULARIZE=1 \
-sEXPORT_NAME='createGALTest' \
-sENVIRONMENT=web
CXXFLAGS = $(OPT_FLAGS) $(WX_CXXFLAGS) $(KICAD_INCLUDES) -std=c++20
LDFLAGS = $(DEBUG_LDFLAGS) $(EM_FLAGS)
# Emscripten flags
BASE_LDFLAGS = -sALLOW_MEMORY_GROWTH=1 \
-sERROR_ON_UNDEFINED_SYMBOLS=0 \
-sEXPORTED_FUNCTIONS=['_main','_runScenario','_getTotalScenarios','_getCurrentScenario','_getCanvasWidth','_getCanvasHeight'] \
-sEXPORTED_RUNTIME_METHODS=['ccall','cwrap','HEAPU8'] \
-sMODULARIZE=1 \
-sEXPORT_NAME='createGALTest' \
-sENVIRONMENT=web
# GL-specific flags - LEGACY_GL_EMULATION handles legacy GL calls
EM_GL_FLAGS = -sLEGACY_GL_EMULATION=1 -sMAX_WEBGL_VERSION=2
GL_SHIM = $(PROJECT_ROOT)/wasm/shims/gl_immediate_shim.js
LDFLAGS = $(DEBUG_LDFLAGS) $(BASE_LDFLAGS) $(EM_GL_FLAGS) --js-library=$(GL_SHIM) $(WX_LDFLAGS)
# Templates
JS = $(TOOLS_ROOT)/wx.js
HTML_TEMPLATE = $(TOOLS_ROOT)/template.html
# Source files
SRCS = gal_webgl_test.cpp
MAIN_SRCS = gal_webgl_test.cpp
# Generated shader sources (from generate_shaders.py)
SHADER_SRCS = generated/glsl_kicad_frag.cpp \
generated/glsl_kicad_vert.cpp \
generated/glsl_smaa_base.cpp \
generated/glsl_smaa_pass_1_frag_color.cpp \
generated/glsl_smaa_pass_1_frag_luma.cpp \
generated/glsl_smaa_pass_1_vert.cpp \
generated/glsl_smaa_pass_2_frag.cpp \
generated/glsl_smaa_pass_2_vert.cpp \
generated/glsl_smaa_pass_3_frag.cpp \
generated/glsl_smaa_pass_3_vert.cpp
# WebGL GAL sources (ported from OpenGL GAL)
WEBGL_SRCS = webgl/webgl_gal.cpp \
webgl/vertex_manager.cpp \
webgl/vertex_container.cpp \
webgl/vertex_item.cpp \
webgl/gpu_manager.cpp \
webgl/noncached_container.cpp \
webgl/cached_container.cpp \
webgl/cached_container_gpu.cpp \
webgl/cached_container_ram.cpp \
webgl/shader.cpp \
webgl/webgl_compositor.cpp \
webgl/utils.cpp \
webgl/gl_context_mgr.cpp \
webgl/gl_resources.cpp \
webgl/webgl_antialiasing.cpp
SRCS = $(MAIN_SRCS) $(SHADER_SRCS) $(WEBGL_SRCS)
OBJS = $(SRCS:.cpp=.o)
# Target
@ -50,7 +122,7 @@ $(OUTPUT_DIR):
$(CXX) -c $(CXXFLAGS) $< -o $@
$(TARGET): $(OBJS)
$(CXX) $(OBJS) $(LDFLAGS) -o $@
$(CXX) $(OBJS) $(LDFLAGS) --pre-js $(JS) -o $@
cp gal_webgl_test.html $(OUTPUT_DIR)/
clean:

View file

@ -0,0 +1,102 @@
#!/usr/bin/env python3
"""
Generate C++ shader headers from KiCad GLSL files.
This script converts GLSL shader files to C++ headers compatible with
KiCad's BUILTIN_SHADERS namespace.
"""
import os
import sys
def convert_shader_to_cpp(source_path, var_name):
"""Convert a shader file to C++ header content."""
with open(source_path, 'rb') as f:
data = f.read()
# Convert to hex array
hex_values = ', '.join(f'0x{b:02x}' for b in data)
hex_values += ', 0x00' # Null terminate
array_size = len(data)
header_content = f"""// Auto-generated shader header from {os.path.basename(source_path)}
#ifndef {var_name.upper()}_H
#define {var_name.upper()}_H
#include <string>
namespace KIGFX {{
namespace BUILTIN_SHADERS {{
extern std::string {var_name};
}}
}}
#endif // {var_name.upper()}_H
"""
cpp_content = f"""// Auto-generated from {os.path.basename(source_path)}
#include <string>
#include "{var_name}.h"
namespace KIGFX {{
namespace BUILTIN_SHADERS {{
static unsigned char {var_name}_bytes[] = {{ {hex_values} }};
std::string {var_name} = std::string(reinterpret_cast<char const*>({var_name}_bytes), {array_size});
}}
}}
"""
return header_content, cpp_content
def main():
script_dir = os.path.dirname(os.path.abspath(__file__))
kicad_root = os.path.abspath(os.path.join(script_dir, '..', '..', '..', 'kicad'))
shaders_dir = os.path.join(kicad_root, 'common', 'gal', 'shaders')
output_dir = os.path.join(script_dir, 'generated')
os.makedirs(output_dir, exist_ok=True)
shaders = [
('kicad_frag.glsl', 'glsl_kicad_frag'),
('kicad_vert.glsl', 'glsl_kicad_vert'),
('smaa_base.glsl', 'glsl_smaa_base'),
('smaa_pass_1_frag_color.glsl', 'glsl_smaa_pass_1_frag_color'),
('smaa_pass_1_frag_luma.glsl', 'glsl_smaa_pass_1_frag_luma'),
('smaa_pass_1_vert.glsl', 'glsl_smaa_pass_1_vert'),
('smaa_pass_2_frag.glsl', 'glsl_smaa_pass_2_frag'),
('smaa_pass_2_vert.glsl', 'glsl_smaa_pass_2_vert'),
('smaa_pass_3_frag.glsl', 'glsl_smaa_pass_3_frag'),
('smaa_pass_3_vert.glsl', 'glsl_smaa_pass_3_vert'),
]
generated_cpp_files = []
for shader_file, var_name in shaders:
source_path = os.path.join(shaders_dir, shader_file)
if not os.path.exists(source_path):
print(f"Warning: {source_path} not found, skipping")
continue
header_content, cpp_content = convert_shader_to_cpp(source_path, var_name)
header_path = os.path.join(output_dir, f'{var_name}.h')
cpp_path = os.path.join(output_dir, f'{var_name}.cpp')
with open(header_path, 'w') as f:
f.write(header_content)
with open(cpp_path, 'w') as f:
f.write(cpp_content)
generated_cpp_files.append(cpp_path)
print(f"Generated {var_name}.h and {var_name}.cpp")
print(f"\nGenerated {len(generated_cpp_files)} shader files in {output_dir}")
if __name__ == '__main__':
main()

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,13 @@
// Auto-generated shader header from kicad_frag.glsl
#ifndef GLSL_KICAD_FRAG_H
#define GLSL_KICAD_FRAG_H
#include <string>
namespace KIGFX {
namespace BUILTIN_SHADERS {
extern std::string glsl_kicad_frag;
}
}
#endif // GLSL_KICAD_FRAG_H

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,13 @@
// Auto-generated shader header from kicad_vert.glsl
#ifndef GLSL_KICAD_VERT_H
#define GLSL_KICAD_VERT_H
#include <string>
namespace KIGFX {
namespace BUILTIN_SHADERS {
extern std::string glsl_kicad_vert;
}
}
#endif // GLSL_KICAD_VERT_H

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,13 @@
// Auto-generated shader header from smaa_base.glsl
#ifndef GLSL_SMAA_BASE_H
#define GLSL_SMAA_BASE_H
#include <string>
namespace KIGFX {
namespace BUILTIN_SHADERS {
extern std::string glsl_smaa_base;
}
}
#endif // GLSL_SMAA_BASE_H

View file

@ -0,0 +1,13 @@
// Auto-generated from smaa_pass_1_frag_color.glsl
#include <string>
#include "glsl_smaa_pass_1_frag_color.h"
namespace KIGFX {
namespace BUILTIN_SHADERS {
static unsigned char glsl_smaa_pass_1_frag_color_bytes[] = { 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5b, 0x33, 0x5d, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x65, 0x78, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2e, 0x78, 0x79, 0x20, 0x3d, 0x20, 0x53, 0x4d, 0x41, 0x41, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x45, 0x64, 0x67, 0x65, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x53, 0x28, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x65, 0x78, 0x29, 0x2e, 0x78, 0x79, 0x3b, 0x0a, 0x7d, 0x00 };
std::string glsl_smaa_pass_1_frag_color = std::string(reinterpret_cast<char const*>(glsl_smaa_pass_1_frag_color_bytes), 170);
}
}

View file

@ -0,0 +1,13 @@
// Auto-generated shader header from smaa_pass_1_frag_color.glsl
#ifndef GLSL_SMAA_PASS_1_FRAG_COLOR_H
#define GLSL_SMAA_PASS_1_FRAG_COLOR_H
#include <string>
namespace KIGFX {
namespace BUILTIN_SHADERS {
extern std::string glsl_smaa_pass_1_frag_color;
}
}
#endif // GLSL_SMAA_PASS_1_FRAG_COLOR_H

View file

@ -0,0 +1,13 @@
// Auto-generated from smaa_pass_1_frag_luma.glsl
#include <string>
#include "glsl_smaa_pass_1_frag_luma.h"
namespace KIGFX {
namespace BUILTIN_SHADERS {
static unsigned char glsl_smaa_pass_1_frag_luma_bytes[] = { 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5b, 0x33, 0x5d, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x65, 0x78, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2e, 0x78, 0x79, 0x20, 0x3d, 0x20, 0x53, 0x4d, 0x41, 0x41, 0x4c, 0x75, 0x6d, 0x61, 0x45, 0x64, 0x67, 0x65, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x53, 0x28, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x65, 0x78, 0x29, 0x2e, 0x78, 0x79, 0x3b, 0x0a, 0x7d, 0x00 };
std::string glsl_smaa_pass_1_frag_luma = std::string(reinterpret_cast<char const*>(glsl_smaa_pass_1_frag_luma_bytes), 169);
}
}

View file

@ -0,0 +1,13 @@
// Auto-generated shader header from smaa_pass_1_frag_luma.glsl
#ifndef GLSL_SMAA_PASS_1_FRAG_LUMA_H
#define GLSL_SMAA_PASS_1_FRAG_LUMA_H
#include <string>
namespace KIGFX {
namespace BUILTIN_SHADERS {
extern std::string glsl_smaa_pass_1_frag_luma;
}
}
#endif // GLSL_SMAA_PASS_1_FRAG_LUMA_H

View file

@ -0,0 +1,13 @@
// Auto-generated from smaa_pass_1_vert.glsl
#include <string>
#include "glsl_smaa_pass_1_vert.h"
namespace KIGFX {
namespace BUILTIN_SHADERS {
static unsigned char glsl_smaa_pass_1_vert_bytes[] = { 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5b, 0x33, 0x5d, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, 0x20, 0x67, 0x6c, 0x5f, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, 0x73, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x53, 0x4d, 0x41, 0x41, 0x45, 0x64, 0x67, 0x65, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x53, 0x28, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x28, 0x29, 0x3b, 0x0a, 0x0a, 0x7d, 0x00 };
std::string glsl_smaa_pass_1_vert = std::string(reinterpret_cast<char const*>(glsl_smaa_pass_1_vert_bytes), 179);
}
}

View file

@ -0,0 +1,13 @@
// Auto-generated shader header from smaa_pass_1_vert.glsl
#ifndef GLSL_SMAA_PASS_1_VERT_H
#define GLSL_SMAA_PASS_1_VERT_H
#include <string>
namespace KIGFX {
namespace BUILTIN_SHADERS {
extern std::string glsl_smaa_pass_1_vert;
}
}
#endif // GLSL_SMAA_PASS_1_VERT_H

View file

@ -0,0 +1,13 @@
// Auto-generated from smaa_pass_2_frag.glsl
#include <string>
#include "glsl_smaa_pass_2_frag.h"
namespace KIGFX {
namespace BUILTIN_SHADERS {
static unsigned char glsl_smaa_pass_2_frag_bytes[] = { 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x70, 0x69, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5b, 0x33, 0x5d, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 0x65, 0x64, 0x67, 0x65, 0x73, 0x54, 0x65, 0x78, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 0x61, 0x72, 0x65, 0x61, 0x54, 0x65, 0x78, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x54, 0x65, 0x78, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x53, 0x4d, 0x41, 0x41, 0x42, 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x53, 0x28, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x70, 0x69, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x65, 0x64, 0x67, 0x65, 0x73, 0x54, 0x65, 0x78, 0x2c, 0x20, 0x61, 0x72, 0x65, 0x61, 0x54, 0x65, 0x78, 0x2c, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x54, 0x65, 0x78, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x34, 0x28, 0x30, 0x2e, 0x2c, 0x30, 0x2e, 0x2c, 0x30, 0x2e, 0x2c, 0x30, 0x2e, 0x29, 0x29, 0x3b, 0x0a, 0x7d, 0x00 };
std::string glsl_smaa_pass_2_frag = std::string(reinterpret_cast<char const*>(glsl_smaa_pass_2_frag_bytes), 299);
}
}

View file

@ -0,0 +1,13 @@
// Auto-generated shader header from smaa_pass_2_frag.glsl
#ifndef GLSL_SMAA_PASS_2_FRAG_H
#define GLSL_SMAA_PASS_2_FRAG_H
#include <string>
namespace KIGFX {
namespace BUILTIN_SHADERS {
extern std::string glsl_smaa_pass_2_frag;
}
}
#endif // GLSL_SMAA_PASS_2_FRAG_H

View file

@ -0,0 +1,13 @@
// Auto-generated from smaa_pass_2_vert.glsl
#include <string>
#include "glsl_smaa_pass_2_vert.h"
namespace KIGFX {
namespace BUILTIN_SHADERS {
static unsigned char glsl_smaa_pass_2_vert_bytes[] = { 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5b, 0x33, 0x5d, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x70, 0x69, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, 0x20, 0x67, 0x6c, 0x5f, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, 0x73, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x53, 0x4d, 0x41, 0x41, 0x42, 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x53, 0x28, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x70, 0x69, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x28, 0x29, 0x3b, 0x0a, 0x7d, 0x00 };
std::string glsl_smaa_pass_2_vert = std::string(reinterpret_cast<char const*>(glsl_smaa_pass_2_vert_bytes), 222);
}
}

View file

@ -0,0 +1,13 @@
// Auto-generated shader header from smaa_pass_2_vert.glsl
#ifndef GLSL_SMAA_PASS_2_VERT_H
#define GLSL_SMAA_PASS_2_VERT_H
#include <string>
namespace KIGFX {
namespace BUILTIN_SHADERS {
extern std::string glsl_smaa_pass_2_vert;
}
}
#endif // GLSL_SMAA_PASS_2_VERT_H

View file

@ -0,0 +1,13 @@
// Auto-generated from smaa_pass_3_frag.glsl
#include <string>
#include "glsl_smaa_pass_3_frag.h"
namespace KIGFX {
namespace BUILTIN_SHADERS {
static unsigned char glsl_smaa_pass_3_frag_bytes[] = { 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x65, 0x78, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 0x62, 0x6c, 0x65, 0x6e, 0x64, 0x54, 0x65, 0x78, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x53, 0x4d, 0x41, 0x41, 0x4e, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6f, 0x72, 0x68, 0x6f, 0x6f, 0x64, 0x42, 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x53, 0x28, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x54, 0x65, 0x78, 0x2c, 0x20, 0x62, 0x6c, 0x65, 0x6e, 0x64, 0x54, 0x65, 0x78, 0x29, 0x3b, 0x0a, 0x7d, 0x00 };
std::string glsl_smaa_pass_3_frag = std::string(reinterpret_cast<char const*>(glsl_smaa_pass_3_frag_bytes), 201);
}
}

View file

@ -0,0 +1,13 @@
// Auto-generated shader header from smaa_pass_3_frag.glsl
#ifndef GLSL_SMAA_PASS_3_FRAG_H
#define GLSL_SMAA_PASS_3_FRAG_H
#include <string>
namespace KIGFX {
namespace BUILTIN_SHADERS {
extern std::string glsl_smaa_pass_3_frag;
}
}
#endif // GLSL_SMAA_PASS_3_FRAG_H

View file

@ -0,0 +1,13 @@
// Auto-generated from smaa_pass_3_vert.glsl
#include <string>
#include "glsl_smaa_pass_3_vert.h"
namespace KIGFX {
namespace BUILTIN_SHADERS {
static unsigned char glsl_smaa_pass_3_vert_bytes[] = { 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, 0x20, 0x67, 0x6c, 0x5f, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x2e, 0x73, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x53, 0x4d, 0x41, 0x41, 0x4e, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6f, 0x72, 0x68, 0x6f, 0x6f, 0x64, 0x42, 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x56, 0x53, 0x28, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x28, 0x29, 0x3b, 0x0a, 0x7d, 0x00 };
std::string glsl_smaa_pass_3_vert = std::string(reinterpret_cast<char const*>(glsl_smaa_pass_3_vert_bytes), 181);
}
}

View file

@ -0,0 +1,13 @@
// Auto-generated shader header from smaa_pass_3_vert.glsl
#ifndef GLSL_SMAA_PASS_3_VERT_H
#define GLSL_SMAA_PASS_3_VERT_H
#include <string>
namespace KIGFX {
namespace BUILTIN_SHADERS {
extern std::string glsl_smaa_pass_3_vert;
}
}
#endif // GLSL_SMAA_PASS_3_VERT_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,132 @@
/**
* Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com)
* Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com)
* Copyright (C) 2013 Belen Masia (bmasia@unizar.es)
* Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com)
* Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to
* do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. As clarification, there
* is no requirement that the copyright notice and permission be included in
* binary distributions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef SEARCHTEX_H
#define SEARCHTEX_H
#define SEARCHTEX_WIDTH 64
#define SEARCHTEX_HEIGHT 16
#define SEARCHTEX_PITCH SEARCHTEX_WIDTH
#define SEARCHTEX_SIZE (SEARCHTEX_HEIGHT * SEARCHTEX_PITCH)
/**
* Stored in R8 format. Load it in the following format:
* - DX9: D3DFMT_L8
* - DX10: DXGI_FORMAT_R8_UNORM
*/
static const unsigned char searchTexBytes[] = {
0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00,
0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe,
0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00,
0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe,
0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f,
0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f,
0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f,
0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
#endif

View file

@ -0,0 +1,143 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef OPENGL_ANTIALIASING_H__
#define OPENGL_ANTIALIASING_H__
#include <memory>
#include "shader.h"
#include <math/vector2d.h>
namespace KIGFX {
class WEBGL_COMPOSITOR;
class OPENGL_PRESENTOR
{
public:
virtual ~OPENGL_PRESENTOR()
{
}
virtual bool Init() = 0;
virtual unsigned int CreateBuffer() = 0;
virtual VECTOR2I GetInternalBufferSize() = 0;
virtual void OnLostBuffers() = 0;
virtual void Begin() = 0;
virtual void DrawBuffer( GLuint aBuffer ) = 0;
virtual void Present() = 0;
};
class ANTIALIASING_NONE : public OPENGL_PRESENTOR
{
public:
ANTIALIASING_NONE( WEBGL_COMPOSITOR* aCompositor );
bool Init() override;
unsigned int CreateBuffer() override;
VECTOR2I GetInternalBufferSize() override;
void OnLostBuffers() override;
void Begin() override;
void DrawBuffer( GLuint aBuffer ) override;
void Present() override;
private:
WEBGL_COMPOSITOR* compositor;
};
class ANTIALIASING_SUPERSAMPLING : public OPENGL_PRESENTOR
{
public:
ANTIALIASING_SUPERSAMPLING( WEBGL_COMPOSITOR* aCompositor );
bool Init() override;
unsigned int CreateBuffer() override;
VECTOR2I GetInternalBufferSize() override;
void OnLostBuffers() override;
void Begin() override;
void DrawBuffer( GLuint ) override;
void Present() override;
private:
WEBGL_COMPOSITOR* compositor;
unsigned int ssaaMainBuffer;
bool areBuffersCreated;
bool areShadersCreated;
};
class ANTIALIASING_SMAA : public OPENGL_PRESENTOR
{
public:
ANTIALIASING_SMAA( WEBGL_COMPOSITOR* aCompositor );
bool Init() override;
unsigned int CreateBuffer () override;
VECTOR2I GetInternalBufferSize() override;
void OnLostBuffers() override;
void Begin() override;
void DrawBuffer( GLuint buffer ) override;
void Present() override;
private:
void loadShaders();
void updateUniforms();
bool areBuffersInitialized;
unsigned int smaaBaseBuffer; // base + overlay temporary
unsigned int smaaEdgesBuffer;
unsigned int smaaBlendBuffer;
// smaa shader lookup textures
unsigned int smaaAreaTex;
unsigned int smaaSearchTex;
bool shadersLoaded;
std::unique_ptr<SHADER> pass_1_shader;
GLint pass_1_metrics;
std::unique_ptr<SHADER> pass_2_shader;
GLint pass_2_metrics;
std::unique_ptr<SHADER> pass_3_shader;
GLint pass_3_metrics;
WEBGL_COMPOSITOR* compositor;
};
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,442 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright 2013-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file cached_container.cpp
* @brief Class to store instances of VERTEX with caching. It allows storing VERTEX objects and
* associates them with VERTEX_ITEMs. This leads to a possibility of caching vertices data in the
* GPU memory and a fast reuse of that data.
*/
#include "cached_container.h"
#include "vertex_manager.h"
#include "vertex_item.h"
#include "utils.h"
#include <list>
#include <algorithm>
#include <cassert>
#ifdef __WIN32__
#include <excpt.h>
#endif
#ifdef KICAD_GAL_PROFILE
#include <wx/log.h>
#include <core/profile.h>
#endif /* KICAD_GAL_PROFILE */
using namespace KIGFX;
CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) :
VERTEX_CONTAINER( aSize ),
m_item( nullptr ),
m_chunkSize( 0 ),
m_chunkOffset( 0 ),
m_maxIndex( 0 )
{
// In the beginning there is only free space
m_freeChunks.insert( std::make_pair( aSize, 0 ) );
}
void CACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem )
{
assert( aItem != nullptr );
unsigned int itemSize = aItem->GetSize();
m_item = aItem;
m_chunkSize = itemSize;
// Get the previously set offset if the item was stored previously
m_chunkOffset = itemSize > 0 ? aItem->GetOffset() : -1;
}
void CACHED_CONTAINER::FinishItem()
{
assert( m_item != nullptr );
unsigned int itemSize = m_item->GetSize();
// Finishing the previously edited item
if( itemSize < m_chunkSize )
{
// There is some not used but reserved memory left, so we should return it to the pool
int itemOffset = m_item->GetOffset();
// Add the not used memory back to the pool
addFreeChunk( itemOffset + itemSize, m_chunkSize - itemSize );
// mergeFreeChunks(); // veery slow and buggy
m_maxIndex = std::max( itemOffset + itemSize, m_maxIndex );
}
if( itemSize > 0 )
m_items.insert( m_item );
m_item = nullptr;
m_chunkSize = 0;
m_chunkOffset = 0;
#if CACHED_CONTAINER_TEST > 1
test();
#endif
}
VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize )
{
assert( m_item != nullptr );
assert( IsMapped() );
if( m_failed )
return nullptr;
unsigned int itemSize = m_item->GetSize();
unsigned int newSize = itemSize + aSize;
if( newSize > m_chunkSize )
{
// There is not enough space in the currently reserved chunk, so we have to resize it
if( !reallocate( newSize ) )
{
m_failed = true;
return nullptr;
}
}
VERTEX* reserved = &m_vertices[m_chunkOffset + itemSize];
// Now the item officially possesses the memory chunk
m_item->setSize( newSize );
// The content has to be updated
m_dirty = true;
#if CACHED_CONTAINER_TEST > 0
test();
#endif
#if CACHED_CONTAINER_TEST > 2
showFreeChunks();
showUsedChunks();
#endif
return reserved;
}
void CACHED_CONTAINER::Delete( VERTEX_ITEM* aItem )
{
assert( aItem != nullptr );
assert( m_items.find( aItem ) != m_items.end() || aItem->GetSize() == 0 );
int size = aItem->GetSize();
if( size == 0 )
return; // Item is not stored here
int offset = aItem->GetOffset();
// Insert a free memory chunk entry in the place where item was stored
addFreeChunk( offset, size );
// Indicate that the item is not stored in the container anymore
aItem->setSize( 0 );
m_items.erase( aItem );
#if CACHED_CONTAINER_TEST > 0
test();
#endif
// This dynamic memory freeing optimize memory usage, but in fact can create
// out of memory issues because freeing and reallocation large chunks of memory
// can create memory fragmentation and no room to reallocate large chunks
// after many free/reallocate cycles during a session using the same complex board
// So it can be disable.
// Currently: it is disable to avoid "out of memory" issues
#if 0
// Dynamic memory freeing, there is no point in holding
// a large amount of memory when there is no use for it
if( m_freeSpace > ( 0.75 * m_currentSize ) && m_currentSize > m_initialSize )
{
defragmentResize( 0.5 * m_currentSize );
}
#endif
}
void CACHED_CONTAINER::Clear()
{
m_freeSpace = m_currentSize;
m_maxIndex = 0;
m_failed = false;
// Set the size of all the stored VERTEX_ITEMs to 0, so it is clear that they are not held
// in the container anymore
for( ITEMS::iterator it = m_items.begin(); it != m_items.end(); ++it )
( *it )->setSize( 0 );
m_items.clear();
// Now there is only free space left
m_freeChunks.clear();
m_freeChunks.insert( std::make_pair( m_freeSpace, 0 ) );
}
bool CACHED_CONTAINER::reallocate( unsigned int aSize )
{
assert( aSize > 0 );
assert( IsMapped() );
unsigned int itemSize = m_item->GetSize();
// Find a free space chunk >= aSize
FREE_CHUNK_MAP::iterator newChunk = m_freeChunks.lower_bound( aSize );
// Is there enough space to store vertices?
if( newChunk == m_freeChunks.end() )
{
bool result;
// Would it be enough to double the current space?
if( aSize < m_freeSpace + m_currentSize )
{
// Yes: exponential growing
result = defragmentResize( m_currentSize * 2 );
}
else
{
// No: grow to the nearest greater power of 2
result = defragmentResize( pow( 2, ceil( log2( m_currentSize * 2 + aSize ) ) ) );
}
if( !result )
return false;
newChunk = m_freeChunks.lower_bound( aSize );
assert( newChunk != m_freeChunks.end() );
}
// Parameters of the allocated chunk
unsigned int newChunkSize = getChunkSize( *newChunk );
unsigned int newChunkOffset = getChunkOffset( *newChunk );
assert( newChunkSize >= aSize );
assert( newChunkOffset < m_currentSize );
// Check if the item was previously stored in the container
if( itemSize > 0 )
{
// The item was reallocated, so we have to copy all the old data to the new place
memcpy( &m_vertices[newChunkOffset], &m_vertices[m_chunkOffset], itemSize * VERTEX_SIZE );
// Free the space used by the previous chunk
addFreeChunk( m_chunkOffset, m_chunkSize );
}
// Remove the new allocated chunk from the free space pool
m_freeChunks.erase( newChunk );
m_freeSpace -= newChunkSize;
m_chunkSize = newChunkSize;
m_chunkOffset = newChunkOffset;
m_item->setOffset( m_chunkOffset );
return true;
}
void CACHED_CONTAINER::defragment( VERTEX* aTarget )
{
// Defragmentation
ITEMS::iterator it, it_end;
int newOffset = 0;
[&]()
{
#ifdef __WIN32__
#ifdef __MINGW32__
// currently, because SEH (Structured Exception Handling) is not documented on msys
// (for instance __try or __try1 exists without doc) or is not supported, do nothing
#else
__try
#endif
#endif
{
for( VERTEX_ITEM* item : m_items )
{
int itemOffset = item->GetOffset();
int itemSize = item->GetSize();
// Move an item to the new container
memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VERTEX_SIZE );
// Update new offset
item->setOffset( newOffset );
// Move to the next free space
newOffset += itemSize;
}
// Move the current item and place it at the end
if( m_item->GetSize() > 0 )
{
memcpy( &aTarget[newOffset], &m_vertices[m_item->GetOffset()],
m_item->GetSize() * VERTEX_SIZE );
m_item->setOffset( newOffset );
m_chunkOffset = newOffset;
}
}
#ifdef __WIN32__
#ifdef __MINGW32__
// currently, because SEH (Structured Exception Handling) is not documented on msys
// (for instance __except1 exists without doc) or is not supported, do nothing
#else
__except( GetExceptionCode() == STATUS_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH )
{
throw std::runtime_error(
"Access violation in defragment. This is usually an indicator of "
"system or GPU memory running low." );
};
#endif
#endif
}();
m_maxIndex = usedSpace();
}
void CACHED_CONTAINER::mergeFreeChunks()
{
if( m_freeChunks.size() <= 1 ) // There are no chunks that can be merged
return;
#ifdef KICAD_GAL_PROFILE
PROF_TIMER totalTime;
#endif /* KICAD_GAL_PROFILE */
// Reversed free chunks map - this one stores chunk size with its offset as the key
std::list<CHUNK> freeChunks;
FREE_CHUNK_MAP::const_iterator it, it_end;
for( it = m_freeChunks.begin(), it_end = m_freeChunks.end(); it != it_end; ++it )
{
freeChunks.emplace_back( it->second, it->first );
}
m_freeChunks.clear();
freeChunks.sort();
std::list<CHUNK>::const_iterator itf, itf_end;
unsigned int offset = freeChunks.front().first;
unsigned int size = freeChunks.front().second;
freeChunks.pop_front();
for( itf = freeChunks.begin(), itf_end = freeChunks.end(); itf != itf_end; ++itf )
{
if( itf->first == offset + size )
{
// These chunks can be merged, so just increase the current chunk size and go on
size += itf->second;
}
else
{
// These chunks cannot be merged
// So store the previous one
m_freeChunks.insert( std::make_pair( size, offset ) );
// and let's check the next chunk
offset = itf->first;
size = itf->second;
}
}
// Add the last one
m_freeChunks.insert( std::make_pair( size, offset ) );
#if CACHED_CONTAINER_TEST > 0
test();
#endif
}
void CACHED_CONTAINER::addFreeChunk( unsigned int aOffset, unsigned int aSize )
{
assert( aOffset + aSize <= m_currentSize );
assert( aSize > 0 );
m_freeChunks.insert( std::make_pair( aSize, aOffset ) );
m_freeSpace += aSize;
}
void CACHED_CONTAINER::showFreeChunks()
{
}
void CACHED_CONTAINER::showUsedChunks()
{
}
void CACHED_CONTAINER::test()
{
#ifdef KICAD_GAL_PROFILE
// Free space check
unsigned int freeSpace = 0;
FREE_CHUNK_MAP::iterator itf;
for( itf = m_freeChunks.begin(); itf != m_freeChunks.end(); ++itf )
freeSpace += getChunkSize( *itf );
assert( freeSpace == m_freeSpace );
// Used space check
unsigned int used_space = 0;
ITEMS::iterator itr;
for( itr = m_items.begin(); itr != m_items.end(); ++itr )
used_space += ( *itr )->GetSize();
// If we have a chunk assigned, then there must be an item edited
assert( m_chunkSize == 0 || m_item );
// Currently reserved chunk is also counted as used
used_space += m_chunkSize;
assert( ( m_freeSpace + used_space ) == m_currentSize );
// Overlapping check TODO
#endif /* KICAD_GAL_PROFILE */
}

View file

@ -0,0 +1,191 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright 2013-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef CACHED_CONTAINER_H_
#define CACHED_CONTAINER_H_
#include "vertex_container.h"
#include <map>
#include <set>
namespace KIGFX
{
class VERTEX_ITEM;
class SHADER;
/**
* Class to store VERTEX instances with caching.
*
* It associates VERTEX objects and with VERTEX_ITEMs. Caching vertices data in the memory and a
* enables fast reuse of that data.
*/
class CACHED_CONTAINER : public VERTEX_CONTAINER
{
public:
CACHED_CONTAINER( unsigned int aSize = DEFAULT_SIZE );
virtual ~CACHED_CONTAINER() {}
bool IsCached() const override
{
return true;
}
virtual void SetItem( VERTEX_ITEM* aItem ) override;
///< @copydoc VERTEX_CONTAINER::FinishItem()
virtual void FinishItem() override;
/**
* Return allocated space for the requested number of vertices associated with the
* current item (set with SetItem()).
*
* The allocated space is added at the end of the chunk used by the current item and
* may serve to store new vertices.
*
* @param aSize is the number of vertices to be allocated.
* @return Pointer to the allocated space.
* @throw bad_alloc exception if allocation fails.
*/
virtual VERTEX* Allocate( unsigned int aSize ) override;
///< @copydoc VERTEX_CONTAINER::Delete()
virtual void Delete( VERTEX_ITEM* aItem ) override;
///< @copydoc VERTEX_CONTAINER::Clear()
virtual void Clear() override;
/**
* Return handle to the vertex buffer. It might be negative if the buffer is not initialized.
*/
virtual unsigned int GetBufferHandle() const = 0;
/**
* Return true if vertex buffer is currently mapped.
*/
virtual bool IsMapped() const = 0;
///< @copydoc VERTEX_CONTAINER::Map()
virtual void Map() override = 0;
///< @copydoc VERTEX_CONTAINER::Unmap()
virtual void Unmap() override = 0;
virtual unsigned int AllItemsSize() const { return 0; }
protected:
///< Maps size of free memory chunks to their offsets
typedef std::pair<unsigned int, unsigned int> CHUNK;
typedef std::multimap<unsigned int, unsigned int> FREE_CHUNK_MAP;
/// List of all the stored items
typedef std::set<VERTEX_ITEM*> ITEMS;
/**
* Resize the chunk that stores the current item to the given size. The current item has
* its offset adjusted after the call, and the new chunk parameters are stored
* in m_chunkOffset and m_chunkSize.
*
* @param aSize is the requested chunk size.
* @return true in case of success, false otherwise.
*/
bool reallocate( unsigned int aSize );
/**
* Remove empty spaces between chunks and optionally resizes the container.
*
* After the operation there is continuous space for storing vertices at the end of the
* container.
*
* @param aNewSize is the new size of container, expressed in number of vertices.
* @return false in case of failure (e.g. memory shortage).
*/
virtual bool defragmentResize( unsigned int aNewSize ) = 0;
/**
* Transfer all stored data to a new buffer, removing empty spaces between the data chunks
* in the container.
*
* @param aTarget is the destination for the defragmented data.
*/
void defragment( VERTEX* aTarget );
/**
* Look for consecutive free memory chunks and merges them, decreasing fragmentation of
* memory.
*/
void mergeFreeChunks();
/**
* Return the size of a chunk.
*
* @param aChunk is the chunk.
*/
inline int getChunkSize( const CHUNK& aChunk ) const
{
return aChunk.first;
}
/**
* Return the offset of a chunk.
*
* @param aChunk is the chunk.
*/
inline unsigned int getChunkOffset( const CHUNK& aChunk ) const
{
return aChunk.second;
}
/**
* Add a chunk marked as a free space.
*/
void addFreeChunk( unsigned int aOffset, unsigned int aSize );
///< Store size & offset of free chunks.
FREE_CHUNK_MAP m_freeChunks;
///< Stored VERTEX_ITEMs
ITEMS m_items;
///< Currently modified item
VERTEX_ITEM* m_item;
///< Properties of currently modified chunk & item
unsigned int m_chunkSize;
unsigned int m_chunkOffset;
///< Maximal vertex index number stored in the container
unsigned int m_maxIndex;
private:
/// Debug & test functions
void showFreeChunks();
void showUsedChunks();
void test();
};
} // namespace KIGFX
#endif /* CACHED_CONTAINER_H_ */

View file

@ -0,0 +1,312 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright 2013-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "cached_container_gpu.h"
#include "vertex_manager.h"
#include "vertex_item.h"
#include "shader.h"
#include "utils.h"
#include <wx/log.h>
#include <list>
#include <core/profile.h>
#include <trace_helpers.h>
using namespace KIGFX;
/**
* Flag to enable debug output of the GAL OpenGL GPU cached container.
*
* Use "KICAD_GAL_CACHED_CONTAINER_GPU" to enable GAL OpenGL GPU cached container tracing.
*
* @ingroup trace_env_vars
*/
static const wxChar* const traceGalCachedContainerGpu = wxT( "KICAD_GAL_CACHED_CONTAINER_GPU" );
CACHED_CONTAINER_GPU::CACHED_CONTAINER_GPU( unsigned int aSize ) :
CACHED_CONTAINER( aSize ),
m_isMapped( false ),
m_glBufferHandle( -1 )
{
m_useCopyBuffer = GLEW_ARB_copy_buffer;
wxString vendor( glGetString( GL_VENDOR ) );
// workaround for intel GPU drivers:
// disable glCopyBuffer, causes crashes/freezes on certain driver versions
// Note, Intel's GL_VENDOR string varies depending on GPU/driver generation
// But generally always starts with Intel at least
if( vendor.StartsWith( "Intel" ) || vendor.Contains( "etnaviv" ) )
{
m_useCopyBuffer = false;
}
KI_TRACE( traceGalProfile, "VBO initial size: %d\n", m_currentSize );
glGenBuffers( 1, &m_glBufferHandle );
glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
glBufferData( GL_ARRAY_BUFFER, m_currentSize * VERTEX_SIZE, nullptr, GL_DYNAMIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
checkGlError( "allocating video memory for cached container", __FILE__, __LINE__ );
}
CACHED_CONTAINER_GPU::~CACHED_CONTAINER_GPU()
{
if( m_isMapped )
Unmap();
if( glDeleteBuffers )
glDeleteBuffers( 1, &m_glBufferHandle );
}
void CACHED_CONTAINER_GPU::Map()
{
wxCHECK( !IsMapped(), /*void*/ );
// OpenGL version might suddenly stop being available in Windows when an RDP session is started
if( !glBindBuffer )
throw std::runtime_error( "OpenGL no longer available!" );
glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
m_vertices = static_cast<VERTEX*>( glMapBuffer( GL_ARRAY_BUFFER, GL_READ_WRITE ) );
if( checkGlError( "mapping vertices buffer", __FILE__, __LINE__ ) == GL_NO_ERROR )
m_isMapped = true;
}
void CACHED_CONTAINER_GPU::Unmap()
{
wxCHECK( IsMapped(), /*void*/ );
// This gets called from ~CACHED_CONTAINER_GPU. To avoid throwing an exception from
// the dtor, catch it here instead.
try
{
glUnmapBuffer( GL_ARRAY_BUFFER );
checkGlError( "unmapping vertices buffer", __FILE__, __LINE__ );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
m_vertices = nullptr;
checkGlError( "unbinding vertices buffer", __FILE__, __LINE__ );
}
catch( const std::runtime_error& err )
{
wxLogError( wxT( "OpenGL did not shut down properly.\n\n%s" ), err.what() );
}
m_isMapped = false;
}
bool CACHED_CONTAINER_GPU::defragmentResize( unsigned int aNewSize )
{
if( !m_useCopyBuffer )
return defragmentResizeMemcpy( aNewSize );
wxCHECK( IsMapped(), false );
wxLogTrace( traceGalCachedContainerGpu,
wxT( "Resizing & defragmenting container from %d to %d" ), m_currentSize,
aNewSize );
// No shrinking if we cannot fit all the data
if( usedSpace() > aNewSize )
return false;
#ifdef KICAD_GAL_PROFILE
PROF_TIMER totalTime;
#endif /* KICAD_GAL_PROFILE */
GLuint newBuffer;
// glCopyBufferSubData requires a buffer to be unmapped
glUnmapBuffer( GL_ARRAY_BUFFER );
// Create a new destination buffer
glGenBuffers( 1, &newBuffer );
// It would be best to use GL_COPY_WRITE_BUFFER here,
// but it is not available everywhere
#ifdef KICAD_GAL_PROFILE
GLint eaBuffer = -1;
glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING, &eaBuffer );
wxASSERT( eaBuffer == 0 );
#endif /* KICAD_GAL_PROFILE */
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, newBuffer );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, aNewSize * VERTEX_SIZE, nullptr, GL_DYNAMIC_DRAW );
checkGlError( "creating buffer during defragmentation", __FILE__, __LINE__ );
ITEMS::iterator it, it_end;
int newOffset = 0;
// Defragmentation
for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
{
VERTEX_ITEM* item = *it;
int itemOffset = item->GetOffset();
int itemSize = item->GetSize();
// Move an item to the new container
glCopyBufferSubData( GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, itemOffset * VERTEX_SIZE,
newOffset * VERTEX_SIZE, itemSize * VERTEX_SIZE );
// Update new offset
item->setOffset( newOffset );
// Move to the next free space
newOffset += itemSize;
}
// Move the current item and place it at the end
if( m_item->GetSize() > 0 )
{
glCopyBufferSubData( GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
m_item->GetOffset() * VERTEX_SIZE, newOffset * VERTEX_SIZE,
m_item->GetSize() * VERTEX_SIZE );
m_item->setOffset( newOffset );
m_chunkOffset = newOffset;
}
// Cleanup
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
// Previously we have unmapped the array buffer, now when it is also
// unbound, it may be officially marked as unmapped
m_isMapped = false;
glDeleteBuffers( 1, &m_glBufferHandle );
// Switch to the new vertex buffer
m_glBufferHandle = newBuffer;
Map();
checkGlError( "switching buffers during defragmentation", __FILE__, __LINE__ );
#ifdef KICAD_GAL_PROFILE
totalTime.Stop();
wxLogTrace( traceGalCachedContainerGpu, "Defragmented container storing %d vertices / %.1f ms",
m_currentSize - m_freeSpace, totalTime.msecs() );
#endif /* KICAD_GAL_PROFILE */
m_freeSpace += ( aNewSize - m_currentSize );
m_currentSize = aNewSize;
KI_TRACE( traceGalProfile, "VBO size %d used %d\n", m_currentSize, AllItemsSize() );
// Now there is only one big chunk of free memory
m_freeChunks.clear();
m_freeChunks.insert( std::make_pair( m_freeSpace, m_currentSize - m_freeSpace ) );
return true;
}
bool CACHED_CONTAINER_GPU::defragmentResizeMemcpy( unsigned int aNewSize )
{
wxCHECK( IsMapped(), false );
wxLogTrace( traceGalCachedContainerGpu,
wxT( "Resizing & defragmenting container (memcpy) from %d to %d" ), m_currentSize,
aNewSize );
// No shrinking if we cannot fit all the data
if( usedSpace() > aNewSize )
return false;
#ifdef KICAD_GAL_PROFILE
PROF_TIMER totalTime;
#endif /* KICAD_GAL_PROFILE */
GLuint newBuffer;
VERTEX* newBufferMem;
// Create the destination buffer
glGenBuffers( 1, &newBuffer );
// It would be best to use GL_COPY_WRITE_BUFFER here,
// but it is not available everywhere
#ifdef KICAD_GAL_PROFILE
GLint eaBuffer = -1;
glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING, &eaBuffer );
wxASSERT( eaBuffer == 0 );
#endif /* KICAD_GAL_PROFILE */
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, newBuffer );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, aNewSize * VERTEX_SIZE, nullptr, GL_DYNAMIC_DRAW );
newBufferMem = static_cast<VERTEX*>( glMapBuffer( GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY ) );
checkGlError( "creating buffer during defragmentation", __FILE__, __LINE__ );
defragment( newBufferMem );
// Cleanup
glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
Unmap();
glDeleteBuffers( 1, &m_glBufferHandle );
// Switch to the new vertex buffer
m_glBufferHandle = newBuffer;
Map();
checkGlError( "switching buffers during defragmentation", __FILE__, __LINE__ );
#ifdef KICAD_GAL_PROFILE
totalTime.Stop();
wxLogTrace( traceGalCachedContainerGpu, "Defragmented container storing %d vertices / %.1f ms",
m_currentSize - m_freeSpace, totalTime.msecs() );
#endif /* KICAD_GAL_PROFILE */
m_freeSpace += ( aNewSize - m_currentSize );
m_currentSize = aNewSize;
KI_TRACE( traceGalProfile, "VBO size %d used: %d \n", m_currentSize, AllItemsSize() );
// Now there is only one big chunk of free memory
m_freeChunks.clear();
m_freeChunks.insert( std::make_pair( m_freeSpace, m_currentSize - m_freeSpace ) );
return true;
}
unsigned int CACHED_CONTAINER_GPU::AllItemsSize() const
{
unsigned int size = 0;
for( const auto& item : m_items )
{
size += item->GetSize();
}
return size;
}

View file

@ -0,0 +1,87 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright 2013-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef CACHED_CONTAINER_GPU_H_
#define CACHED_CONTAINER_GPU_H_
#include "cached_container.h"
namespace KIGFX
{
/**
* Specialization of CACHED_CONTAINER that stores data in video memory via memory mapping.
*/
class CACHED_CONTAINER_GPU : public CACHED_CONTAINER
{
public:
CACHED_CONTAINER_GPU( unsigned int aSize = DEFAULT_SIZE );
~CACHED_CONTAINER_GPU();
unsigned int GetBufferHandle() const override
{
return m_glBufferHandle;
}
bool IsMapped() const override
{
return m_isMapped;
}
///< @copydoc VERTEX_CONTAINER::Map()
void Map() override;
///< @copydoc VERTEX_CONTAINER::Unmap()
void Unmap() override;
virtual unsigned int AllItemsSize() const override;
protected:
/**
* Remove empty spaces between chunks and optionally resizes the container.
*
* After the operation there is continuous space for storing vertices at the end of
* the container.
*
* @param aNewSize is the new size of container, expressed in number of vertices.
* @return false in case of failure (e.g. memory shortage).
*/
bool defragmentResize( unsigned int aNewSize ) override;
bool defragmentResizeMemcpy( unsigned int aNewSize );
///< Flag saying if vertex buffer is currently mapped
bool m_isMapped;
///< Vertex buffer handle
unsigned int m_glBufferHandle;
///< Flag saying whether it is safe to use glCopyBufferSubData
bool m_useCopyBuffer;
};
} // namespace KIGFX
#endif /* CACHED_CONTAINER_GPU_H_ */

View file

@ -0,0 +1,134 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright 2013-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "cached_container_ram.h"
#include "vertex_manager.h"
#include "vertex_item.h"
#include "shader.h"
#include "utils.h"
#include <confirm.h>
#include <list>
#include <cassert>
#include <wx/log.h>
#ifdef KICAD_GAL_PROFILE
#include <core/profile.h>
#endif /* KICAD_GAL_PROFILE */
using namespace KIGFX;
/**
* Flag to enable debug output of the GAL OpenGL cached container.
*
* Use "KICAD_GAL_CACHED_CONTAINER" to enable GAL OpenGL cached container tracing.
*
* @ingroup trace_env_vars
*/
static const wxChar* const traceGalCachedContainer = wxT( "KICAD_GAL_CACHED_CONTAINER" );
CACHED_CONTAINER_RAM::CACHED_CONTAINER_RAM( unsigned int aSize ) :
CACHED_CONTAINER( aSize ),
m_verticesBuffer( 0 )
{
glGenBuffers( 1, &m_verticesBuffer );
checkGlError( "generating vertices buffer", __FILE__, __LINE__ );
m_vertices = static_cast<VERTEX*>( malloc( aSize * VERTEX_SIZE ) );
if( !m_vertices )
throw std::bad_alloc();
}
CACHED_CONTAINER_RAM::~CACHED_CONTAINER_RAM()
{
if( glDeleteBuffers )
glDeleteBuffers( 1, &m_verticesBuffer );
free( m_vertices );
}
void CACHED_CONTAINER_RAM::Unmap()
{
if( !m_dirty )
return;
// Upload vertices coordinates and shader types to GPU memory
glBindBuffer( GL_ARRAY_BUFFER, m_verticesBuffer );
checkGlError( "binding vertices buffer", __FILE__, __LINE__ );
glBufferData( GL_ARRAY_BUFFER, m_maxIndex * VERTEX_SIZE, m_vertices, GL_STREAM_DRAW );
checkGlError( "transferring vertices", __FILE__, __LINE__ );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
checkGlError( "unbinding vertices buffer", __FILE__, __LINE__ );
}
bool CACHED_CONTAINER_RAM::defragmentResize( unsigned int aNewSize )
{
wxLogTrace( traceGalCachedContainer,
wxT( "Resizing & defragmenting container (memcpy) from %d to %d" ), m_currentSize,
aNewSize );
// No shrinking if we cannot fit all the data
if( usedSpace() > aNewSize )
return false;
#ifdef KICAD_GAL_PROFILE
PROF_TIMER totalTime;
#endif /* KICAD_GAL_PROFILE */
VERTEX* newBufferMem = static_cast<VERTEX*>( malloc( aNewSize * VERTEX_SIZE ) );
if( !newBufferMem )
throw std::bad_alloc();
defragment( newBufferMem );
// Switch to the new vertex buffer
free( m_vertices );
m_vertices = newBufferMem;
#ifdef KICAD_GAL_PROFILE
totalTime.Stop();
wxLogTrace( traceGalCachedContainer, "Defragmented container storing %d vertices / %.1f ms",
m_currentSize - m_freeSpace, totalTime.msecs() );
#endif /* KICAD_GAL_PROFILE */
m_freeSpace += ( aNewSize - m_currentSize );
m_currentSize = aNewSize;
// Now there is only one big chunk of free memory
m_freeChunks.clear();
m_freeChunks.insert( std::make_pair( m_freeSpace, m_currentSize - m_freeSpace ) );
m_dirty = true;
return true;
}

View file

@ -0,0 +1,86 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright 2013-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef CACHED_CONTAINER_RAM_H_
#define CACHED_CONTAINER_RAM_H_
#include "cached_container.h"
#include <map>
#include <set>
namespace KIGFX
{
class VERTEX_ITEM;
class SHADER;
/**
* Specialization of CACHED_CONTAINER that stores data in RAM.
*
* This is mainly for video cards/drivers that do not cope well with video memory mapping.
*/
class CACHED_CONTAINER_RAM : public CACHED_CONTAINER
{
public:
CACHED_CONTAINER_RAM( unsigned int aSize = DEFAULT_SIZE );
~CACHED_CONTAINER_RAM();
///< @copydoc VERTEX_CONTAINER::Unmap()
void Map() override {}
///< @copydoc VERTEX_CONTAINER::Unmap()
void Unmap() override;
bool IsMapped() const override
{
return true;
}
/**
* Return handle to the vertex buffer.
*
* It might be negative if the buffer is not initialized.
*/
unsigned int GetBufferHandle() const override
{
return m_verticesBuffer; // make common with CACHED_CONTAINER_RAM
}
protected:
/**
* Defragment the currently stored data and resizes the buffer.
*
* @param aNewSize is the new buffer vertex buffer size, expressed as the number of vertices.
* @return true on success.
*/
bool defragmentResize( unsigned int aNewSize ) override;
///< Handle to vertices buffer
GLuint m_verticesBuffer;
};
} // namespace KIGFX
#endif /* CACHED_CONTAINER_RAM_H_ */

View file

@ -0,0 +1,118 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "gl_context_mgr.h"
#include <wx/debug.h>
wxGLContext* GL_CONTEXT_MANAGER::CreateCtx( wxGLCanvas* aCanvas, const wxGLContext* aOther )
{
wxGLContext* context = new wxGLContext( aCanvas, aOther );
wxCHECK( context, nullptr );
if( !context->IsOK() )
{
delete context;
return nullptr;
}
m_glContexts.insert( std::make_pair( context, aCanvas ) );
return context;
}
void GL_CONTEXT_MANAGER::DestroyCtx( wxGLContext* aContext )
{
if( m_glContexts.count( aContext ) )
{
m_glContexts.erase( aContext );
delete aContext;
}
else
{
// Do not delete unknown GL contexts
wxFAIL;
}
if( m_glCtx == aContext )
m_glCtx = nullptr;
}
void GL_CONTEXT_MANAGER::DeleteAll()
{
m_glCtxMutex.lock();
for( auto& ctx : m_glContexts )
delete ctx.first;
m_glContexts.clear();
m_glCtx = nullptr;
m_glCtxMutex.unlock();
}
void GL_CONTEXT_MANAGER::LockCtx( wxGLContext* aContext, wxGLCanvas* aCanvas )
{
wxCHECK( aContext && m_glContexts.count( aContext ) > 0, /* void */ );
m_glCtxMutex.lock();
wxGLCanvas* canvas = aCanvas ? aCanvas : m_glContexts.at( aContext );
// Prevent assertion failure in wxGLContext::SetCurrent during GAL teardown
#ifdef __WXGTK__
#ifdef KICAD_USE_EGL
if( canvas->GTKGetDrawingWindow() )
#else
if( canvas->GetXWindow() )
#endif // KICAD_USE_EGL
#endif // __WXGTK__
{
canvas->SetCurrent( *aContext );
}
m_glCtx = aContext;
}
void GL_CONTEXT_MANAGER::UnlockCtx( wxGLContext* aContext )
{
wxCHECK( aContext && m_glContexts.count( aContext ) > 0, /* void */ );
if( m_glCtx == aContext )
{
m_glCtxMutex.unlock();
m_glCtx = nullptr;
}
else
{
wxFAIL_MSG( wxString::Format( wxS( "Trying to unlock GL context mutex from "
"a wrong context: aContext %p m_glCtx %p" ), aContext, m_glCtx ) );
}
}

View file

@ -0,0 +1,147 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef GL_CONTEXT_MANAGER_H
#define GL_CONTEXT_MANAGER_H
#include <kicommon.h>
#include <gal/gal.h>
#include <wx/glcanvas.h>
#include <mutex>
#include <map>
class KICOMMON_API GL_CONTEXT_MANAGER
{
public:
GL_CONTEXT_MANAGER() : m_glCtx( nullptr ) {}
/**
* Create a managed OpenGL context.
*
* It is assured that the created context is freed upon exit. See wxGLContext
* documentation for the parameters description.
*
* @return Created OpenGL context.
*/
wxGLContext* CreateCtx( wxGLCanvas* aCanvas, const wxGLContext* aOther = nullptr );
/**
* Destroy a managed OpenGL context.
*
* The context to be removed has to be created using GL_CONTEXT_MANAGER::CreateCtx() first.
*
* @param aContext is the OpenGL context to be destroyed. It will not be managed anymore.
*/
void DestroyCtx( wxGLContext* aContext );
/**
* Destroy all managed OpenGL contexts.
*
* This method should be called in the final deinitialization routine.
*/
void DeleteAll();
/**
* Set a context as current and prevents other canvases from switching it.
*
* Requires calling UnlockCtx() when there are no more GL calls for the context. If
* another canvas has already locked a GL context, then the calling process is blocked.
*
* @param aContext is the GL context to be bound.
* @param aCanvas (optional) allows caller to bind the context to a non-parent canvas
* (e.g. when a few canvases share a single GL context).
*/
void LockCtx( wxGLContext* aContext, wxGLCanvas* aCanvas );
/**
* Allow other canvases to bind an OpenGL context.
*
* @param aContext is the currently bound context. It is only a check to assure the right
* canvas wants to unlock GL context.
*/
void UnlockCtx( wxGLContext* aContext );
/**
* Get the currently bound GL context.
*
* @return the currently bound GL context.
*/
wxGLContext* GetCurrentCtx() const
{
return m_glCtx;
}
/**
* Get the currently bound GL canvas.
*
* @return the currently bound GL canvas.
*/
wxGLCanvas* GetCurrentCanvas() const
{
auto it = m_glContexts.find( m_glCtx );
return it != m_glContexts.end() ? it->second : nullptr;
}
/**
* Run the given function first releasing the GL context lock, then restoring it.
*
* @param aFunction is the function to be executed.
*/
template<typename Func, typename... Args>
auto RunWithoutCtxLock( Func&& aFunction, Args&&... args )
{
wxGLContext* currentCtx = GetCurrentCtx();
wxGLCanvas* currentCanvas = GetCurrentCanvas();
UnlockCtx( currentCtx );
if constexpr (std::is_void_v<decltype(aFunction(std::forward<Args>(args)...))>)
{
std::forward<Func>(aFunction)(std::forward<Args>(args)...);
LockCtx( currentCtx, currentCanvas );
return;
}
else
{
auto result = std::forward<Func>(aFunction)(std::forward<Args>(args)...);
LockCtx( currentCtx, currentCanvas );
return result;
}
}
private:
///< Map of GL contexts & their parent canvases.
std::map<wxGLContext*, wxGLCanvas*> m_glContexts;
///< Currently bound GL context.
wxGLContext* m_glCtx;
///< Lock to prevent unexpected GL context switching.
std::mutex m_glCtxMutex;
};
#endif /* GL_CONTEXT_MANAGER_H */

View file

@ -0,0 +1,63 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
// The current font is "Ubuntu Mono" available under Ubuntu Font Licence 1.0
// (see ubuntu-font-licence-1.0.txt for details)
#include <algorithm>
#include "gl_resources.h"
#define BITMAP_FONT_USE_SPANS
namespace KIGFX {
namespace BUILTIN_FONT {
#include "bitmap_font_img.c"
#include "bitmap_font_desc.c"
const FONT_GLYPH_TYPE* LookupGlyph( unsigned int aCodepoint )
{
#ifdef BITMAP_FONT_USE_SPANS
auto *end = font_codepoint_spans + sizeof( font_codepoint_spans ) / sizeof(FONT_SPAN_TYPE);
auto ptr = std::upper_bound( font_codepoint_spans, end, aCodepoint,
[]( unsigned int codepoint, const FONT_SPAN_TYPE& span )
{
return codepoint < span.end;
} );
if( ptr != end && ptr->start <= aCodepoint )
{
unsigned int index = aCodepoint - ptr->start + ptr->cumulative;
return &font_codepoint_infos[ index ];
}
else
{
return nullptr;
}
#else
return &bitmap_chars[codepoint];
#endif
}
}
}

View file

@ -0,0 +1,73 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef GAL_OPENGL_RESOURCES_H___
#define GAL_OPENGL_RESOURCES_H___
#define BITMAP_FONT_USE_SPANS
namespace KIGFX {
namespace BUILTIN_FONT {
struct FONT_IMAGE_TYPE
{
unsigned int width, height;
unsigned int char_border;
unsigned int spacing;
unsigned char pixels[1024 * 1024 * 3];
};
struct FONT_INFO_TYPE
{
unsigned int smooth_pixels;
float min_y;
float max_y;
};
struct FONT_SPAN_TYPE
{
unsigned int start;
unsigned int end;
unsigned int cumulative;
};
struct FONT_GLYPH_TYPE
{
unsigned int atlas_x, atlas_y;
unsigned int atlas_w, atlas_h;
float minx, maxx;
float miny, maxy;
float advance;
};
extern FONT_IMAGE_TYPE font_image;
extern FONT_INFO_TYPE font_information;
const FONT_GLYPH_TYPE* LookupGlyph( unsigned int aCodePoint );
}
}
#endif

View file

@ -0,0 +1,172 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef GL_UTILS_H
#define GL_UTILS_H
#include "kiglew.h" // Must be included first
#include <wx/glcanvas.h>
#include <wx/utils.h>
#ifdef _WIN32
#ifdef __MINGW32__
#pragma GCC push_options
#pragma GCC optimize( "O0" )
#else
#pragma optimize( "", off )
#endif
#endif
class GL_UTILS
{
public:
/**
* Attempt to set the OpenGL swap interval.
*
* @param aVal if -1 = try to set adaptive swapping, 0 = sync off, 1 = sync with VSYNC rate.
* @return actual value set
*/
static int SetSwapInterval( int aVal )
{
#if defined( __linux__ ) && !defined( KICAD_USE_EGL )
if( Display* dpy = glXGetCurrentDisplay() )
{
GLXDrawable drawable = glXGetCurrentDrawable();
std::string exts( glXQueryExtensionsString( dpy, DefaultScreen( dpy ) ) );
if( glXSwapIntervalEXT && glXQueryDrawable && drawable
&& exts.find( "GLX_EXT_swap_control" ) != std::string::npos )
{
if( aVal == -1 )
{
if( exts.find( "GLX_EXT_swap_control_tear" ) == std::string::npos )
{
aVal = 1;
}
else
{
// Even though the extensions might be available,
// we need to be sure that late/adaptive swaps are
// enabled on the drawable.
unsigned lateSwapsEnabled = 0;
glXQueryDrawable( dpy, drawable, GLX_LATE_SWAPS_TEAR_EXT,
&lateSwapsEnabled );
if( !lateSwapsEnabled )
{
aVal = 0;
}
}
}
unsigned clampedInterval;
glXSwapIntervalEXT( dpy, drawable, aVal );
glXQueryDrawable( dpy, drawable, GLX_SWAP_INTERVAL_EXT, &clampedInterval );
return clampedInterval;
}
if( glXSwapIntervalMESA && glXGetSwapIntervalMESA
&& exts.find( "GLX_MESA_swap_control" ) != std::string::npos )
{
if( aVal == -1 )
aVal = 1;
if( !glXSwapIntervalMESA( aVal ) )
return aVal;
}
if( glXSwapIntervalSGI && exts.find( "GLX_SGI_swap_control" ) != std::string::npos )
{
if( aVal == -1 )
aVal = 1;
if( !glXSwapIntervalSGI( aVal ) )
return aVal;
}
}
#elif defined( _WIN32 )
const GLubyte* vendor = glGetString( GL_VENDOR );
const GLubyte* version = glGetString( GL_VERSION );
if( wglSwapIntervalEXT && wxGLCanvas::IsExtensionSupported( "WGL_EXT_swap_control" ) )
{
wxString vendorStr = vendor;
wxString versionStr = version;
if( aVal == -1 && ( !wxGLCanvas::IsExtensionSupported( "WGL_EXT_swap_control_tear" ) ) )
aVal = 1;
// Trying to enable adaptive swapping on AMD drivers from 2017 or older leads to crash
if( aVal == -1 && vendorStr == wxS( "ATI Technologies Inc." ) )
{
wxArrayString parts = wxSplit( versionStr.AfterLast( ' ' ), '.', 0 );
if( parts.size() == 4 )
{
long majorVer = 0;
if( parts[0].ToLong( &majorVer ) )
{
if( majorVer <= 22 )
aVal = 1;
}
}
}
HDC hdc = wglGetCurrentDC();
HGLRC hglrc = wglGetCurrentContext();
if( hdc && hglrc )
{
int currentInterval = wglGetSwapIntervalEXT();
if( currentInterval != aVal )
{
wglSwapIntervalEXT( aVal );
currentInterval = wglGetSwapIntervalEXT();
}
return currentInterval;
}
}
#endif
return 0;
}
};
#ifdef _WIN32
#ifdef __MINGW32__
#pragma GCC pop_options
#else
#pragma optimize( "", on )
#endif
#endif
#endif /* GL_CONTEXT_MANAGER_H */

View file

@ -0,0 +1,340 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright 2013-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "gpu_manager.h"
#include "cached_container_gpu.h"
#include "cached_container_ram.h"
#include "noncached_container.h"
#include "shader.h"
#include "utils.h"
#include "vertex_item.h"
#include <core/profile.h>
#include <typeinfo>
#include <confirm.h>
#include <trace_helpers.h>
#ifdef KICAD_GAL_PROFILE
#include <core/profile.h>
#include <wx/log.h>
#endif /* KICAD_GAL_PROFILE */
using namespace KIGFX;
GPU_MANAGER* GPU_MANAGER::MakeManager( VERTEX_CONTAINER* aContainer )
{
if( aContainer->IsCached() )
return new GPU_CACHED_MANAGER( aContainer );
else
return new GPU_NONCACHED_MANAGER( aContainer );
}
GPU_MANAGER::GPU_MANAGER( VERTEX_CONTAINER* aContainer ) :
m_isDrawing( false ),
m_container( aContainer ),
m_shader( nullptr ),
m_shaderAttrib( 0 ),
m_enableDepthTest( true )
{
}
GPU_MANAGER::~GPU_MANAGER()
{
}
void GPU_MANAGER::SetShader( SHADER& aShader )
{
m_shader = &aShader;
m_shaderAttrib = m_shader->GetAttribute( "a_shaderParams" );
if( m_shaderAttrib == -1 )
{
DisplayError( nullptr, wxT( "Could not get the shader attribute location" ) );
}
}
// Cached manager
GPU_CACHED_MANAGER::GPU_CACHED_MANAGER( VERTEX_CONTAINER* aContainer ) :
GPU_MANAGER( aContainer ),
m_buffersInitialized( false ),
m_indicesCapacity( 0 ),
m_totalHuge( 0 ),
m_totalNormal( 0 ),
m_indexBufSize( 0 ),
m_indexBufMaxSize( 0 ),
m_curVrangeSize( 0 )
{
}
GPU_CACHED_MANAGER::~GPU_CACHED_MANAGER()
{
}
void GPU_CACHED_MANAGER::BeginDrawing()
{
wxASSERT( !m_isDrawing );
m_curVrangeSize = 0;
m_indexBufMaxSize = 0;
m_indexBufSize = 0;
m_vranges.clear();
m_isDrawing = true;
}
void GPU_CACHED_MANAGER::DrawIndices( const VERTEX_ITEM* aItem )
{
// Hot path: don't use wxASSERT
assert( m_isDrawing );
unsigned int offset = aItem->GetOffset();
unsigned int size = aItem->GetSize();
if( size == 0 )
return;
if( size <= 1000 )
{
m_totalNormal += size;
m_vranges.emplace_back( offset, offset + size - 1, false );
m_curVrangeSize += size;
}
else
{
m_totalHuge += size;
m_vranges.emplace_back( offset, offset + size - 1, true );
m_indexBufSize = std::max( m_curVrangeSize, m_indexBufSize );
m_curVrangeSize = 0;
}
}
void GPU_CACHED_MANAGER::EndDrawing()
{
wxASSERT( m_isDrawing );
CACHED_CONTAINER* cached = static_cast<CACHED_CONTAINER*>( m_container );
if( cached->IsMapped() )
cached->Unmap();
m_indexBufSize = std::max( m_curVrangeSize, m_indexBufSize );
m_indexBufMaxSize = std::max( 2*m_indexBufSize, m_indexBufMaxSize );
resizeIndices( m_indexBufMaxSize );
if( m_enableDepthTest )
glEnable( GL_DEPTH_TEST );
else
glDisable( GL_DEPTH_TEST );
// Prepare buffers
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
// Bind vertices data buffers
glBindBuffer( GL_ARRAY_BUFFER, cached->GetBufferHandle() );
glVertexPointer( COORD_STRIDE, GL_FLOAT, VERTEX_SIZE, (GLvoid*) COORD_OFFSET );
glColorPointer( COLOR_STRIDE, GL_UNSIGNED_BYTE, VERTEX_SIZE, (GLvoid*) COLOR_OFFSET );
if( m_shader != nullptr ) // Use shader if applicable
{
m_shader->Use();
glEnableVertexAttribArray( m_shaderAttrib );
glVertexAttribPointer( m_shaderAttrib, SHADER_STRIDE, GL_FLOAT, GL_FALSE, VERTEX_SIZE,
(GLvoid*) SHADER_OFFSET );
}
PROF_TIMER cntDraw( "gl-draw-elements" );
int n_ranges = m_vranges.size();
int n = 0;
GLuint* iptr = m_indices.get();
GLuint icnt = 0;
int drawCalls = 0;
while( n < n_ranges )
{
VRANGE* cur = &m_vranges[n];
if( cur->m_isContinuous )
{
if( icnt > 0 )
{
glDrawElements( GL_TRIANGLES, icnt, GL_UNSIGNED_INT, m_indices.get() );
drawCalls++;
}
icnt = 0;
iptr = m_indices.get();
glDrawArrays( GL_TRIANGLES, cur->m_start, cur->m_end - cur->m_start + 1 );
drawCalls++;
}
else
{
for( GLuint i = cur->m_start; i <= cur->m_end; i++ )
{
*iptr++ = i;
icnt++;
}
}
n++;
}
if( icnt > 0 )
{
glDrawElements( GL_TRIANGLES, icnt, GL_UNSIGNED_INT, m_indices.get() );
drawCalls++;
}
cntDraw.Stop();
KI_TRACE( traceGalProfile,
"Cached manager size: VBO size %u iranges %zu max elt size %u drawcalls %u\n",
cached->AllItemsSize(), m_vranges.size(), m_indexBufMaxSize, drawCalls );
KI_TRACE( traceGalProfile, "Timing: %s\n", cntDraw.to_string() );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
cached->ClearDirty();
// Deactivate vertex array
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
if( m_shader != nullptr )
{
glDisableVertexAttribArray( m_shaderAttrib );
m_shader->Deactivate();
}
m_isDrawing = false;
}
void GPU_CACHED_MANAGER::resizeIndices( unsigned int aNewSize )
{
if( aNewSize > m_indicesCapacity )
{
m_indicesCapacity = aNewSize;
m_indices.reset( new GLuint[m_indicesCapacity] );
}
}
// Noncached manager
GPU_NONCACHED_MANAGER::GPU_NONCACHED_MANAGER( VERTEX_CONTAINER* aContainer ) :
GPU_MANAGER( aContainer )
{
}
void GPU_NONCACHED_MANAGER::BeginDrawing()
{
// Nothing has to be prepared
}
void GPU_NONCACHED_MANAGER::DrawIndices( const VERTEX_ITEM* aItem )
{
wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
}
void GPU_NONCACHED_MANAGER::EndDrawing()
{
#ifdef KICAD_GAL_PROFILE
PROF_TIMER totalRealTime;
#endif /* KICAD_GAL_PROFILE */
if( m_container->GetSize() == 0 )
return;
VERTEX* vertices = m_container->GetAllVertices();
GLfloat* coordinates = (GLfloat*) ( vertices );
GLubyte* colors = (GLubyte*) ( vertices ) + COLOR_OFFSET;
if( m_enableDepthTest )
glEnable( GL_DEPTH_TEST );
else
glDisable( GL_DEPTH_TEST );
// Prepare buffers
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
glVertexPointer( COORD_STRIDE, GL_FLOAT, VERTEX_SIZE, coordinates );
glColorPointer( COLOR_STRIDE, GL_UNSIGNED_BYTE, VERTEX_SIZE, colors );
if( m_shader != nullptr ) // Use shader if applicable
{
GLfloat* shaders = (GLfloat*) ( vertices ) + SHADER_OFFSET / sizeof( GLfloat );
m_shader->Use();
glEnableVertexAttribArray( m_shaderAttrib );
glVertexAttribPointer( m_shaderAttrib, SHADER_STRIDE, GL_FLOAT, GL_FALSE, VERTEX_SIZE,
shaders );
}
glDrawArrays( GL_TRIANGLES, 0, m_container->GetSize() );
#ifdef KICAD_GAL_PROFILE
wxLogTrace( traceGalProfile, wxT( "Noncached manager size: %d" ), m_container->GetSize() );
#endif /* KICAD_GAL_PROFILE */
// Deactivate vertex array
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
if( m_shader != nullptr )
{
glDisableVertexAttribArray( m_shaderAttrib );
m_shader->Deactivate();
}
m_container->Clear();
#ifdef KICAD_GAL_PROFILE
totalRealTime.Stop();
wxLogTrace( traceGalProfile, wxT( "GPU_NONCACHED_MANAGER::EndDrawing(): %.1f ms" ),
totalRealTime.msecs() );
#endif /* KICAD_GAL_PROFILE */
}
void GPU_MANAGER::EnableDepthTest( bool aEnabled )
{
m_enableDepthTest = aEnabled;
}

View file

@ -0,0 +1,188 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef GPU_MANAGER_H_
#define GPU_MANAGER_H_
#include <vector>
#include "vertex_common.h"
#include <boost/scoped_array.hpp>
namespace KIGFX
{
class SHADER;
class VERTEX_CONTAINER;
class VERTEX_ITEM;
class CACHED_CONTAINER;
class NONCACHED_CONTAINER;
/**
* Class to handle uploading vertices and indices to GPU in drawing purposes.
*/
class GPU_MANAGER
{
public:
static GPU_MANAGER* MakeManager( VERTEX_CONTAINER* aContainer );
virtual ~GPU_MANAGER();
/**
* Prepare the stored data to be drawn.
*/
virtual void BeginDrawing() = 0;
/**
* Make the GPU draw given range of vertices.
*
* @param aOffset is the beginning of the range.
* @param aSize is the number of vertices to be drawn.
*/
virtual void DrawIndices( const VERTEX_ITEM* aItem ) = 0;
/**
* Clear the container after drawing routines.
*/
virtual void EndDrawing() = 0;
/**
* Allow using shaders with the stored data.
*
* @param aShader is the object that allows using shaders.
*/
virtual void SetShader( SHADER& aShader );
/**
* Enable/disable Z buffer depth test.
*/
void EnableDepthTest( bool aEnabled );
protected:
GPU_MANAGER( VERTEX_CONTAINER* aContainer );
///< Drawing status flag.
bool m_isDrawing;
///< Container that stores vertices data.
VERTEX_CONTAINER* m_container;
///< Shader handling
SHADER* m_shader;
///< Location of shader attributes (for glVertexAttribPointer)
int m_shaderAttrib;
///< true: enable Z test when drawing
bool m_enableDepthTest;
};
class GPU_CACHED_MANAGER : public GPU_MANAGER
{
public:
struct VRANGE
{
VRANGE( int aStart, int aEnd, bool aContinuous ) :
m_start( aStart ),
m_end( aEnd ),
m_isContinuous( aContinuous )
{
}
unsigned int m_start, m_end;
bool m_isContinuous;
};
GPU_CACHED_MANAGER( VERTEX_CONTAINER* aContainer );
~GPU_CACHED_MANAGER();
///< @copydoc GPU_MANAGER::BeginDrawing()
virtual void BeginDrawing() override;
///< @copydoc GPU_MANAGER::DrawIndices()
virtual void DrawIndices( const VERTEX_ITEM* aItem ) override;
///< @copydoc GPU_MANAGER::EndDrawing()
virtual void EndDrawing() override;
///< Map vertex buffer stored in GPU memory.
void Map();
///< Unmap vertex buffer.
void Unmap();
protected:
///< Resizes the indices buffer to aNewSize if necessary
void resizeIndices( unsigned int aNewSize );
///< Buffers initialization flag
bool m_buffersInitialized;
///< Pointer to the current indices buffer
boost::scoped_array<GLuint> m_indices;
///< Current indices buffer size
unsigned int m_indicesCapacity;
///< Ranges of visible vertex indices to render
std::vector<VRANGE> m_vranges;
///< Number of huge VRANGEs (i.e. large zones) with separate draw calls
int m_totalHuge;
///< Number of regular VRANGEs (small items) pooled into single draw call
int m_totalNormal;
///< Current size of index buffer
unsigned int m_indexBufSize;
///< Maximum size taken by the index buffer for all frames rendered so far
unsigned int m_indexBufMaxSize;
///< Size of the current VRANGE
unsigned int m_curVrangeSize;
};
class GPU_NONCACHED_MANAGER : public GPU_MANAGER
{
public:
GPU_NONCACHED_MANAGER( VERTEX_CONTAINER* aContainer );
///< @copydoc GPU_MANAGER::BeginDrawing()
virtual void BeginDrawing() override;
///< @copydoc GPU_MANAGER::DrawIndices()
virtual void DrawIndices( const VERTEX_ITEM* aItem ) override;
///< @copydoc GPU_MANAGER::EndDrawing()
virtual void EndDrawing() override;
};
} // namespace KIGFX
#endif /* GPU_MANAGER_H_ */

View file

@ -0,0 +1,258 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* This file is used for including the proper GLEW header for the platform.
*/
#ifndef KIGLEW_H_
#define KIGLEW_H_
// Pull in the configuration options for wxWidgets
#include <wx/platform.h>
#if defined( __EMSCRIPTEN__ )
// WebGL2/GLES3: Modern shader functions (glUseProgram, etc.)
#include <GLES3/gl3.h>
// Legacy GL emulation: glMatrixMode, glColor4d, glBegin/glEnd, etc.
#include <GL/gl.h>
// GLU tesselator - provided by wasm/stubs/glu_wasm_impl.cpp
#include <GL/glu.h>
// GLEW compatibility stubs for WebGL
#define GLEW_OK 0
#define GLEW_VERSION 1
#define GLEW_VERSION_1_2 1
#define GLEW_VERSION_1_3 1
#define GLEW_VERSION_1_4 1
#define GLEW_VERSION_1_5 1
#define GLEW_VERSION_2_0 1
#define GLEW_VERSION_2_1 1
#define GLEW_ARB_vertex_array_object 1
#define GLEW_ARB_vertex_buffer_object 1
#define GLEW_ARB_framebuffer_object 1
#define GLEW_EXT_framebuffer_object 1
#define GLEW_ARB_texture_non_power_of_two 1
#define GLEW_ARB_copy_buffer 0 // Not available in WebGL 1.0
#define GLEW_EXT_framebuffer_multisample 0 // Limited in WebGL
inline int glewInit() { return GLEW_OK; }
inline const unsigned char* glewGetString(int) { return (const unsigned char*)"WebGL"; }
inline const char* glewGetErrorString(int) { return ""; }
inline int glewIsSupported(const char*) { return 1; }
// VAO functions - available in WebGL2 / OpenGL ES 3.0
#ifndef GL_VERTEX_ARRAY_BINDING
#define GL_VERTEX_ARRAY_BINDING 0x85B5
#endif
// Geometry shader extensions - not supported in WebGL
#ifndef GL_GEOMETRY_VERTICES_OUT_EXT
#define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA
#define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB
#define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC
#endif
// Geometry shader function stub (not supported in WebGL)
inline void glProgramParameteriEXT(GLuint program, GLenum pname, GLint value) {
(void)program; (void)pname; (void)value;
}
// glMapBuffer family - not available in WebGL 1.0
// Return nullptr to signal failure, KiCad has RAM-based fallback
inline void* glMapBuffer(GLenum target, GLenum access) {
(void)target; (void)access;
return nullptr;
}
inline GLboolean glUnmapBuffer(GLenum target) {
(void)target;
return GL_TRUE;
}
// Buffer copy - not available in WebGL 1.0, no-op stub
inline void glCopyBufferSubData(GLenum readTarget, GLenum writeTarget,
GLintptr readOffset, GLintptr writeOffset,
GLsizeiptr size) {
(void)readTarget; (void)writeTarget;
(void)readOffset; (void)writeOffset; (void)size;
}
// EXT framebuffer functions - alias to standard GL ES 2.0 functions
#ifndef GL_FRAMEBUFFER_EXT
#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER
#endif
#ifndef GL_RENDERBUFFER_EXT
#define GL_RENDERBUFFER_EXT GL_RENDERBUFFER
#endif
#ifndef GL_FRAMEBUFFER_COMPLETE_EXT
#define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE
#endif
#define glGenFramebuffersEXT glGenFramebuffers
#define glDeleteFramebuffersEXT glDeleteFramebuffers
#define glBindFramebufferEXT glBindFramebuffer
#define glCheckFramebufferStatusEXT glCheckFramebufferStatus
#define glFramebufferTexture2DEXT glFramebufferTexture2D
#define glFramebufferRenderbufferEXT glFramebufferRenderbuffer
#define glGenRenderbuffersEXT glGenRenderbuffers
#define glDeleteRenderbuffersEXT glDeleteRenderbuffers
#define glBindRenderbufferEXT glBindRenderbuffer
#define glRenderbufferStorageEXT glRenderbufferStorage
// GL_DEPTH24_STENCIL8 - map to GLES2/WebGL constant
#ifndef GL_DEPTH24_STENCIL8
#define GL_DEPTH24_STENCIL8 0x88F0
#endif
// GL_DEPTH_STENCIL_ATTACHMENT - WebGL uses separate depth/stencil, but this constant exists
#ifndef GL_DEPTH_STENCIL_ATTACHMENT
#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
#endif
// Debug output - not available in WebGL, no-op stubs
#ifndef GL_DEBUG_OUTPUT
#define GL_DEBUG_OUTPUT 0x92E0
#endif
#ifndef GLchar
typedef char GLchar;
#endif
typedef void (*GLDEBUGPROC)(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar* message, const void* userParam);
inline void glDebugMessageCallback(GLDEBUGPROC callback, const void* userParam) {
(void)callback; (void)userParam;
}
// GLdouble type for double-precision functions
#ifndef GLdouble
typedef double GLdouble;
#endif
// Double-precision GL function wrappers - LEGACY_GL_EMULATION only provides float versions
// These convert double arguments to float and call the float variants
inline void glVertex2d(GLdouble x, GLdouble y) {
glVertex2f((GLfloat)x, (GLfloat)y);
}
inline void glVertex3d(GLdouble x, GLdouble y, GLdouble z) {
glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
}
inline void glColor4d(GLdouble r, GLdouble g, GLdouble b, GLdouble a) {
glColor4f((GLfloat)r, (GLfloat)g, (GLfloat)b, (GLfloat)a);
}
inline void glColor3d(GLdouble r, GLdouble g, GLdouble b) {
glColor3f((GLfloat)r, (GLfloat)g, (GLfloat)b);
}
inline void glTranslated(GLdouble x, GLdouble y, GLdouble z) {
glTranslatef((GLfloat)x, (GLfloat)y, (GLfloat)z);
}
inline void glScaled(GLdouble x, GLdouble y, GLdouble z) {
glScalef((GLfloat)x, (GLfloat)y, (GLfloat)z);
}
inline void glRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z) {
glRotatef((GLfloat)angle, (GLfloat)x, (GLfloat)y, (GLfloat)z);
}
inline void glNormal3d(GLdouble x, GLdouble y, GLdouble z) {
glNormal3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
}
inline void glTexCoord2d(GLdouble s, GLdouble t) {
glTexCoord2f((GLfloat)s, (GLfloat)t);
}
inline void glRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) {
glRectf((GLfloat)x1, (GLfloat)y1, (GLfloat)x2, (GLfloat)y2);
}
inline void glLoadMatrixd(const GLdouble* m) {
GLfloat fm[16];
for(int i = 0; i < 16; i++) fm[i] = (GLfloat)m[i];
glLoadMatrixf(fm);
}
inline void glMultMatrixd(const GLdouble* m) {
GLfloat fm[16];
for(int i = 0; i < 16; i++) fm[i] = (GLfloat)m[i];
glMultMatrixf(fm);
}
// Display lists - not supported in WebGL, stub implementations
inline GLuint glGenLists(GLsizei range) { (void)range; return 0; }
inline GLboolean glIsList(GLuint list) { (void)list; return GL_FALSE; }
inline void glNewList(GLuint list, GLenum mode) { (void)list; (void)mode; }
inline void glEndList(void) {}
inline void glCallList(GLuint list) { (void)list; }
inline void glDeleteLists(GLuint list, GLsizei range) { (void)list; (void)range; }
// Lighting and material functions - stubs (lighting not fully supported in WebGL)
inline void glLightModeli(GLenum pname, GLint param) { (void)pname; (void)param; }
inline void glColorMaterial(GLenum face, GLenum mode) { (void)face; (void)mode; }
inline void glMaterialf(GLenum face, GLenum pname, GLfloat param) {
(void)face; (void)pname; (void)param;
}
inline void glMaterialfv(GLenum face, GLenum pname, const GLfloat* params) {
(void)face; (void)pname; (void)params;
}
inline void glLightfv(GLenum light, GLenum pname, const GLfloat* params) {
(void)light; (void)pname; (void)params;
}
inline void glLightf(GLenum light, GLenum pname, GLfloat param) {
(void)light; (void)pname; (void)param;
}
#elif defined( __unix__ ) and not defined( __APPLE__ )
#ifdef KICAD_USE_EGL
#if wxUSE_GLCANVAS_EGL
// wxWidgets was compiled with the EGL canvas, so use the EGL header for GLEW
#include <GL/eglew.h>
#else
#error "KICAD_USE_EGL can only be used when wxWidgets is compiled with the EGL canvas"
#endif
#else // KICAD_USE_EGL
#if wxUSE_GLCANVAS_EGL
#error "KICAD_USE_EGL must be defined since wxWidgets has been compiled with the EGL canvas"
#else
// wxWidgets wasn't compiled with the EGL canvas, so use the X11 GLEW
#include <GL/glxew.h>
#endif
#endif // KICAD_USE_EGL
#else // defined( __unix__ ) and not defined( __APPLE__ )
// Non-GTK platforms only need the normal GLEW include
#include <GL/glew.h>
#endif // defined( __unix__ ) and not defined( __APPLE__ )
#ifdef _WIN32
#include <GL/wglew.h>
#endif // _WIN32
#endif // KIGLEW_H_

View file

@ -0,0 +1,102 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file noncached_container.cpp
* @brief Class to store instances of VERTEX without caching. It allows a fast one-frame drawing
* and then clearing the buffer and starting from scratch.
*/
#include "noncached_container.h"
#include <cstring>
#include <cstdlib>
using namespace KIGFX;
NONCACHED_CONTAINER::NONCACHED_CONTAINER( unsigned int aSize ) :
VERTEX_CONTAINER( aSize ),
m_freePtr( 0 )
{
m_vertices = static_cast<VERTEX*>( malloc( aSize * sizeof( VERTEX ) ) );
// Unfortunately we cannot remove the use of malloc here because realloc is used in
// the Allocate method below. The new operator behavior is mimicked here so that a
// malloc failure can be caught in the OpenGL initialization code further up the stack.
if( !m_vertices )
throw std::bad_alloc();
memset( m_vertices, 0x00, aSize * sizeof( VERTEX ) );
}
NONCACHED_CONTAINER::~NONCACHED_CONTAINER()
{
free( m_vertices );
}
void NONCACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem )
{
// Nothing has to be done, as the noncached container
// does not care about VERTEX_ITEMs ownership
}
VERTEX* NONCACHED_CONTAINER::Allocate( unsigned int aSize )
{
if( m_freeSpace < aSize )
{
// Double the space
VERTEX* newVertices =
static_cast<VERTEX*>( realloc( m_vertices, m_currentSize * 2 * sizeof( VERTEX ) ) );
if( newVertices != nullptr )
{
m_vertices = newVertices;
m_freeSpace += m_currentSize;
m_currentSize *= 2;
}
else
{
throw std::bad_alloc();
}
}
VERTEX* freeVertex = &m_vertices[m_freePtr];
// Move to the next free chunk
m_freePtr += aSize;
m_freeSpace -= aSize;
return freeVertex;
}
void NONCACHED_CONTAINER::Clear()
{
m_freePtr = 0;
m_freeSpace = m_currentSize;
}

View file

@ -0,0 +1,85 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file noncached_container.h
* @brief Class to store instances of VERTEX without caching. It allows a fast one-frame drawing
* and then clearing the buffer and starting from scratch.
*/
#ifndef NONCACHED_CONTAINER_H_
#define NONCACHED_CONTAINER_H_
#include "vertex_container.h"
namespace KIGFX
{
class VERTEX_ITEM;
class SHADER;
class NONCACHED_CONTAINER : public VERTEX_CONTAINER
{
public:
/**
* Construct a non-cached container object.
*
* @param aSize is the size of the cache.
* @throw bad_alloc exception if memory allocation fails.
*/
NONCACHED_CONTAINER( unsigned int aSize = DEFAULT_SIZE );
virtual ~NONCACHED_CONTAINER();
bool IsCached() const override
{
return false;
}
/// @copydoc VERTEX_CONTAINER::SetItem( VERTEX_ITEM* aItem )
virtual void SetItem( VERTEX_ITEM* aItem ) override;
/// @copydoc VERTEX_CONTAINER::Allocate( unsigned int aSize )
virtual VERTEX* Allocate( unsigned int aSize ) override;
/// @copydoc VERTEX_CONTAINER::Delete( VERTEX_ITEM* aItem )
void Delete( VERTEX_ITEM* aItem ) override {}
/// @copydoc VERTEX_CONTAINER::Clear()
virtual void Clear() override;
/// @copydoc VERTEX_CONTAINER::GetSize()
virtual unsigned int GetSize() const override
{
// As the m_freePtr points to the first free space, we can safely assume
// that this is the number of vertices stored inside
return m_freePtr;
}
protected:
///< Index of the free first space where a vertex can be stored
unsigned int m_freePtr;
};
} // namespace KIGFX
#endif /* NONCACHED_CONTAINER_H_ */

View file

@ -0,0 +1,298 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* Graphics Abstraction Layer (GAL) for OpenGL
*
* Shader class
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <cstring>
#include <cassert>
#include "shader.h"
#include <vector>
using namespace KIGFX;
SHADER::SHADER() :
isProgramCreated( false ),
isShaderLinked( false ),
active( false ),
maximumVertices( 4 ),
geomInputType( GL_LINES ),
geomOutputType( GL_LINES )
{
// Do not have uninitialized members:
programNumber = 0;
}
SHADER::~SHADER()
{
if( active )
Deactivate();
if( isProgramCreated )
{
if( glIsShader )
{
// Delete the shaders and the program
for( std::deque<GLuint>::iterator it = shaderNumbers.begin(); it != shaderNumbers.end();
++it )
{
GLuint shader = *it;
if( glIsShader( shader ) )
{
glDetachShader( programNumber, shader );
glDeleteShader( shader );
}
}
glDeleteProgram( programNumber );
}
}
}
bool SHADER::LoadShaderFromFile( SHADER_TYPE aShaderType, const std::string& aShaderSourceName )
{
// Load shader sources
const std::string shaderSource = ReadSource( aShaderSourceName );
return LoadShaderFromStrings( aShaderType, shaderSource );
}
void SHADER::ConfigureGeometryShader( GLuint maxVertices, GLuint geometryInputType,
GLuint geometryOutputType )
{
maximumVertices = maxVertices;
geomInputType = geometryInputType;
geomOutputType = geometryOutputType;
}
bool SHADER::Link()
{
// Shader linking
glLinkProgram( programNumber );
programInfo( programNumber );
// Check the Link state
GLint tmp;
glGetProgramiv( programNumber, GL_LINK_STATUS, &tmp );
isShaderLinked = !!tmp;
#ifdef DEBUG
if( !isShaderLinked )
{
int maxLength;
glGetProgramiv( programNumber, GL_INFO_LOG_LENGTH, &maxLength );
maxLength = maxLength + 1;
char* linkInfoLog = new char[maxLength];
glGetProgramInfoLog( programNumber, maxLength, &maxLength, linkInfoLog );
std::cerr << "Shader linking error:" << std::endl;
std::cerr << linkInfoLog;
delete[] linkInfoLog;
}
#endif /* DEBUG */
return isShaderLinked;
}
int SHADER::AddParameter( const std::string& aParameterName )
{
GLint location = glGetUniformLocation( programNumber, aParameterName.c_str() );
if( location >= 0 )
parameterLocation.push_back( location );
else
throw std::runtime_error( "Could not find shader uniform: " + aParameterName );
return static_cast<int>( parameterLocation.size() ) - 1;
}
void SHADER::SetParameter( int parameterNumber, float value ) const
{
assert( (unsigned) parameterNumber < parameterLocation.size() );
glUniform1f( parameterLocation[parameterNumber], value );
}
void SHADER::SetParameter( int parameterNumber, int value ) const
{
assert( (unsigned) parameterNumber < parameterLocation.size() );
glUniform1i( parameterLocation[parameterNumber], value );
}
void SHADER::SetParameter( int parameterNumber, float f0, float f1, float f2, float f3 ) const
{
assert( (unsigned) parameterNumber < parameterLocation.size() );
float arr[4] = { f0, f1, f2, f3 };
glUniform4fv( parameterLocation[parameterNumber], 1, arr );
}
void SHADER::SetParameter( int aParameterNumber, const VECTOR2D& aValue ) const
{
assert( (unsigned) aParameterNumber < parameterLocation.size() );
glUniform2f( parameterLocation[aParameterNumber], static_cast<GLfloat>( aValue.x ),
static_cast<GLfloat>( aValue.y ) );
}
int SHADER::GetAttribute( const std::string& aAttributeName ) const
{
return glGetAttribLocation( programNumber, aAttributeName.c_str() );
}
void SHADER::programInfo( GLuint aProgram )
{
GLint glInfoLogLength = 0;
GLint writtenChars = 0;
// Get the length of the info string
glGetProgramiv( aProgram, GL_INFO_LOG_LENGTH, &glInfoLogLength );
// Print the information
if( glInfoLogLength > 2 )
{
GLchar* glInfoLog = new GLchar[glInfoLogLength];
glGetProgramInfoLog( aProgram, glInfoLogLength, &writtenChars, glInfoLog );
delete[] glInfoLog;
}
}
void SHADER::shaderInfo( GLuint aShader )
{
GLint glInfoLogLength = 0;
GLint writtenChars = 0;
// Get the length of the info string
glGetShaderiv( aShader, GL_INFO_LOG_LENGTH, &glInfoLogLength );
// Print the information
if( glInfoLogLength > 2 )
{
GLchar* glInfoLog = new GLchar[glInfoLogLength];
glGetShaderInfoLog( aShader, glInfoLogLength, &writtenChars, glInfoLog );
delete[] glInfoLog;
}
}
std::string SHADER::ReadSource( const std::string& aShaderSourceName )
{
// Open the shader source for reading
std::ifstream inputFile( aShaderSourceName.c_str(), std::ifstream::in );
std::string shaderSource;
if( !inputFile )
throw std::runtime_error( "Can't read the shader source: " + aShaderSourceName );
std::string shaderSourceLine;
// Read all lines from the text file
while( getline( inputFile, shaderSourceLine ) )
{
shaderSource += shaderSourceLine;
shaderSource += "\n";
}
return shaderSource;
}
bool SHADER::loadShaderFromStringArray( SHADER_TYPE aShaderType, const char** aArray, size_t aSize )
{
assert( !isShaderLinked );
// Create the program
if( !isProgramCreated )
{
programNumber = glCreateProgram();
isProgramCreated = true;
}
// Create a shader
GLuint shaderNumber = glCreateShader( aShaderType );
shaderNumbers.push_back( shaderNumber );
// Get the program info
programInfo( programNumber );
// Attach the sources
glShaderSource( shaderNumber, static_cast<GLsizei>( aSize ), (const GLchar**) aArray, nullptr );
programInfo( programNumber );
// Compile and attach shader to the program
glCompileShader( shaderNumber );
GLint status;
glGetShaderiv( shaderNumber, GL_COMPILE_STATUS, &status );
if( status != GL_TRUE )
{
shaderInfo( shaderNumber );
GLint maxLength = 0;
glGetShaderiv( shaderNumber, GL_INFO_LOG_LENGTH, &maxLength );
// The maxLength includes the NULL character
std::vector<GLchar> errorLog( (size_t) maxLength );
glGetShaderInfoLog( shaderNumber, maxLength, &maxLength, &errorLog[0] );
// Provide the infolog in whatever manor you deem best.
// Exit with failure.
glDeleteShader( shaderNumber ); // Don't leak the shader.
throw std::runtime_error( &errorLog[0] );
}
glAttachShader( programNumber, shaderNumber );
programInfo( programNumber );
// Special handling for the geometry shader
if( aShaderType == SHADER_TYPE_GEOMETRY )
{
glProgramParameteriEXT( programNumber, GL_GEOMETRY_VERTICES_OUT_EXT, maximumVertices );
glProgramParameteriEXT( programNumber, GL_GEOMETRY_INPUT_TYPE_EXT, geomInputType );
glProgramParameteriEXT( programNumber, GL_GEOMETRY_OUTPUT_TYPE_EXT, geomOutputType );
}
return true;
}

View file

@ -0,0 +1,236 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* Graphics Abstraction Layer (GAL) for OpenGL
*
* Shader class
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef SHADER_H_
#define SHADER_H_
#include "kiglew.h" // Must be included first
#include <math/vector2d.h>
#include <string>
#include <deque>
namespace KIGFX
{
class WEBGL_GAL;
/// Type definition for the shader
enum SHADER_TYPE
{
SHADER_TYPE_VERTEX = GL_VERTEX_SHADER, ///< Vertex shader
SHADER_TYPE_FRAGMENT = GL_FRAGMENT_SHADER, ///< Fragment shader
SHADER_TYPE_GEOMETRY = GL_GEOMETRY_SHADER ///< Geometry shader
};
namespace DETAIL {
inline const char* translateStringArg( const std::string& str )
{
return str.c_str();
}
inline const char* translateStringArg( const char* str )
{
return str;
}
}
/**
* Provide the access to the OpenGL shaders.
*
* The purpose of this class is advanced drawing with OpenGL. One example is using the pixel
* shader for drawing exact circles or for anti-aliasing. This class supports vertex, geometry
* and fragment shaders.
*
* Make sure that the hardware supports these features. This can be identified with the "GLEW"
* library.
*/
class SHADER
{
public:
SHADER();
virtual ~SHADER();
/**
* Add a shader and compile the shader sources.
*
* @param aArgs is the list of strings (std::string or convertible to const char*) which
* are concatenated and compiled as a single shader source code.
* @param aShaderType is the type of the shader.
* @return True in case of success, false otherwise.
*/
template< typename... Args >
bool LoadShaderFromStrings( SHADER_TYPE aShaderType, Args&&... aArgs )
{
const char* arr[] = { DETAIL::translateStringArg( aArgs )... };
return loadShaderFromStringArray( aShaderType, arr, sizeof...(Args) );
}
/**
* Load one of the built-in shaders and compiles it.
*
* @param aShaderSourceName is the shader source file name.
* @param aShaderType is the type of the shader.
* @return True in case of success, false otherwise.
*/
bool LoadShaderFromFile( SHADER_TYPE aShaderType, const std::string& aShaderSourceName );
/**
* Link the shaders.
*
* @return true in case of success, false otherwise.
*/
bool Link();
/**
* Return true if shaders are linked correctly.
*/
bool IsLinked() const
{
return isShaderLinked;
}
/**
* Use the shader.
*/
inline void Use()
{
glUseProgram( programNumber );
active = true;
}
/**
* Deactivate the shader and use the default OpenGL program.
*/
inline void Deactivate()
{
glUseProgram( 0 );
active = false;
}
/**
* Return the current state of the shader.
*
* @return True if any of shaders is enabled.
*/
inline bool IsActive() const
{
return active;
}
/**
* Configure the geometry shader - has to be done before linking!
*
* @param maxVertices is the maximum of vertices to be generated.
* @param geometryInputType is the input type [e.g. GL_LINES, GL_TRIANGLES, GL_QUADS etc.]
* @param geometryOutputType is the output type [e.g. GL_LINES, GL_TRIANGLES, GL_QUADS etc.]
*/
void ConfigureGeometryShader( GLuint maxVertices, GLuint geometryInputType,
GLuint geometryOutputType );
/**
* Add a parameter to the parameter queue.
*
* To communicate with the shader use this function to set up the names for the uniform
* variables. These are queued in a list and can be assigned with the SetParameter(..)
* method using the queue position.
*
* @param aParameterName is the name of the parameter.
* @return the added parameter location.
*/
int AddParameter( const std::string& aParameterName );
/**
* Set a parameter of the shader.
*
* @param aParameterNumber is the number of the parameter.
* @param aValue is the value of the parameter.
*/
void SetParameter( int aParameterNumber, float aValue ) const;
void SetParameter( int aParameterNumber, int aValue ) const;
void SetParameter( int aParameterNumber, const VECTOR2D& aValue ) const;
void SetParameter( int aParameterNumber, float f0, float f1, float f2, float f3 ) const;
/**
* Get an attribute location.
*
* @param aAttributeName is the name of the attribute.
* @return the location.
*/
int GetAttribute( const std::string& aAttributeName ) const;
/**
* Read the shader source file
*
* @param aShaderSourceName is the shader source file name.
* @return the source as string
*/
static std::string ReadSource( const std::string& aShaderSourceName );
private:
/**
* Compile vertex of fragment shader source code into the program.
*/
bool loadShaderFromStringArray( SHADER_TYPE aShaderType, const char** aArray, size_t aSize );
/**
* Get the shader program information.
*
* @param aProgram is the program number.
*/
void programInfo( GLuint aProgram );
/**
* Get the shader information.
*
* @param aShader is the shader number.
*/
void shaderInfo( GLuint aShader );
std::deque<GLuint> shaderNumbers; ///< Shader number list
GLuint programNumber; ///< Shader program number
bool isProgramCreated; ///< Flag for program creation
bool isShaderLinked; ///< Is the shader linked?
bool active; ///< Is any of shaders used?
GLuint maximumVertices; ///< The maximum of vertices to be generated
///< Input type [e.g. GL_LINES, GL_TRIANGLES, GL_QUADS etc.]
GLuint geomInputType;
///< Output type [e.g. GL_LINES, GL_TRIANGLES, GL_QUADS etc.]
GLuint geomOutputType;
std::deque<GLint> parameterLocation; ///< Location of the parameter
};
} // namespace KIGFX
#endif /* SHADER_H_ */

View file

@ -0,0 +1,199 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <confirm.h> // DisplayError
#include "kiglew.h" // Must be included first
#include <stdexcept>
#include <wx/log.h> // wxLogDebug
/**
* Flag to enable debug output of the GAL OpenGL error checking.
*
* Use "KICAD_GAL_OPENGL_ERROR" to enable GAL OpenGL error tracing.
*
* @ingroup trace_env_vars
*/
static const wxChar* const traceGalOpenGlError = wxT( "KICAD_GAL_OPENGL_ERROR" );
int checkGlError( const std::string& aInfo, const char* aFile, int aLine, bool aThrow )
{
int result = glGetError();
wxString errorMsg;
switch( result )
{
case GL_NO_ERROR:
// all good
break;
case GL_INVALID_ENUM:
errorMsg = wxString::Format( "Error: %s: invalid enum", aInfo );
break;
case GL_INVALID_VALUE:
errorMsg = wxString::Format( "Error: %s: invalid value", aInfo );
break;
case GL_INVALID_OPERATION:
errorMsg = wxString::Format( "Error: %s: invalid operation", aInfo );
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
{
GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
if( status != GL_FRAMEBUFFER_COMPLETE_EXT )
{
switch( status )
{
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
errorMsg = "The framebuffer attachment points are incomplete.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
errorMsg = "No images attached to the framebuffer.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
errorMsg = "The framebuffer does not have at least one image attached to it.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
errorMsg = "The framebuffer read buffer is incomplete.";
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
errorMsg = "The combination of internal formats of the attached images violates "
"an implementation dependent set of restrictions.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
errorMsg = "GL_RENDERBUFFER_SAMPLES is not the same for all attached render "
"buffers.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT:
errorMsg = "Framebuffer incomplete layer targets errors.";
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
errorMsg = "Framebuffer attachments have different dimensions";
break;
default:
errorMsg.Printf( "Unknown incomplete framebuffer error id %X", status );
}
}
else
{
errorMsg = wxString::Format( "Error: %s: invalid framebuffer operation", aInfo );
}
}
break;
case GL_OUT_OF_MEMORY:
errorMsg = wxString::Format( "Error: %s: out of memory", aInfo );
break;
case GL_STACK_UNDERFLOW:
errorMsg = wxString::Format( "Error: %s: stack underflow", aInfo );
break;
case GL_STACK_OVERFLOW:
errorMsg = wxString::Format( "Error: %s: stack overflow", aInfo );
break;
default:
errorMsg = wxString::Format( "Error: %s: unknown error", aInfo );
break;
}
if( result != GL_NO_ERROR )
{
if( aThrow )
{
wxLogTrace( traceGalOpenGlError, wxT( "Throwing exception for glGetError() '%s' "
"in file '%s' on line %d." ),
errorMsg,
aFile,
aLine );
throw std::runtime_error( (const char*) errorMsg.char_str() );
}
else
{
wxString msg = wxString::Format( wxT( "glGetError() '%s' in file '%s' on line %d." ),
errorMsg,
aFile,
aLine );
DisplayErrorMessage( nullptr, "OpenGL Error", errorMsg );
}
}
return result;
}
// debugMsgCallback is a callback function for glDebugMessageCallback.
// It must have the right type ( GLAPIENTRY )
static void GLAPIENTRY debugMsgCallback( GLenum aSource, GLenum aType, GLuint aId, GLenum aSeverity,
GLsizei aLength, const GLchar* aMessage,
const void* aUserParam )
{
switch( aSeverity )
{
case GL_DEBUG_SEVERITY_HIGH:
wxLogTrace( traceGalOpenGlError, wxS( "OpenGL ERROR: %s" ), aMessage );
break;
case GL_DEBUG_SEVERITY_MEDIUM:
wxLogTrace( traceGalOpenGlError, wxS( "OpenGL WARNING: %s" ), aMessage );
break;
case GL_DEBUG_SEVERITY_LOW:
wxLogTrace( traceGalOpenGlError, wxS( "OpenGL INFO: %s" ), aMessage );
break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
return;
}
}
void enableGlDebug( bool aEnable )
{
if( aEnable )
{
glEnable( GL_DEBUG_OUTPUT );
glDebugMessageCallback( (GLDEBUGPROC) debugMsgCallback, nullptr );
}
else
{
glDisable( GL_DEBUG_OUTPUT );
}
}

View file

@ -0,0 +1,51 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __OPENGL_UTILS_H
#define __OPENGL_UTILS_H
#include <string>
/**
* Check if a recent OpenGL operation has failed. If so, display the appropriate message
* starting with \a aInfo string to give more details.
*
* @param aInfo is the beginning of the error message.
* @param aFile is the file where the error occurred defined by the C __FILE__ variable.
* @param aLine is the line in \a aFile where the error occurred defined by the C __LINE__
* variable.
* @param aThrow an exception is thrown when true, otherwise only an error message is displayed.
* @return GL_NO_ERROR in case of no errors or one of GL_ constants returned by glGetError().
*/
int checkGlError( const std::string& aInfo, const char* aFile, int aLine, bool aThrow = true );
/**
* Enable or disable OpenGL driver messages output.
*
* @param aEnable decides whether the message should be shown.
*/
void enableGlDebug( bool aEnable );
#endif /* __OPENGL_ERROR_H */

View file

@ -0,0 +1,90 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vertex_common.h
* @brief Common defines and consts used in vertex related classes.
*/
#ifndef VERTEX_COMMON_H_
#define VERTEX_COMMON_H_
#include "kiglew.h" // Must be included first
#include <math/vector2d.h>
#include <cstddef>
namespace KIGFX
{
///< Possible types of shaders (keep consistent with the actual shader source in
///< kicad_vert.glsl and kicad_frag.glsl).
enum SHADER_MODE
{
SHADER_NONE = 0,
SHADER_FILLED_CIRCLE = 2,
SHADER_STROKED_CIRCLE = 3,
SHADER_FONT = 4,
SHADER_LINE_A = 5,
SHADER_LINE_B = 6,
SHADER_LINE_C = 7,
SHADER_LINE_D = 8,
SHADER_LINE_E = 9,
SHADER_LINE_F = 10,
SHADER_HOLE_WALL = 11
};
///< Data structure for vertices {X,Y,Z,R,G,B,A,shader&param}
struct VERTEX
{
GLfloat x, y, z; // Coordinates
GLubyte r, g, b, a; // Color
GLfloat shader[4]; // Shader type & params
};
static constexpr size_t VERTEX_SIZE = sizeof( VERTEX );
static constexpr size_t VERTEX_STRIDE = VERTEX_SIZE / sizeof( GLfloat );
static constexpr size_t COORD_OFFSET = offsetof( VERTEX, x );
static constexpr size_t COORD_SIZE = sizeof( VERTEX::x ) + sizeof( VERTEX::y ) +
sizeof( VERTEX::z );
static constexpr size_t COORD_STRIDE = COORD_SIZE / sizeof( GLfloat );
static constexpr size_t COLOR_OFFSET = offsetof( VERTEX, r );
static constexpr size_t COLOR_SIZE = sizeof( VERTEX::r ) + sizeof( VERTEX::g ) +
sizeof( VERTEX::b ) + sizeof( VERTEX::a );
static constexpr size_t COLOR_STRIDE = COLOR_SIZE / sizeof( GLubyte );
// Shader attributes
static constexpr size_t SHADER_OFFSET = offsetof( VERTEX, shader );
static constexpr size_t SHADER_SIZE = sizeof( VERTEX::shader );
static constexpr size_t SHADER_STRIDE = SHADER_SIZE / sizeof( GLfloat );
static constexpr size_t INDEX_SIZE = sizeof( GLuint );
} // namespace KIGFX
#endif /* VERTEX_COMMON_H_ */

View file

@ -0,0 +1,73 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vertex_container.cpp
* @brief Class to store vertices and handle transfers between system memory and GPU memory.
*/
#include "vertex_container.h"
#include "cached_container_ram.h"
#include "cached_container_gpu.h"
#include "noncached_container.h"
#include "shader.h"
#include <cstring>
using namespace KIGFX;
VERTEX_CONTAINER* VERTEX_CONTAINER::MakeContainer( bool aCached )
{
if( aCached )
{
const char* vendor = (const char*) glGetString( GL_VENDOR );
// Open source drivers do not cope well with GPU memory mapping,
// so the vertex data has to be kept in RAM
if( strstr( vendor, "X.Org" ) || strstr( vendor, "nouveau" ) )
return new CACHED_CONTAINER_RAM;
else
return new CACHED_CONTAINER_GPU;
}
return new NONCACHED_CONTAINER;
}
VERTEX_CONTAINER::VERTEX_CONTAINER( unsigned int aSize ) :
m_freeSpace( aSize ),
m_currentSize( aSize ),
m_initialSize( aSize ),
m_vertices( nullptr ),
m_failed( false ),
m_dirty( true )
{
}
VERTEX_CONTAINER::~VERTEX_CONTAINER()
{
}

View file

@ -0,0 +1,191 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright 2013-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vertex_container.h
* Class to store vertices and handle transfers between system memory and GPU memory.
*/
#ifndef VERTEX_CONTAINER_H_
#define VERTEX_CONTAINER_H_
#include "vertex_common.h"
namespace KIGFX
{
class VERTEX_ITEM;
class SHADER;
class VERTEX_CONTAINER
{
public:
/**
* Return a pointer to a new container of an appropriate type.
*/
static VERTEX_CONTAINER* MakeContainer( bool aCached );
virtual ~VERTEX_CONTAINER();
/**
* Return true if the container caches vertex data in RAM or video memory.
* Otherwise it is a single batch draw which is later discarded.
*/
virtual bool IsCached() const = 0;
/**
* Prepare the container for vertices updates.
*/
virtual void Map() {}
/**
* Finish the vertices updates stage.
*/
virtual void Unmap() {}
/**
* Set the item for the further actions.
*
* @param aItem is the item or NULL in case of finishing the item.
*/
virtual void SetItem( VERTEX_ITEM* aItem ) = 0;
/**
* Clean up after adding an item.
*/
virtual void FinishItem() {};
/**
* Return allocated space for the requested number of vertices associated with the
* current item (set with SetItem()).
*
* The allocated space is added at the end of the chunk used by the current item and
* may serve to store new vertices.
*
* @param aSize is the number of vertices to be allocated.
* @return Pointer to the allocated space or NULL in case of failure.
*/
virtual VERTEX* Allocate( unsigned int aSize ) = 0;
/**
* Erase the data related to an item.
*
* @param aItem is the item to be erased.
*/
virtual void Delete( VERTEX_ITEM* aItem ) = 0;
/**
* Remove all data stored in the container and restores its original state.
*/
virtual void Clear() = 0;
/**
* Return pointer to the vertices stored in the container.
*/
VERTEX* GetAllVertices() const
{
return m_vertices;
}
/**
* Return vertices stored at the specific offset.
*
* @param aOffset is the offset.
*/
virtual VERTEX* GetVertices( unsigned int aOffset ) const
{
return &m_vertices[aOffset];
}
/**
* Return amount of vertices currently stored in the container.
*/
virtual unsigned int GetSize() const
{
return m_currentSize;
}
/**
* Return information about the container cache state.
*
* @return True in case the vertices have to be reuploaded.
*/
bool IsDirty() const
{
return m_dirty;
}
/**
* Set the dirty flag, so vertices in the container are going to be reuploaded to the GPU on
* the next frame.
*/
void SetDirty()
{
m_dirty = true;
}
/**
* Clear the dirty flag to prevent reuploading vertices to the GPU memory.
*/
void ClearDirty()
{
m_dirty = false;
}
protected:
VERTEX_CONTAINER( unsigned int aSize = DEFAULT_SIZE );
/**
* Return size of the used memory space.
*
* @return Size of the used memory space (expressed as a number of vertices).
*/
unsigned int usedSpace() const
{
return m_currentSize - m_freeSpace;
}
///< Free space left in the container, expressed in vertices
unsigned int m_freeSpace;
///< Current container size, expressed in vertices
unsigned int m_currentSize;
///< Store the initial size, so it can be resized to this on Clear()
unsigned int m_initialSize;
///< Actual storage memory
VERTEX* m_vertices;
// Status flags
bool m_failed;
bool m_dirty;
///< Default initial size of a container (expressed in vertices)
static constexpr unsigned int DEFAULT_SIZE = 1048576;
};
} // namespace KIGFX
#endif /* VERTEX_CONTAINER_H_ */

View file

@ -0,0 +1,57 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vertex_item.cpp
* @brief Class to handle an item held in a container.
*/
#include "vertex_item.h"
#include "vertex_manager.h"
#include <cstring>
using namespace KIGFX;
VERTEX_ITEM::VERTEX_ITEM( const VERTEX_MANAGER& aManager ) :
m_manager( aManager ),
m_offset( 0 ),
m_size( 0 )
{
// As the item is created, we are going to modify it, so call to SetItem() is needed
m_manager.SetItem( *this );
}
VERTEX_ITEM::~VERTEX_ITEM()
{
m_manager.FreeItem( *this );
}
VERTEX* VERTEX_ITEM::GetVertices() const
{
return m_manager.GetVertices( *this );
}

View file

@ -0,0 +1,105 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vertex_item.h
* Class to handle an item held in a container.
*/
#ifndef VERTEX_ITEM_H_
#define VERTEX_ITEM_H_
#include "vertex_common.h"
#include <gal/color4d.h>
#include <cstddef>
namespace KIGFX
{
class VERTEX_MANAGER;
class VERTEX_ITEM
{
public:
friend class CACHED_CONTAINER;
friend class CACHED_CONTAINER_GPU;
friend class VERTEX_MANAGER;
explicit VERTEX_ITEM( const VERTEX_MANAGER& aManager );
~VERTEX_ITEM();
/**
* Return information about number of vertices stored.
*
* @return Number of vertices.
*/
inline unsigned int GetSize() const
{
return m_size;
}
/**
* Return data offset in the container.
*
* @return Data offset expressed as a number of vertices.
*/
inline unsigned int GetOffset() const
{
return m_offset;
}
/**
* Return pointer to the data used by the VERTEX_ITEM.
*/
VERTEX* GetVertices() const;
private:
/**
* Set data offset in the container.
*
* @param aOffset is the offset expressed as a number of vertices.
*/
inline void setOffset( unsigned int aOffset )
{
m_offset = aOffset;
}
/**
* Set data size in the container.
*
* @param aSize is the size expressed as a number of vertices.
*/
inline void setSize( unsigned int aSize )
{
m_size = aSize;
}
const VERTEX_MANAGER& m_manager;
unsigned int m_offset;
unsigned int m_size;
};
} // namespace KIGFX
#endif /* VERTEX_ITEM_H_ */

View file

@ -0,0 +1,318 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013-2016 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vertex_manager.cpp
* @brief Class to control vertex container and GPU with possibility of emulating old-style OpenGL
* 1.0 state machine using modern OpenGL methods.
*/
#include "vertex_manager.h"
#include "cached_container.h"
#include "noncached_container.h"
#include "gpu_manager.h"
#include "vertex_item.h"
#include <confirm.h>
#include <wx/log.h>
/**
* Flag to enable #VERTEX_MANAGER debugging output.
*
* @ingroup trace_env_vars
*/
static const wxChar traceVertexManager[] = wxT( "KICAD_VERTEX_MANAGER" );
using namespace KIGFX;
VERTEX_MANAGER::VERTEX_MANAGER( bool aCached ) :
m_noTransform( true ),
m_transform( 1.0f ),
m_reserved( nullptr ),
m_reservedSpace( 0 )
{
m_container.reset( VERTEX_CONTAINER::MakeContainer( aCached ) );
m_gpu.reset( GPU_MANAGER::MakeManager( m_container.get() ) );
// There is no shader used by default
for( unsigned int i = 0; i < SHADER_STRIDE; ++i )
m_shader[i] = 0.0f;
}
void VERTEX_MANAGER::Map()
{
m_container->Map();
}
void VERTEX_MANAGER::Unmap()
{
m_container->Unmap();
}
bool VERTEX_MANAGER::Reserve( unsigned int aSize )
{
if( !aSize )
return true;
// flags to avoid hanging by calling DisplayError too many times:
static bool show_err_reserve = true;
static bool show_err_alloc = true;
if( m_reservedSpace != 0 || m_reserved )
{
if( show_err_reserve )
{
DisplayError( nullptr, wxT( "VERTEX_MANAGER::Reserve: Did not use all previous vertices allocated" ) );
show_err_reserve = false;
}
}
m_reserved = m_container->Allocate( aSize );
if( m_reserved == nullptr )
{
if( show_err_alloc )
{
DisplayError( nullptr, wxT( "VERTEX_MANAGER::Reserve: Vertex allocation error" ) );
show_err_alloc = false;
}
return false;
}
m_reservedSpace = aSize;
return true;
}
bool VERTEX_MANAGER::Vertex( GLfloat aX, GLfloat aY, GLfloat aZ )
{
// flag to avoid hanging by calling DisplayError too many times:
static bool show_err = true;
// Obtain the pointer to the vertex in the currently used container
VERTEX* newVertex;
if( m_reservedSpace > 0 )
{
newVertex = m_reserved++;
--m_reservedSpace;
if( m_reservedSpace == 0 )
m_reserved = nullptr;
}
else
{
newVertex = m_container->Allocate( 1 );
if( newVertex == nullptr )
{
if( show_err )
{
DisplayError( nullptr, wxT( "VERTEX_MANAGER::Vertex: Vertex allocation error" ) );
show_err = false;
}
return false;
}
}
putVertex( *newVertex, aX, aY, aZ );
return true;
}
bool VERTEX_MANAGER::Vertices( const VERTEX aVertices[], unsigned int aSize )
{
// flag to avoid hanging by calling DisplayError too many times:
static bool show_err = true;
// Obtain pointer to the vertex in currently used container
VERTEX* newVertex = m_container->Allocate( aSize );
if( newVertex == nullptr )
{
if( show_err )
{
DisplayError( nullptr, wxT( "VERTEX_MANAGER::Vertices: Vertex allocation error" ) );
show_err = false;
}
return false;
}
// Put vertices in already allocated memory chunk
for( unsigned int i = 0; i < aSize; ++i )
{
putVertex( newVertex[i], aVertices[i].x, aVertices[i].y, aVertices[i].z );
}
return true;
}
void VERTEX_MANAGER::SetItem( VERTEX_ITEM& aItem ) const
{
m_container->SetItem( &aItem );
}
void VERTEX_MANAGER::FinishItem() const
{
if( m_reservedSpace != 0 || m_reserved )
wxLogTrace( traceVertexManager, wxS( "Did not use all previous vertices allocated" ) );
m_container->FinishItem();
}
void VERTEX_MANAGER::FreeItem( VERTEX_ITEM& aItem ) const
{
m_container->Delete( &aItem );
}
void VERTEX_MANAGER::ChangeItemColor( const VERTEX_ITEM& aItem, const COLOR4D& aColor ) const
{
unsigned int size = aItem.GetSize();
unsigned int offset = aItem.GetOffset();
VERTEX* vertex = m_container->GetVertices( offset );
for( unsigned int i = 0; i < size; ++i )
{
vertex->r = aColor.r * 255.0;
vertex->g = aColor.g * 255.0;
vertex->b = aColor.b * 255.0;
vertex->a = aColor.a * 255.0;
vertex++;
}
m_container->SetDirty();
}
void VERTEX_MANAGER::ChangeItemDepth( const VERTEX_ITEM& aItem, GLfloat aDepth ) const
{
unsigned int size = aItem.GetSize();
unsigned int offset = aItem.GetOffset();
VERTEX* vertex = m_container->GetVertices( offset );
for( unsigned int i = 0; i < size; ++i )
{
vertex->z = aDepth;
vertex++;
}
m_container->SetDirty();
}
VERTEX* VERTEX_MANAGER::GetVertices( const VERTEX_ITEM& aItem ) const
{
if( aItem.GetSize() == 0 )
return nullptr; // The item is not stored in the container
return m_container->GetVertices( aItem.GetOffset() );
}
void VERTEX_MANAGER::SetShader( SHADER& aShader ) const
{
m_gpu->SetShader( aShader );
}
void VERTEX_MANAGER::Clear() const
{
m_container->Clear();
}
void VERTEX_MANAGER::BeginDrawing() const
{
m_gpu->BeginDrawing();
}
void VERTEX_MANAGER::DrawItem( const VERTEX_ITEM& aItem ) const
{
m_gpu->DrawIndices( &aItem );
}
void VERTEX_MANAGER::EndDrawing() const
{
m_gpu->EndDrawing();
}
void VERTEX_MANAGER::putVertex( VERTEX& aTarget, GLfloat aX, GLfloat aY, GLfloat aZ ) const
{
// Modify the vertex according to the currently used transformations
if( m_noTransform )
{
// Simply copy coordinates, when the transform matrix is the identity matrix
aTarget.x = aX;
aTarget.y = aY;
aTarget.z = aZ;
}
else
{
// Apply transformations
glm::vec4 transVertex( aX, aY, aZ, 1.0f );
transVertex = m_transform * transVertex;
aTarget.x = transVertex.x;
aTarget.y = transVertex.y;
aTarget.z = transVertex.z;
}
// Apply currently used color
aTarget.r = m_color[0];
aTarget.g = m_color[1];
aTarget.b = m_color[2];
aTarget.a = m_color[3];
// Apply currently used shader
for( unsigned int j = 0; j < SHADER_STRIDE; ++j )
{
aTarget.shader[j] = m_shader[j];
}
}
void VERTEX_MANAGER::EnableDepthTest( bool aEnabled )
{
m_gpu->EnableDepthTest( aEnabled );
}

View file

@ -0,0 +1,393 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013-2016 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file vertex_manager.h
*/
#ifndef VERTEX_MANAGER_H_
#define VERTEX_MANAGER_H_
#define GLM_FORCE_RADIANS
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
#include "vertex_common.h"
#include <gal/color4d.h>
#include <stack>
#include <memory>
namespace KIGFX
{
class SHADER;
class VERTEX_ITEM;
class VERTEX_CONTAINER;
class GPU_MANAGER;
/**
* Class to control vertex container and GPU with possibility of emulating old-style OpenGL
* 1.0 state machine using modern OpenGL methods.
*/
class VERTEX_MANAGER
{
public:
/**
* @param aCached says if vertices should be cached in GPU or system memory. For data that
* does not change every frame, it is better to store vertices in GPU memory.
*/
VERTEX_MANAGER( bool aCached );
/**
* Map vertex buffer.
*/
void Map();
/**
* Unmap vertex buffer.
*/
void Unmap();
/**
* Allocate space for vertices, so it will be used with subsequent Vertex() calls.
*
* @param aSize is the number of vertices that should be available in the reserved space.
* @return True if successful, false otherwise.
*/
bool Reserve( unsigned int aSize );
/**
* Add a vertex with the given coordinates to the currently set item.
*
* Color & shader parameters stored in aVertex are ignored, instead color & shader set
* by Color() and Shader() functions are used. Vertex coordinates will have the current
* transformation matrix applied.
*
* @param aVertex contains vertex coordinates.
* @return True if successful, false otherwise.
*/
inline bool Vertex( const VERTEX& aVertex )
{
return Vertex( aVertex.x, aVertex.y, aVertex.z );
}
/**
* Add a vertex with the given coordinates to the currently set item.
*
* Vertex coordinates will have the current transformation matrix applied.
*
* @param aX is the X coordinate of the new vertex.
* @param aY is the Y coordinate of the new vertex.
* @param aZ is the Z coordinate of the new vertex.
* @return True if successful, false otherwise.
*/
bool Vertex( GLfloat aX, GLfloat aY, GLfloat aZ );
/**
* Add a vertex with the given coordinates to the currently set item.
*
* Vertex coordinates will have the current transformation matrix applied.
*
* @param aXY are the XY coordinates of the new vertex.
* @param aZ is the Z coordinate of the new vertex.
* @return True if successful, false otherwise.
*/
bool Vertex( const VECTOR2D& aXY, GLfloat aZ )
{
return Vertex( aXY.x, aXY.y, aZ );
}
/**
* Add one or more vertices to the currently set item.
*
* It takes advantage of allocating memory in advance, so should be faster than
* adding vertices one by one. Color & shader parameters stored in aVertices are
* ignored, instead color & shader set by Color() and Shader() functions are used.
* All the vertex coordinates will have the current transformation matrix applied.
*
* @param aVertices contains vertices to be added.
* @param aSize is the number of vertices to be added.
* @return True if successful, false otherwise.
*/
bool Vertices( const VERTEX aVertices[], unsigned int aSize );
/**
* Change currently used color that will be applied to newly added vertices.
*
* @param aColor is the new color.
*/
inline void Color( const COLOR4D& aColor )
{
m_color[0] = aColor.r * 255.0;
m_color[1] = aColor.g * 255.0;
m_color[2] = aColor.b * 255.0;
m_color[3] = aColor.a * 255.0;
}
/**
* Change currently used color that will be applied to newly added vertices.
*
* It is the equivalent of glColor4f() function.
*
* @param aRed is the red component of the new color.
* @param aGreen is the green component of the new color.
* @param aBlue is the blue component of the new color.
* @param aAlpha is the alpha component of the new color.
*/
inline void Color( GLfloat aRed, GLfloat aGreen, GLfloat aBlue, GLfloat aAlpha )
{
m_color[0] = aRed * 255.0;
m_color[1] = aGreen * 255.0;
m_color[2] = aBlue * 255.0;
m_color[3] = aAlpha * 255.0;
}
/**
* Change currently used shader and its parameters that will be applied to newly added
* vertices.
*
* Parameters depend on shader, for more information have a look at shaders source code.
*
* @see SHADER_TYPE
*
* @param aShaderType is the a shader type to be applied.
* @param aParam1 is the optional parameter for a shader.
* @param aParam2 is the optional parameter for a shader.
* @param aParam3 is the optional parameter for a shader.
*/
inline void Shader( GLfloat aShaderType, GLfloat aParam1 = 0.0f, GLfloat aParam2 = 0.0f,
GLfloat aParam3 = 0.0f )
{
m_shader[0] = aShaderType;
m_shader[1] = aParam1;
m_shader[2] = aParam2;
m_shader[3] = aParam3;
}
/**
* Multiply the current matrix by a translation matrix, so newly vertices will be
* translated by the given vector.
*
* It is the equivalent of the glTranslatef() function.
*
* @param aX is the X coordinate of a translation vector.
* @param aY is the X coordinate of a translation vector.
* @param aZ is the X coordinate of a translation vector.
*/
inline void Translate( GLfloat aX, GLfloat aY, GLfloat aZ )
{
m_transform = glm::translate( m_transform, glm::vec3( aX, aY, aZ ) );
}
/**
* Multiply the current matrix by a rotation matrix, so the newly vertices will be
* rotated by the given angles.
*
* It is the equivalent of the glRotatef() function.
*
* @param aAngle is the angle of rotation, in radians.
* @param aX is a multiplier for the X axis
* @param aY is a multiplier for the Y axis
* @param aZ is a multiplier for the Z axis.
*/
inline void Rotate( GLfloat aAngle, GLfloat aX, GLfloat aY, GLfloat aZ )
{
m_transform = glm::rotate( m_transform, aAngle, glm::vec3( aX, aY, aZ ) );
}
/**
* Multiply the current matrix by a scaling matrix, so the newly vertices will be
* scaled by the given factors.
*
* It is the equivalent of the glScalef() function.
*
* @param aX is the X axis scaling factor.
* @param aY is the Y axis scaling factor.
* @param aZ is the Z axis scaling factor.
*/
inline void Scale( GLfloat aX, GLfloat aY, GLfloat aZ )
{
m_transform = glm::scale( m_transform, glm::vec3( aX, aY, aZ ) );
}
/**
* Push the current transformation matrix stack.
*
* It is the equivalent of the glPushMatrix() function.
*/
inline void PushMatrix()
{
m_transformStack.push( m_transform );
// Every transformation starts with PushMatrix
m_noTransform = false;
}
/**
* Pop the current transformation matrix stack.
*
* It is the equivalent of the glPopMatrix() function.
*/
void PopMatrix()
{
wxASSERT( !m_transformStack.empty() );
m_transform = m_transformStack.top();
m_transformStack.pop();
if( m_transformStack.empty() )
{
// We return back to the identity matrix, thus no vertex transformation is needed
m_noTransform = true;
}
}
/**
* Set an item to start its modifications.
*
* After calling the function it is possible to add vertices using function Add().
*
* @param aItem is the item that is going to store vertices in the container.
*/
void SetItem( VERTEX_ITEM& aItem ) const;
/**
* Clean after adding an item.
*/
void FinishItem() const;
/**
* Free the memory occupied by the item, so it is no longer stored in the container.
*
* @param aItem is the item to be freed
*/
void FreeItem( VERTEX_ITEM& aItem ) const;
/**
* Change the color of all vertices owned by an item.
*
* @param aItem is the item to change.
* @param aColor is the new color to be applied.
*/
void ChangeItemColor( const VERTEX_ITEM& aItem, const COLOR4D& aColor ) const;
/**
* Change the depth of all vertices owned by an item.
*
* @param aItem is the item to change.
* @param aDepth is the new color to be applied.
*/
void ChangeItemDepth( const VERTEX_ITEM& aItem, GLfloat aDepth ) const;
/**
* Return a pointer to the vertices owned by an item.
*
* @param aItem is the owner of vertices that are going to be returned.
* @return Pointer to the vertices or NULL if the item is not stored at the container.
*/
VERTEX* GetVertices( const VERTEX_ITEM& aItem ) const;
const glm::mat4& GetTransformation() const
{
return m_transform;
}
/**
* Set a shader program that is going to be used during rendering.
*
* @param aShader is the object containing compiled and linked shader program.
*/
void SetShader( SHADER& aShader ) const;
/**
* Remove all the stored vertices from the container.
*/
void Clear() const;
/**
* Prepare buffers and items to start drawing.
*/
void BeginDrawing() const;
/**
* Draw an item to the buffer.
*
* @param aItem is the item to be drawn.
*/
void DrawItem( const VERTEX_ITEM& aItem ) const;
/**
* Finish drawing operations.
*/
void EndDrawing() const;
/**
* Enable/disable Z buffer depth test.
*/
void EnableDepthTest( bool aEnabled );
protected:
/**
* Apply all transformation to the given coordinates and store them at the specified target.
*
* @param aTarget is the place where the new vertex is going to be stored (it has to be
* allocated first).
* @param aX is the X coordinate of the new vertex.
* @param aY is the Y coordinate of the new vertex.
* @param aZ is the Z coordinate of the new vertex.
*/
void putVertex( VERTEX& aTarget, GLfloat aX, GLfloat aY, GLfloat aZ ) const;
/// Container for vertices, may be cached or noncached
std::shared_ptr<VERTEX_CONTAINER> m_container;
/// GPU manager for data transfers and drawing operations
std::shared_ptr<GPU_MANAGER> m_gpu;
/// State machine variables
/// True in case there is no need to transform vertices
bool m_noTransform;
/// Currently used transform matrix
glm::mat4 m_transform;
/// Stack of transformation matrices, used for Push/PopMatrix
std::stack<glm::mat4> m_transformStack;
/// Currently used color
GLubyte m_color[COLOR_STRIDE];
/// Currently used shader and its parameters
GLfloat m_shader[SHADER_STRIDE];
/// Currently reserved chunk to store vertices
VERTEX* m_reserved;
/// Currently available reserved space
unsigned int m_reservedSpace;
};
} // namespace KIGFX
#endif /* VERTEX_MANAGER_H_ */

View file

@ -0,0 +1,562 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "webgl_antialiasing.h"
#include "webgl_compositor.h"
#include "utils.h"
#include <gal/color4d.h>
#include <memory>
#include <tuple>
#include <glsl_smaa_base.h>
#include <glsl_smaa_pass_1_frag_color.h>
#include <glsl_smaa_pass_1_frag_luma.h>
#include <glsl_smaa_pass_1_vert.h>
#include <glsl_smaa_pass_2_frag.h>
#include <glsl_smaa_pass_2_vert.h>
#include <glsl_smaa_pass_3_frag.h>
#include <glsl_smaa_pass_3_vert.h>
#include "SmaaAreaTex.h"
#include "SmaaSearchTex.h"
using namespace KIGFX;
// =========================
// ANTIALIASING_NONE
// =========================
ANTIALIASING_NONE::ANTIALIASING_NONE( WEBGL_COMPOSITOR* aCompositor ) :
compositor( aCompositor )
{
}
bool ANTIALIASING_NONE::Init()
{
// Nothing to initialize
return true;
}
VECTOR2I ANTIALIASING_NONE::GetInternalBufferSize()
{
return compositor->GetScreenSize();
}
void ANTIALIASING_NONE::DrawBuffer( GLuint buffer )
{
compositor->DrawBuffer( buffer, WEBGL_COMPOSITOR::DIRECT_RENDERING );
}
void ANTIALIASING_NONE::Present()
{
// Nothing to present, draw_buffer already drew to the screen
}
void ANTIALIASING_NONE::OnLostBuffers()
{
// Nothing to do
}
void ANTIALIASING_NONE::Begin()
{
// Nothing to do
}
unsigned int ANTIALIASING_NONE::CreateBuffer()
{
return compositor->CreateBuffer( compositor->GetScreenSize() );
}
namespace
{
void draw_fullscreen_primitive()
{
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
glBegin( GL_TRIANGLES );
glTexCoord2f( 0.0f, 1.0f );
glVertex2f( -1.0f, 1.0f );
glTexCoord2f( 0.0f, 0.0f );
glVertex2f( -1.0f, -1.0f );
glTexCoord2f( 1.0f, 1.0f );
glVertex2f( 1.0f, 1.0f );
glTexCoord2f( 1.0f, 1.0f );
glVertex2f( 1.0f, 1.0f );
glTexCoord2f( 0.0f, 0.0f );
glVertex2f( -1.0f, -1.0f );
glTexCoord2f( 1.0f, 0.0f );
glVertex2f( 1.0f, -1.0f );
glEnd();
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
}
} // namespace
// =========================
// ANTIALIASING_SUPERSAMPLING
// =========================
ANTIALIASING_SUPERSAMPLING::ANTIALIASING_SUPERSAMPLING( WEBGL_COMPOSITOR* aCompositor ) :
compositor( aCompositor ),
ssaaMainBuffer( 0 ), areBuffersCreated( false ), areShadersCreated( false )
{
}
bool ANTIALIASING_SUPERSAMPLING::Init()
{
areShadersCreated = false;
if( !areBuffersCreated )
{
ssaaMainBuffer = compositor->CreateBuffer();
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
areBuffersCreated = true;
}
return true;
}
VECTOR2I ANTIALIASING_SUPERSAMPLING::GetInternalBufferSize()
{
return compositor->GetScreenSize() * 2;
}
void ANTIALIASING_SUPERSAMPLING::Begin()
{
compositor->SetBuffer( ssaaMainBuffer );
compositor->ClearBuffer( COLOR4D::BLACK );
}
void ANTIALIASING_SUPERSAMPLING::DrawBuffer( GLuint aBuffer )
{
compositor->DrawBuffer( aBuffer, ssaaMainBuffer );
}
void ANTIALIASING_SUPERSAMPLING::Present()
{
glDisable( GL_BLEND );
glDisable( GL_DEPTH_TEST );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, compositor->GetBufferTexture( ssaaMainBuffer ) );
compositor->SetBuffer( WEBGL_COMPOSITOR::DIRECT_RENDERING );
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE );
draw_fullscreen_primitive();
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
}
void ANTIALIASING_SUPERSAMPLING::OnLostBuffers()
{
areBuffersCreated = false;
}
unsigned int ANTIALIASING_SUPERSAMPLING::CreateBuffer()
{
return compositor->CreateBuffer( GetInternalBufferSize() );
}
// ===============================
// ANTIALIASING_SMAA
// ===============================
ANTIALIASING_SMAA::ANTIALIASING_SMAA( WEBGL_COMPOSITOR* aCompositor ) :
areBuffersInitialized( false ),
shadersLoaded( false ),
compositor( aCompositor )
{
smaaBaseBuffer = 0;
smaaEdgesBuffer = 0;
smaaBlendBuffer = 0;
smaaAreaTex = 0;
smaaSearchTex = 0;
pass_1_metrics = 0;
pass_2_metrics = 0;
pass_3_metrics = 0;
}
VECTOR2I ANTIALIASING_SMAA::GetInternalBufferSize()
{
return compositor->GetScreenSize();
}
void ANTIALIASING_SMAA::loadShaders()
{
// Load constant textures
glEnable( GL_TEXTURE_2D );
glActiveTexture( GL_TEXTURE0 );
glGenTextures( 1, &smaaAreaTex );
glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT, 0, GL_RG,
GL_UNSIGNED_BYTE, areaTexBytes );
checkGlError( "loading smaa area tex", __FILE__, __LINE__ );
glGenTextures( 1, &smaaSearchTex );
glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 0, GL_RED,
GL_UNSIGNED_BYTE, searchTexBytes );
checkGlError( "loading smaa search tex", __FILE__, __LINE__ );
// Quality settings:
// THRESHOLD: intended to exclude spurious edges in photorealistic game graphics
// but in a high-contrast CAD application, all edges are intentional
// should be set fairly low, so user color choices do not affect antialiasing
// MAX_SEARCH_STEPS: steps of 2px, searched in H/V direction to discover true angle of edges
// improves AA for lines close H/V but creates fuzzyness at junctions
// MAX_SEARCH_STEPS_DIAG: steps of 1px, searched in diagonal direction
// improves lines close to 45deg but turns small circles into octagons
// CORNER_ROUNDING: SMAA can distinguish actual corners from aliasing jaggies,
// we want to preserve those as much as possible
// Edge Detection: In Eeschema, when a single pixel line changes color, edge detection using
// color is too aggressive and leads to a white spot at the transition point
std::string quality_string;
std::string edge_detect_shader;
// trades imperfect AA of shallow angles for a near artifact-free reproduction of fine features
// jaggies are smoothed over max 5px (original step + 2px in both directions)
quality_string = "#define SMAA_THRESHOLD 0.005\n"
"#define SMAA_MAX_SEARCH_STEPS 1\n"
"#define SMAA_MAX_SEARCH_STEPS_DIAG 2\n"
"#define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 1.5\n"
"#define SMAA_CORNER_ROUNDING 0\n";
edge_detect_shader = BUILTIN_SHADERS::glsl_smaa_pass_1_frag_luma;
// set up shaders
std::string vert_preamble( R"SHADER(
#version 120
#define SMAA_GLSL_2_1
#define SMAA_INCLUDE_VS 1
#define SMAA_INCLUDE_PS 0
uniform vec4 SMAA_RT_METRICS;
)SHADER" );
std::string frag_preamble( R"SHADER(
#version 120
#define SMAA_GLSL_2_1
#define SMAA_INCLUDE_VS 0
#define SMAA_INCLUDE_PS 1
uniform vec4 SMAA_RT_METRICS;
)SHADER" );
//
// Set up pass 1 Shader
//
pass_1_shader = std::make_unique<SHADER>();
pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
BUILTIN_SHADERS::glsl_smaa_base,
BUILTIN_SHADERS::glsl_smaa_pass_1_vert );
pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
quality_string, BUILTIN_SHADERS::glsl_smaa_base,
edge_detect_shader );
pass_1_shader->Link();
checkGlError( "linking pass 1 shader", __FILE__, __LINE__ );
GLint smaaColorTexParameter = pass_1_shader->AddParameter( "colorTex" );
checkGlError( "pass1: getting colorTex uniform", __FILE__, __LINE__ );
pass_1_metrics = pass_1_shader->AddParameter( "SMAA_RT_METRICS" );
checkGlError( "pass1: getting metrics uniform", __FILE__, __LINE__ );
pass_1_shader->Use();
checkGlError( "pass1: using shader", __FILE__, __LINE__ );
pass_1_shader->SetParameter( smaaColorTexParameter, 0 );
checkGlError( "pass1: setting colorTex uniform", __FILE__, __LINE__ );
pass_1_shader->Deactivate();
checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
//
// set up pass 2 shader
//
pass_2_shader = std::make_unique<SHADER>();
pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
BUILTIN_SHADERS::glsl_smaa_base,
BUILTIN_SHADERS::glsl_smaa_pass_2_vert );
pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
quality_string, BUILTIN_SHADERS::glsl_smaa_base,
BUILTIN_SHADERS::glsl_smaa_pass_2_frag );
pass_2_shader->Link();
checkGlError( "linking pass 2 shader", __FILE__, __LINE__ );
GLint smaaEdgesTexParameter = pass_2_shader->AddParameter( "edgesTex" );
checkGlError( "pass2: getting colorTex uniform", __FILE__, __LINE__ );
GLint smaaAreaTexParameter = pass_2_shader->AddParameter( "areaTex" );
checkGlError( "pass2: getting areaTex uniform", __FILE__, __LINE__ );
GLint smaaSearchTexParameter = pass_2_shader->AddParameter( "searchTex" );
checkGlError( "pass2: getting searchTex uniform", __FILE__, __LINE__ );
pass_2_metrics = pass_2_shader->AddParameter( "SMAA_RT_METRICS" );
checkGlError( "pass2: getting metrics uniform", __FILE__, __LINE__ );
pass_2_shader->Use();
checkGlError( "pass2: using shader", __FILE__, __LINE__ );
pass_2_shader->SetParameter( smaaEdgesTexParameter, 0 );
checkGlError( "pass2: setting colorTex uniform", __FILE__, __LINE__ );
pass_2_shader->SetParameter( smaaAreaTexParameter, 1 );
checkGlError( "pass2: setting areaTex uniform", __FILE__, __LINE__ );
pass_2_shader->SetParameter( smaaSearchTexParameter, 3 );
checkGlError( "pass2: setting searchTex uniform", __FILE__, __LINE__ );
pass_2_shader->Deactivate();
checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
//
// set up pass 3 shader
//
pass_3_shader = std::make_unique<SHADER>();
pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
BUILTIN_SHADERS::glsl_smaa_base,
BUILTIN_SHADERS::glsl_smaa_pass_3_vert );
pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
quality_string, BUILTIN_SHADERS::glsl_smaa_base,
BUILTIN_SHADERS::glsl_smaa_pass_3_frag );
pass_3_shader->Link();
GLint smaaP3ColorTexParameter = pass_3_shader->AddParameter( "colorTex" );
checkGlError( "pass3: getting colorTex uniform", __FILE__, __LINE__ );
GLint smaaBlendTexParameter = pass_3_shader->AddParameter( "blendTex" );
checkGlError( "pass3: getting blendTex uniform", __FILE__, __LINE__ );
pass_3_metrics = pass_3_shader->AddParameter( "SMAA_RT_METRICS" );
checkGlError( "pass3: getting metrics uniform", __FILE__, __LINE__ );
pass_3_shader->Use();
checkGlError( "pass3: using shader", __FILE__, __LINE__ );
pass_3_shader->SetParameter( smaaP3ColorTexParameter, 0 );
checkGlError( "pass3: setting colorTex uniform", __FILE__, __LINE__ );
pass_3_shader->SetParameter( smaaBlendTexParameter, 1 );
checkGlError( "pass3: setting blendTex uniform", __FILE__, __LINE__ );
pass_3_shader->Deactivate();
checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
shadersLoaded = true;
}
void ANTIALIASING_SMAA::updateUniforms()
{
auto dims = compositor->GetScreenSize();
pass_1_shader->Use();
checkGlError( "pass1: using shader", __FILE__, __LINE__ );
pass_1_shader->SetParameter( pass_1_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
float( dims.x ), float( dims.y ) );
checkGlError( "pass1: setting metrics uniform", __FILE__, __LINE__ );
pass_1_shader->Deactivate();
checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
pass_2_shader->Use();
checkGlError( "pass2: using shader", __FILE__, __LINE__ );
pass_2_shader->SetParameter( pass_2_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
float( dims.x ), float( dims.y ) );
checkGlError( "pass2: setting metrics uniform", __FILE__, __LINE__ );
pass_2_shader->Deactivate();
checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
pass_3_shader->Use();
checkGlError( "pass3: using shader", __FILE__, __LINE__ );
pass_3_shader->SetParameter( pass_3_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
float( dims.x ), float( dims.y ) );
checkGlError( "pass3: setting metrics uniform", __FILE__, __LINE__ );
pass_3_shader->Deactivate();
checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
}
bool ANTIALIASING_SMAA::Init()
{
if( !shadersLoaded )
loadShaders();
if( !areBuffersInitialized )
{
smaaBaseBuffer = compositor->CreateBuffer();
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
smaaEdgesBuffer = compositor->CreateBuffer();
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
smaaBlendBuffer = compositor->CreateBuffer();
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
updateUniforms();
areBuffersInitialized = true;
}
// Nothing to initialize
return true;
}
void ANTIALIASING_SMAA::OnLostBuffers()
{
areBuffersInitialized = false;
}
unsigned int ANTIALIASING_SMAA::CreateBuffer()
{
return compositor->CreateBuffer( compositor->GetScreenSize() );
}
void ANTIALIASING_SMAA::DrawBuffer( GLuint buffer )
{
// draw to internal buffer
compositor->DrawBuffer( buffer, smaaBaseBuffer );
}
void ANTIALIASING_SMAA::Begin()
{
compositor->SetBuffer( smaaBaseBuffer );
compositor->ClearBuffer( COLOR4D::BLACK );
}
namespace
{
void draw_fullscreen_triangle()
{
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
glBegin( GL_TRIANGLES );
glTexCoord2f( 0.0f, 1.0f );
glVertex2f( -1.0f, 1.0f );
glTexCoord2f( 0.0f, -1.0f );
glVertex2f( -1.0f, -3.0f );
glTexCoord2f( 2.0f, 1.0f );
glVertex2f( 3.0f, 1.0f );
glEnd();
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
}
} // namespace
void ANTIALIASING_SMAA::Present()
{
auto sourceTexture = compositor->GetBufferTexture( smaaBaseBuffer );
glDisable( GL_BLEND );
glDisable( GL_DEPTH_TEST );
glEnable( GL_TEXTURE_2D );
//
// pass 1: main-buffer -> smaaEdgesBuffer
//
compositor->SetBuffer( smaaEdgesBuffer );
compositor->ClearBuffer( COLOR4D::BLACK );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, sourceTexture );
checkGlError( "binding colorTex", __FILE__, __LINE__ );
pass_1_shader->Use();
checkGlError( "using smaa pass 1 shader", __FILE__, __LINE__ );
draw_fullscreen_triangle();
pass_1_shader->Deactivate();
//
// pass 2: smaaEdgesBuffer -> smaaBlendBuffer
//
compositor->SetBuffer( smaaBlendBuffer );
compositor->ClearBuffer( COLOR4D::BLACK );
auto edgesTex = compositor->GetBufferTexture( smaaEdgesBuffer );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, edgesTex );
glActiveTexture( GL_TEXTURE1 );
glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
glActiveTexture( GL_TEXTURE3 );
glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
pass_2_shader->Use();
draw_fullscreen_triangle();
pass_2_shader->Deactivate();
//
// pass 3: colorTex + BlendBuffer -> output
//
compositor->SetBuffer( WEBGL_COMPOSITOR::DIRECT_RENDERING );
compositor->ClearBuffer( COLOR4D::BLACK );
auto blendTex = compositor->GetBufferTexture( smaaBlendBuffer );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, sourceTexture );
glActiveTexture( GL_TEXTURE1 );
glBindTexture( GL_TEXTURE_2D, blendTex );
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE );
pass_3_shader->Use();
draw_fullscreen_triangle();
pass_3_shader->Deactivate();
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
}

View file

@ -0,0 +1,143 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef OPENGL_ANTIALIASING_H__
#define OPENGL_ANTIALIASING_H__
#include <memory>
#include "shader.h"
#include <math/vector2d.h>
namespace KIGFX {
class WEBGL_COMPOSITOR;
class OPENGL_PRESENTOR
{
public:
virtual ~OPENGL_PRESENTOR()
{
}
virtual bool Init() = 0;
virtual unsigned int CreateBuffer() = 0;
virtual VECTOR2I GetInternalBufferSize() = 0;
virtual void OnLostBuffers() = 0;
virtual void Begin() = 0;
virtual void DrawBuffer( GLuint aBuffer ) = 0;
virtual void Present() = 0;
};
class ANTIALIASING_NONE : public OPENGL_PRESENTOR
{
public:
ANTIALIASING_NONE( WEBGL_COMPOSITOR* aCompositor );
bool Init() override;
unsigned int CreateBuffer() override;
VECTOR2I GetInternalBufferSize() override;
void OnLostBuffers() override;
void Begin() override;
void DrawBuffer( GLuint aBuffer ) override;
void Present() override;
private:
WEBGL_COMPOSITOR* compositor;
};
class ANTIALIASING_SUPERSAMPLING : public OPENGL_PRESENTOR
{
public:
ANTIALIASING_SUPERSAMPLING( WEBGL_COMPOSITOR* aCompositor );
bool Init() override;
unsigned int CreateBuffer() override;
VECTOR2I GetInternalBufferSize() override;
void OnLostBuffers() override;
void Begin() override;
void DrawBuffer( GLuint ) override;
void Present() override;
private:
WEBGL_COMPOSITOR* compositor;
unsigned int ssaaMainBuffer;
bool areBuffersCreated;
bool areShadersCreated;
};
class ANTIALIASING_SMAA : public OPENGL_PRESENTOR
{
public:
ANTIALIASING_SMAA( WEBGL_COMPOSITOR* aCompositor );
bool Init() override;
unsigned int CreateBuffer () override;
VECTOR2I GetInternalBufferSize() override;
void OnLostBuffers() override;
void Begin() override;
void DrawBuffer( GLuint buffer ) override;
void Present() override;
private:
void loadShaders();
void updateUniforms();
bool areBuffersInitialized;
unsigned int smaaBaseBuffer; // base + overlay temporary
unsigned int smaaEdgesBuffer;
unsigned int smaaBlendBuffer;
// smaa shader lookup textures
unsigned int smaaAreaTex;
unsigned int smaaSearchTex;
bool shadersLoaded;
std::unique_ptr<SHADER> pass_1_shader;
GLint pass_1_metrics;
std::unique_ptr<SHADER> pass_2_shader;
GLint pass_2_metrics;
std::unique_ptr<SHADER> pass_3_shader;
GLint pass_3_metrics;
WEBGL_COMPOSITOR* compositor;
};
}
#endif

View file

@ -0,0 +1,421 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013-2017 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file opengl_compositor.cpp
* @brief Class that handles multitarget rendering (i.e. to different textures/surfaces) and
* later compositing into a single image (OpenGL flavour).
*/
#include "webgl_compositor.h"
#include "utils.h"
#include <gal/color4d.h>
#include <cassert>
#include <memory>
#include <stdexcept>
#include <wx/log.h>
#include <wx/debug.h>
using namespace KIGFX;
WEBGL_COMPOSITOR::WEBGL_COMPOSITOR() :
m_initialized( false ),
m_curBuffer( 0 ),
m_mainFbo( 0 ),
m_depthBuffer( 0 ),
m_curFbo( DIRECT_RENDERING ),
m_currentAntialiasingMode( GAL_ANTIALIASING_MODE::AA_NONE )
{
m_antialiasing = std::make_unique<ANTIALIASING_NONE>( this );
}
WEBGL_COMPOSITOR::~WEBGL_COMPOSITOR()
{
if( m_initialized )
{
try
{
clean();
}
catch( const std::runtime_error& exc )
{
wxLogError( wxT( "Run time exception `%s` occurred in WEBGL_COMPOSITOR destructor." ),
exc.what() );
}
}
}
void WEBGL_COMPOSITOR::SetAntialiasingMode( GAL_ANTIALIASING_MODE aMode )
{
m_currentAntialiasingMode = aMode;
if( m_initialized )
clean();
}
GAL_ANTIALIASING_MODE WEBGL_COMPOSITOR::GetAntialiasingMode() const
{
return m_currentAntialiasingMode;
}
void WEBGL_COMPOSITOR::Initialize()
{
if( m_initialized )
return;
switch( m_currentAntialiasingMode )
{
case GAL_ANTIALIASING_MODE::AA_FAST:
m_antialiasing = std::make_unique<ANTIALIASING_SMAA>( this );
break;
case GAL_ANTIALIASING_MODE::AA_HIGHQUALITY:
m_antialiasing = std::make_unique<ANTIALIASING_SUPERSAMPLING>( this );
break;
default:
m_antialiasing = std::make_unique<ANTIALIASING_NONE>( this );
break;
}
VECTOR2I dims = m_antialiasing->GetInternalBufferSize();
assert( dims.x != 0 && dims.y != 0 );
GLint maxBufSize;
glGetIntegerv( GL_MAX_RENDERBUFFER_SIZE_EXT, &maxBufSize );
if( dims.x < 0 || dims.y < 0 || dims.x > maxBufSize || dims.y >= maxBufSize )
throw std::runtime_error( "Requested render buffer size is not supported" );
// We need framebuffer objects for drawing the screen contents
// Generate framebuffer and a depth buffer
glGenFramebuffersEXT( 1, &m_mainFbo );
checkGlError( "generating framebuffer", __FILE__, __LINE__ );
bindFb( m_mainFbo );
// Allocate memory for the depth buffer
// Attach the depth buffer to the framebuffer
glGenRenderbuffersEXT( 1, &m_depthBuffer );
checkGlError( "generating renderbuffer", __FILE__, __LINE__ );
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, m_depthBuffer );
checkGlError( "binding renderbuffer", __FILE__, __LINE__ );
glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8, dims.x, dims.y );
checkGlError( "creating renderbuffer storage", __FILE__, __LINE__ );
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER_EXT, m_depthBuffer );
checkGlError( "attaching renderbuffer", __FILE__, __LINE__ );
// Unbind the framebuffer, so by default all the rendering goes directly to the display
bindFb( DIRECT_RENDERING );
m_initialized = true;
m_antialiasing->Init();
}
void WEBGL_COMPOSITOR::Resize( unsigned int aWidth, unsigned int aHeight )
{
if( m_initialized )
clean();
m_antialiasing->OnLostBuffers();
m_width = aWidth;
m_height = aHeight;
}
unsigned int WEBGL_COMPOSITOR::CreateBuffer()
{
return m_antialiasing->CreateBuffer();
}
unsigned int WEBGL_COMPOSITOR::CreateBuffer( VECTOR2I aDimensions )
{
assert( m_initialized );
int maxBuffers, maxTextureSize;
// Get the maximum number of buffers
glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS, (GLint*) &maxBuffers );
if( (int) usedBuffers() >= maxBuffers )
{
throw std::runtime_error( "Cannot create more framebuffers. OpenGL rendering backend requires at "
"least 3 framebuffers. You may try to update/change your graphic drivers." );
}
glGetIntegerv( GL_MAX_TEXTURE_SIZE, (GLint*) &maxTextureSize );
if( maxTextureSize < (int) aDimensions.x || maxTextureSize < (int) aDimensions.y )
{
throw std::runtime_error( "Requested texture size is not supported. Could not create a buffer." );
}
// GL_COLOR_ATTACHMENTn are consecutive integers
GLuint attachmentPoint = GL_COLOR_ATTACHMENT0 + usedBuffers();
GLuint textureTarget;
// Generate the texture for the pixel storage
glActiveTexture( GL_TEXTURE0 );
glGenTextures( 1, &textureTarget );
checkGlError( "generating framebuffer texture target", __FILE__, __LINE__ );
glBindTexture( GL_TEXTURE_2D, textureTarget );
checkGlError( "binding framebuffer texture target", __FILE__, __LINE__ );
// Set texture parameters
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, aDimensions.x, aDimensions.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
checkGlError( "creating framebuffer texture", __FILE__, __LINE__ );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
// Bind the texture to the specific attachment point, clear and rebind the screen
bindFb( m_mainFbo );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, attachmentPoint, GL_TEXTURE_2D, textureTarget, 0 );
// Check the status, exit if the framebuffer can't be created
GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
if( status != GL_FRAMEBUFFER_COMPLETE_EXT )
{
switch( status )
{
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
throw std::runtime_error( "The framebuffer attachment points are incomplete." );
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
throw std::runtime_error( "No images attached to the framebuffer." );
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
throw std::runtime_error( "The framebuffer does not have at least one image attached to it." );
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
throw std::runtime_error( "The framebuffer read buffer is incomplete." );
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
throw std::runtime_error( "The combination of internal formats of the attached images violates "
"an implementation-dependent set of restrictions." );
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
throw std::runtime_error( "GL_RENDERBUFFER_SAMPLES is not the same for all attached renderbuffers" );
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT:
throw std::runtime_error( "Framebuffer incomplete layer targets errors." );
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
throw std::runtime_error( "Framebuffer attachments have different dimensions" );
default:
throw std::runtime_error( "Unknown error occurred when creating the framebuffer." );
}
}
ClearBuffer( COLOR4D::BLACK );
// Return to direct rendering (we were asked only to create a buffer, not switch to one)
bindFb( DIRECT_RENDERING );
// Store the new buffer
OPENGL_BUFFER buffer = { aDimensions, textureTarget, attachmentPoint };
m_buffers.push_back( buffer );
return usedBuffers();
}
GLenum WEBGL_COMPOSITOR::GetBufferTexture( unsigned int aBufferHandle )
{
wxCHECK( aBufferHandle > 0 && aBufferHandle <= usedBuffers(), 0 );
return m_buffers[aBufferHandle - 1].textureTarget;
}
void WEBGL_COMPOSITOR::SetBuffer( unsigned int aBufferHandle )
{
wxCHECK( m_initialized && aBufferHandle <= usedBuffers(), /* void */ );
// Either unbind the FBO for direct rendering, or bind the one with target textures
bindFb( aBufferHandle == DIRECT_RENDERING ? DIRECT_RENDERING : m_mainFbo );
// Switch the target texture
if( m_curFbo != DIRECT_RENDERING )
{
m_curBuffer = aBufferHandle - 1;
glDrawBuffer( m_buffers[m_curBuffer].attachmentPoint );
checkGlError( "setting draw buffer", __FILE__, __LINE__ );
glViewport( 0, 0, m_buffers[m_curBuffer].dimensions.x, m_buffers[m_curBuffer].dimensions.y );
}
else
{
glViewport( 0, 0, GetScreenSize().x, GetScreenSize().y );
}
}
void WEBGL_COMPOSITOR::ClearBuffer( const COLOR4D& aColor )
{
wxCHECK( m_initialized, /* void */ );
glClearColor( aColor.r, aColor.g, aColor.b, m_curFbo == DIRECT_RENDERING ? 1.0f : 0.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
}
VECTOR2I WEBGL_COMPOSITOR::GetScreenSize() const
{
typedef VECTOR2I::coord_type coord_t;
wxASSERT( m_width <= static_cast<unsigned int>( std::numeric_limits<coord_t>::max() ) );
wxASSERT( m_height <= static_cast<unsigned int>( std::numeric_limits<coord_t>::max() ) );
return { static_cast<coord_t>( m_width ), static_cast<coord_t>( m_height ) };
}
void WEBGL_COMPOSITOR::Begin()
{
m_antialiasing->Begin();
}
void WEBGL_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle )
{
m_antialiasing->DrawBuffer( aBufferHandle );
}
void WEBGL_COMPOSITOR::DrawBuffer( unsigned int aSourceHandle, unsigned int aDestHandle )
{
wxCHECK( m_initialized && aSourceHandle != 0 && aSourceHandle <= usedBuffers(), /* void */ );
wxCHECK( aDestHandle <= usedBuffers(), /* void */ );
// Switch to the destination buffer and blit the scene
SetBuffer( aDestHandle );
// Depth test has to be disabled to make transparency working
glDisable( GL_DEPTH_TEST );
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
// Enable texturing and bind the main texture
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, m_buffers[aSourceHandle - 1].textureTarget );
// Draw a full screen quad with the texture
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
glBegin( GL_TRIANGLES );
glTexCoord2f( 0.0f, 1.0f );
glVertex2f( -1.0f, 1.0f );
glTexCoord2f( 0.0f, 0.0f );
glVertex2f( -1.0f, -1.0f );
glTexCoord2f( 1.0f, 1.0f );
glVertex2f( 1.0f, 1.0f );
glTexCoord2f( 1.0f, 1.0f );
glVertex2f( 1.0f, 1.0f );
glTexCoord2f( 0.0f, 0.0f );
glVertex2f( -1.0f, -1.0f );
glTexCoord2f( 1.0f, 0.0f );
glVertex2f( 1.0f, -1.0f );
glEnd();
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
}
void WEBGL_COMPOSITOR::Present()
{
m_antialiasing->Present();
}
void WEBGL_COMPOSITOR::bindFb( unsigned int aFb )
{
// Currently there are only 2 valid FBOs
wxASSERT( aFb == DIRECT_RENDERING || aFb == m_mainFbo );
if( m_curFbo != aFb )
{
glBindFramebufferEXT( GL_FRAMEBUFFER, aFb );
checkGlError( "switching framebuffer", __FILE__, __LINE__ );
m_curFbo = aFb;
}
}
void WEBGL_COMPOSITOR::clean()
{
wxCHECK( m_initialized, /* void */ );
bindFb( DIRECT_RENDERING );
for( const OPENGL_BUFFER& buffer : m_buffers )
glDeleteTextures( 1, &buffer.textureTarget );
m_buffers.clear();
if( glDeleteFramebuffersEXT )
glDeleteFramebuffersEXT( 1, &m_mainFbo );
if( glDeleteRenderbuffersEXT )
glDeleteRenderbuffersEXT( 1, &m_depthBuffer );
m_initialized = false;
}
int WEBGL_COMPOSITOR::GetAntialiasSupersamplingFactor() const
{
switch ( m_currentAntialiasingMode )
{
case GAL_ANTIALIASING_MODE::AA_HIGHQUALITY: return 2;
default: return 1;
}
}
VECTOR2D WEBGL_COMPOSITOR::GetAntialiasRenderingOffset() const
{
switch( m_currentAntialiasingMode )
{
case GAL_ANTIALIASING_MODE::AA_HIGHQUALITY: return VECTOR2D( 0.5, -0.5 );
default: return VECTOR2D( 0, 0 );
}
}

View file

@ -0,0 +1,139 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013-2016 CERN
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file opengl_compositor.h
* Handle multitarget rendering (ie. to different textures/surfaces) and later compositing
* into a single image (OpenGL flavor).
*/
#ifndef WEBGL_COMPOSITOR_H_
#define WEBGL_COMPOSITOR_H_
#include "kiglew.h" // Must be included first
#include <gal/compositor.h>
#include "webgl_antialiasing.h"
#include <gal/gal_display_options.h>
#include <deque>
namespace KIGFX
{
class WEBGL_COMPOSITOR : public COMPOSITOR
{
public:
WEBGL_COMPOSITOR();
virtual ~WEBGL_COMPOSITOR();
/// @copydoc COMPOSITOR::Initialize()
virtual void Initialize() override;
/// @copydoc COMPOSITOR::Resize()
virtual void Resize( unsigned int aWidth, unsigned int aHeight ) override;
/// @copydoc COMPOSITOR::CreateBuffer()
virtual unsigned int CreateBuffer() override;
/// @copydoc COMPOSITOR::SetBuffer()
virtual void SetBuffer( unsigned int aBufferHandle ) override;
/// @copydoc COMPOSITOR::GetBuffer()
inline virtual unsigned int GetBuffer() const override
{
if( m_curFbo == DIRECT_RENDERING )
return DIRECT_RENDERING;
return m_curBuffer + 1;
}
/// @copydoc COMPOSITOR::ClearBuffer()
virtual void ClearBuffer( const COLOR4D& aColor ) override;
/// @copydoc COMPOSITOR::DrawBuffer()
virtual void DrawBuffer( unsigned int aBufferHandle ) override;
/// @copydoc COMPOSITOR::Begin()
virtual void Begin() override;
// @copydoc COMPOSITOR::Present()
virtual void Present() override;
// Constant used by glBindFramebuffer to turn off rendering to framebuffers
static const unsigned int DIRECT_RENDERING = 0;
VECTOR2I GetScreenSize() const;
GLenum GetBufferTexture( unsigned int aBufferHandle );
void DrawBuffer( unsigned int aSourceHandle, unsigned int aDestHandle );
unsigned int CreateBuffer( VECTOR2I aDimensions );
void SetAntialiasingMode( GAL_ANTIALIASING_MODE aMode ); // clears all buffers
GAL_ANTIALIASING_MODE GetAntialiasingMode() const;
int GetAntialiasSupersamplingFactor() const;
VECTOR2D GetAntialiasRenderingOffset() const;
protected:
/// Binds a specific Framebuffer Object.
void bindFb( unsigned int aFb );
/**
* Perform freeing of resources.
*/
void clean();
/// Returns number of used buffers
inline unsigned int usedBuffers()
{
return m_buffers.size();
}
// Buffers are simply textures storing a result of certain target rendering.
struct OPENGL_BUFFER
{
VECTOR2I dimensions;
GLuint textureTarget; ///< Main texture handle
GLuint attachmentPoint; ///< Point to which an image from texture is attached
};
bool m_initialized; ///< Initialization status flag
unsigned int m_curBuffer; ///< Currently used buffer handle
GLuint m_mainFbo; ///< Main FBO handle (storing all target textures)
GLuint m_depthBuffer; ///< Depth buffer handle
typedef std::deque<OPENGL_BUFFER> OPENGL_BUFFERS;
/// Stores information about initialized buffers
OPENGL_BUFFERS m_buffers;
/// Store the used FBO name in case there was more than one compositor used
GLuint m_curFbo;
GAL_ANTIALIASING_MODE m_currentAntialiasingMode;
std::unique_ptr<OPENGL_PRESENTOR> m_antialiasing;
};
} // namespace KIGFX
#endif /* COMPOSITOR_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,614 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2013-2017 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* Graphics Abstraction Layer (GAL) for OpenGL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef OPENGLGAL_H_
#define OPENGLGAL_H_
// GAL imports
#include <gal/gal.h>
#include <gal/graphics_abstraction_layer.h>
#include <gal/gal_display_options.h>
#include "shader.h"
#include "vertex_manager.h"
#include "vertex_item.h"
#include "cached_container.h"
#include "noncached_container.h"
#include "webgl_compositor.h"
#include <gal/hidpi_gl_canvas.h>
#include <unordered_map>
#include <memory>
#include <wx/event.h>
#ifndef CALLBACK
#define CALLBACK
#endif
///< The default number of points for circle approximation
#define SEG_PER_CIRCLE_COUNT 64
struct bitmap_glyph;
namespace KIGFX
{
class SHADER;
class GL_BITMAP_CACHE;
/**
* OpenGL implementation of the Graphics Abstraction Layer.
*
* This is a direct OpenGL-implementation and uses low-level graphics primitives like triangles
* and quads. The purpose is to provide a fast graphics interface, that takes advantage of modern
* graphics card GPUs. All methods here benefit thus from the hardware acceleration.
*/
class GAL_API WEBGL_GAL : public GAL, public HIDPI_GL_CANVAS
{
public:
/**
* @param aParent is the wxWidgets immediate wxWindow parent of this object.
*
* @param aMouseListener is the wxEvtHandler that should receive the mouse events,
* this can be can be any wxWindow, but is often a wxFrame container.
*
* @param aPaintListener is the wxEvtHandler that should receive the paint
* event. This can be any wxWindow, but is often a derived instance
* of this class or a containing wxFrame. The "paint event" here is
* a wxCommandEvent holding EVT_GAL_REDRAW, as sent by PostPaint().
*
* @param aName is the name of this window for use by wxWindow::FindWindowByName()
*/
WEBGL_GAL( const KIGFX::VC_SETTINGS& aVcSettings, GAL_DISPLAY_OPTIONS& aDisplayOptions,
wxWindow* aParent,
wxEvtHandler* aMouseListener = nullptr, wxEvtHandler* aPaintListener = nullptr,
const wxString& aName = wxT( "GLCanvas" ) );
~WEBGL_GAL();
/**
* Checks OpenGL features.
*
* @param aOptions
* @return wxEmptyString if OpenGL 2.1 or greater is available, otherwise returns error message
*/
static wxString CheckFeatures( GAL_DISPLAY_OPTIONS& aOptions );
bool IsOpenGlEngine() override { return true; }
/// @copydoc GAL::IsInitialized()
bool IsInitialized() const override
{
// is*Initialized flags, but it is enough for OpenGL to show up
return IsShownOnScreen() && !GetClientRect().IsEmpty();
}
///< @copydoc GAL::IsVisible()
bool IsVisible() const override
{
return IsShownOnScreen() && !GetClientRect().IsEmpty();
}
void SetMinLineWidth( float aLineWidth ) override;
// ---------------
// Drawing methods
// ---------------
/// @copydoc GAL::DrawLine()
void DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) override;
/// @copydoc GAL::DrawSegment()
void DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
double aWidth ) override;
/// @copydoc GAL::DrawSegmentChain()
void DrawSegmentChain( const std::vector<VECTOR2D>& aPointList, double aWidth ) override;
void DrawSegmentChain( const SHAPE_LINE_CHAIN& aLineChain, double aWidth ) override;
/// @copydoc GAL::DrawCircle()
void DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) override;
/// @copydoc GAL::DrawHoleWall()
void DrawHoleWall( const VECTOR2D& aCenterPoint, double aHoleRadius,
double aWallWidth ) override;
/// @copydoc GAL::DrawArc()
void DrawArc( const VECTOR2D& aCenterPoint, double aRadius, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aAngle ) override;
/// @copydoc GAL::DrawArcSegment()
void DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, const EDA_ANGLE& aStartAngle,
const EDA_ANGLE& aAngle, double aWidth, double aMaxError ) override;
/// @copydoc GAL::DrawRectangle()
void DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) override;
/// @copydoc GAL::DrawPolyline()
void DrawPolyline( const std::deque<VECTOR2D>& aPointList ) override;
void DrawPolyline( const std::vector<VECTOR2D>& aPointList ) override;
void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) override;
void DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain ) override;
/// @copydoc GAL::DrawPolylines()
void DrawPolylines( const std::vector<std::vector<VECTOR2D>>& aPointLists ) override;
/// @copydoc GAL::DrawPolygon()
void DrawPolygon( const std::deque<VECTOR2D>& aPointList ) override;
void DrawPolygon( const VECTOR2D aPointList[], int aListSize ) override;
void DrawPolygon( const SHAPE_POLY_SET& aPolySet, bool aStrokeTriangulation = false ) override;
void DrawPolygon( const SHAPE_LINE_CHAIN& aPolySet ) override;
/// @copydoc GAL::DrawGlyph()
virtual void DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal ) override;
/// @copydoc GAL::DrawGlyphs()
virtual void DrawGlyphs( const std::vector<std::unique_ptr<KIFONT::GLYPH>>& aGlyphs ) override;
/// @copydoc GAL::DrawCurve()
void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA,
const VECTOR2D& controlPointB, const VECTOR2D& endPoint,
double aFilterValue = 0.0 ) override;
/// @copydoc GAL::DrawBitmap()
void DrawBitmap( const BITMAP_BASE& aBitmap, double alphaBlend = 1.0 ) override;
/// @copydoc GAL::BitmapText()
void BitmapText( const wxString& aText, const VECTOR2I& aPosition,
const EDA_ANGLE& aAngle ) override;
/// @copydoc GAL::DrawGrid()
void DrawGrid() override;
// --------------
// Screen methods
// --------------
/// @brief Resizes the canvas.
void ResizeScreen( int aWidth, int aHeight ) override;
/// @brief Shows/hides the GAL canvas
bool Show( bool aShow ) override;
/// @copydoc GAL::GetSwapInterval()
int GetSwapInterval() const override { return m_swapInterval; };
/// @copydoc GAL::Flush()
void Flush() override;
/// @copydoc GAL::ClearScreen()
void ClearScreen( ) override;
// --------------
// Transformation
// --------------
/// @copydoc GAL::Transform()
void Transform( const MATRIX3x3D& aTransformation ) override;
/// @copydoc GAL::Rotate()
void Rotate( double aAngle ) override;
/// @copydoc GAL::Translate()
void Translate( const VECTOR2D& aTranslation ) override;
/// @copydoc GAL::Scale()
void Scale( const VECTOR2D& aScale ) override;
/// @copydoc GAL::Save()
void Save() override;
/// @copydoc GAL::Restore()
void Restore() override;
// --------------------------------------------
// Group methods
// ---------------------------------------------
/// @copydoc GAL::BeginGroup()
int BeginGroup() override;
/// @copydoc GAL::EndGroup()
void EndGroup() override;
/// @copydoc GAL::DrawGroup()
void DrawGroup( int aGroupNumber ) override;
/// @copydoc GAL::ChangeGroupColor()
void ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor ) override;
/// @copydoc GAL::ChangeGroupDepth()
void ChangeGroupDepth( int aGroupNumber, int aDepth ) override;
/// @copydoc GAL::DeleteGroup()
void DeleteGroup( int aGroupNumber ) override;
/// @copydoc GAL::ClearCache()
void ClearCache() override;
// --------------------------------------------------------
// Handling the world <-> screen transformation
// --------------------------------------------------------
/// @copydoc GAL::SetTarget()
void SetTarget( RENDER_TARGET aTarget ) override;
/// @copydoc GAL::GetTarget()
RENDER_TARGET GetTarget() const override;
/// @copydoc GAL::ClearTarget()
void ClearTarget( RENDER_TARGET aTarget ) override;
/// @copydoc GAL::HasTarget()
virtual bool HasTarget( RENDER_TARGET aTarget ) override;
/// @copydoc GAL::SetNegativeDrawMode()
void SetNegativeDrawMode( bool aSetting ) override {}
/// @copydoc GAL::StartDiffLayer()
void StartDiffLayer() override;
//
/// @copydoc GAL::EndDiffLayer()
void EndDiffLayer() override;
void ComputeWorldScreenMatrix() override;
// -------
// Cursor
// -------
/// @copydoc GAL::SetNativeCursorStyle()
bool SetNativeCursorStyle( KICURSOR aCursor, bool aHiDPI ) override;
/// @copydoc GAL::DrawCursor()
void DrawCursor( const VECTOR2D& aCursorPosition ) override;
/**
* Post an event to #m_paint_listener.
*
* A post is used so that the actual drawing function can use a device context type that
* is not specific to the wxEVT_PAINT event, just by changing the PostPaint code.
*/
void PostPaint( wxPaintEvent& aEvent );
void SetMouseListener( wxEvtHandler* aMouseListener )
{
m_mouseListener = aMouseListener;
}
void SetPaintListener( wxEvtHandler* aPaintListener )
{
m_paintListener = aPaintListener;
}
void EnableDepthTest( bool aEnabled = false ) override;
bool IsContextLocked() override
{
return m_isContextLocked;
}
void LockContext( int aClientCookie ) override;
void UnlockContext( int aClientCookie ) override;
/// @copydoc GAL::BeginDrawing()
void BeginDrawing() override;
/// @copydoc GAL::EndDrawing()
void EndDrawing() override;
///< Parameters passed to the GLU tesselator
struct TessParams
{
/// Manager used for storing new vertices
VERTEX_MANAGER* vboManager;
/// Intersect points, that have to be freed after tessellation
std::deque<std::shared_ptr<GLdouble>>& intersectPoints;
};
private:
/// Super class definition
typedef GAL super;
static wxGLContext* m_glMainContext; ///< Parent OpenGL context
wxGLContext* m_glPrivContext; ///< Canvas-specific OpenGL context
int m_swapInterval; ///< Used to store swap interval information
static int m_instanceCounter; ///< GL GAL instance counter
wxEvtHandler* m_mouseListener;
wxEvtHandler* m_paintListener;
static GLuint g_fontTexture; ///< Bitmap font texture handle (shared)
// Vertex buffer objects related fields
typedef std::unordered_map< unsigned int, std::shared_ptr<VERTEX_ITEM> > GROUPS_MAP;
GROUPS_MAP m_groups; ///< Stores information about VBO objects (groups)
unsigned int m_groupCounter; ///< Counter used for generating keys for groups
VERTEX_MANAGER* m_currentManager; ///< Currently used VERTEX_MANAGER (for storing
///< VERTEX_ITEMs).
VERTEX_MANAGER* m_cachedManager; ///< Container for storing cached VERTEX_ITEMs
VERTEX_MANAGER* m_nonCachedManager; ///< Container for storing non-cached VERTEX_ITEMs
VERTEX_MANAGER* m_overlayManager; ///< Container for storing overlaid VERTEX_ITEMs
/// Container for storing temp (diff mode) VERTEX_ITEMs
VERTEX_MANAGER* m_tempManager;
// Framebuffer & compositing
WEBGL_COMPOSITOR* m_compositor; ///< Handles multiple rendering targets
unsigned int m_mainBuffer; ///< Main rendering target
unsigned int m_overlayBuffer; ///< Auxiliary rendering target (for menus etc.)
unsigned int m_tempBuffer; ///< Temporary rendering target (for diffing etc.)
RENDER_TARGET m_currentTarget; ///< Current rendering target
// Shader
/// There is only one shader used for different objects.
SHADER* m_shader;
// Internal flags
bool m_isFramebufferInitialized; ///< Are the framebuffers initialized?
static bool m_isBitmapFontLoaded; ///< Is the bitmap font texture loaded?
bool m_isBitmapFontInitialized; ///< Is the shader set to use bitmap fonts?
bool m_isInitialized; ///< Basic initialization flag, has to be
///< done when the window is visible
bool m_isGrouping; ///< Was a group started?
bool m_isContextLocked; ///< Used for assertion checking
int m_lockClientCookie;
GLint ufm_worldPixelSize;
GLint ufm_screenPixelSize;
GLint ufm_pixelSizeMultiplier;
GLint ufm_antialiasingOffset;
GLint ufm_minLinePixelWidth;
GLint ufm_fontTexture;
GLint ufm_fontTextureWidth;
/// wx cursor showing the current native cursor.
WX_CURSOR_TYPE m_currentwxCursor;
std::unique_ptr<GL_BITMAP_CACHE> m_bitmapCache;
// Polygon tesselation
GLUtesselator* m_tesselator;
std::deque<std::shared_ptr<GLdouble>> m_tessIntersects;
/// @copydoc GAL::BeginUpdate()
void beginUpdate() override;
/// @copydoc GAL::EndUpdate()
void endUpdate() override;
///< Update handler for OpenGL settings
bool updatedGalDisplayOptions( const GAL_DISPLAY_OPTIONS& aOptions ) override;
/**
* Draw a quad for the line.
*
* @param aStartPoint is the start point of the line.
* @param aEndPoint is the end point of the line.
* @param aReserve if set to false, call reserveLineQuads beforehand
* to reserve the right amount of vertices.
*/
void drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
bool aReserve = true );
/**
* Reserve specified number of line quads.
*
* @param aLineCount the number of line quads to reserve.
*/
void reserveLineQuads( const int aLineCount );
/**
* Draw a semicircle.
*
* Depending on settings (m_isStrokeEnabled & isFilledEnabled) it runs the proper function
* (drawStrokedSemiCircle or drawFilledSemiCircle).
*
* @param aCenterPoint is the center point.
* @param aRadius is the radius of the semicircle.
* @param aAngle is the angle of the semicircle.
*
*/
void drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle );
/**
*Draw a filled semicircle.
*
* @param aCenterPoint is the center point.
* @param aRadius is the radius of the semicircle.
* @param aAngle is the angle of the semicircle.
*
*/
void drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle );
/**
* Draw a stroked semicircle.
*
* @param aCenterPoint is the center point.
* @param aRadius is the radius of the semicircle.
* @param aAngle is the angle of the semicircle.
* @param aReserve if set to false, reserve 3 vertices for each semicircle.
*
*/
void drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle,
bool aReserve = true );
/**
* Internal method for circle drawing.
*
* @param aReserve if set to false, reserve 3 vertices for each circle.
*/
void drawCircle( const VECTOR2D& aCenterPoint, double aRadius, bool aReserve = true );
/**
* Generic way of drawing a polyline stored in different containers.
*
* @param aPointGetter is a function to obtain coordinates of n-th vertex.
* @param aPointCount is the number of points to be drawn.
* @param aReserve if set to false, reserve aPointCount - 1 line quads.
*/
void drawPolyline( const std::function<VECTOR2D( int )>& aPointGetter, int aPointCount,
bool aReserve = true );
/**
* Generic way of drawing a chain of segments stored in different containers.
*
* @param aPointGetter is a function to obtain coordinates of n-th vertex.
* @param aPointCount is the number of points to be drawn.
* @param aReserve if set to false, do not reserve vertices internally.
*/
void drawSegmentChain( const std::function<VECTOR2D( int )>& aPointGetter, int aPointCount,
double aWidth, bool aReserve = true );
/**
* Internal method for segment drawing
*/
void drawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth,
bool aReserve = true );
/**
* Draw a filled polygon. It does not need the last point to have the same coordinates
* as the first one.
*
* @param aPoints is the vertices data (3 coordinates: x, y, z).
* @param aPointCount is the number of points.
*/
void drawPolygon( GLdouble* aPoints, int aPointCount );
/**
* Draw a set of polygons with a cached triangulation. Way faster than drawPolygon.
*
* @param aStrokeTriangulation indicates the triangulation should be stroked rather than
* filled. Used for debugging.
*/
void drawTriangulatedPolyset( const SHAPE_POLY_SET& aPoly, bool aStrokeTriangulation );
/**
* Draw a single character using bitmap font.
*
* Its main purpose is to be used in BitmapText() function.
*
* @param aChar is the character to be drawn.
* @return Width of the drawn glyph.
* @param aReserve if set to false, reserve 6 vertices for each character.
*/
int drawBitmapChar( unsigned long aChar, bool aReserve = true );
/**
* Draw an overbar over the currently drawn text.
*
* Its main purpose is to be used in BitmapText() function.
* This method requires appropriate scaling to be applied (as is done in BitmapText() function).
* The current X coordinate will be the overbar ending.
*
* @param aLength is the width of the overbar.
* @param aHeight is the height for the overbar.
* @param aReserve if set to false, reserve 6 vertices for each overbar.
*/
void drawBitmapOverbar( double aLength, double aHeight, bool aReserve = true );
/**
* Compute a size of text drawn using bitmap font with current text setting applied.
*
* @param aText is the text to be drawn.
* @return Pair containing text bounding box and common Y axis offset. The values are expressed
* as a number of pixels on the bitmap font texture and need to be scaled before drawing.
*/
std::pair<VECTOR2D, float> computeBitmapTextSize( const UTF8& aText ) const;
// Event handling
/**
* This is the OnPaint event handler.
*
* @param aEvent is the OnPaint event.
*/
void onPaint( wxPaintEvent& aEvent );
/**
* Skip the mouse event to the parent.
*
* @param aEvent is the mouse event.
*/
void skipMouseEvent( wxMouseEvent& aEvent );
/**
* Skip the gesture event to the parent.
*
* @param aEvent is the gesture event.
*/
void skipGestureEvent( wxGestureEvent& aEvent );
/**
* Give the correct cursor image when the native widget asks for it.
*
* @param aEvent is the cursor event to plac the cursor into.
*/
void onSetNativeCursor( wxSetCursorEvent& aEvent );
/**
* Blit cursor into the current screen.
*/
void blitCursor();
/**
* Return a valid key that can be used as a new group number.
*
* @return An unique group number that is not used by any other group.
*/
unsigned int getNewGroupNumber();
/**
* Compute the angle step when drawing arcs/circles approximated with lines.
*/
double calcAngleStep( double aRadius ) const
{
// Bigger arcs need smaller alpha increment to make them look smooth
return std::min( 1e6 / aRadius, 2.0 * M_PI / SEG_PER_CIRCLE_COUNT );
}
double getWorldPixelSize() const;
VECTOR2D getScreenPixelSize() const;
/**
* Set up the shader parameters for OpenGL rendering.
* This method initializes all the uniform parameter locations
* after the shader has been linked.
*/
void setupShaderParameters();
/**
* Basic OpenGL initialization and feature checks.
*
* @throw std::runtime_error if any of the OpenGL feature checks failed
*/
void init();
};
} // namespace KIGFX
#endif // OPENGLGAL_H_