Commit 28ee90fc authored by Miguel Casas's avatar Miguel Casas Committed by Commit Bot

Ozone: enumerate minigbm's supported TEXTURING formats

This CL enumerates minigbm supported formats for GBM_BO_USE_TEXTURING,
and creates a vector that can be obtained through SurfaceFactoryOzone
GetSupportedFormatsForTexturing(). This CL also wires that to a new
GpuInfo entry supported over Mojo (and dumped in chrome:gpu).

This CL is used in e.g. crrev.com/c/1590464 in GLES2DecoderImpl's
GetCapabilities() (vicinity of [1]) to indicate if the platform
supports or not P010 (and will possibly be used to address the
TODO in [2] where a gles2 FeatureFlag is hardcoded).

[1] https://cs.chromium.org/chromium/src/gpu/command_buffer/service/gles2_cmd_decoder.cc?gsn=ContextGroup&g=0&l=4266
[2] https://cs.chromium.org/chromium/src/gpu/command_buffer/service/feature_info.cc?type=cs&g=0&l=1102

Bug: 911754, 646148
Change-Id: I49d6002a06d1f4585956f8f0746ab5349e2714e8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1612041Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Reviewed-by: default avatarKenneth Russell <kbr@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarJorge Lucangeli Obes <jorgelo@chromium.org>
Reviewed-by: default avatarDaniel Nicoara <dnicoara@chromium.org>
Commit-Queue: Miguel Casas <mcasas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#663857}
parent c036ac28
...@@ -304,6 +304,21 @@ std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue( ...@@ -304,6 +304,21 @@ std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue(
"RGBA visual ID", base::NumberToString(gpu_info.rgba_visual))); "RGBA visual ID", base::NumberToString(gpu_info.rgba_visual)));
#endif #endif
std::string buffer_formats;
for (int i = 0; i <= static_cast<int>(gfx::BufferFormat::LAST); ++i) {
const gfx::BufferFormat buffer_format = static_cast<gfx::BufferFormat>(i);
if (i > 0)
buffer_formats += ", ";
buffer_formats += gfx::BufferFormatToString(buffer_format);
const bool supported = base::ContainsValue(
gpu_info.supported_buffer_formats_for_allocation_and_texturing,
buffer_format);
buffer_formats += supported ? ": supported" : ": not supported";
}
basic_info->Append(NewDescriptionValuePair(
"gfx::BufferFormats supported for allocation and texturing",
buffer_formats));
return basic_info; return basic_info;
} }
......
...@@ -137,6 +137,16 @@ void AddArmMaliGpuWhitelist(std::vector<BrokerFilePermission>* permissions) { ...@@ -137,6 +137,16 @@ void AddArmMaliGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
permissions->push_back(BrokerFilePermission::ReadWrite(kMali0Path)); permissions->push_back(BrokerFilePermission::ReadWrite(kMali0Path));
permissions->push_back(BrokerFilePermission::ReadWrite(kDevImageProc0Path)); permissions->push_back(BrokerFilePermission::ReadWrite(kDevImageProc0Path));
// Non-privileged render nodes for format enumeration.
// https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html#render-nodes
base::FileEnumerator enumerator(
base::FilePath(FILE_PATH_LITERAL("/dev/dri/")), false /* recursive */,
base::FileEnumerator::FILES, FILE_PATH_LITERAL("renderD*"));
for (base::FilePath name = enumerator.Next(); !name.empty();
name = enumerator.Next()) {
permissions->push_back(BrokerFilePermission::ReadWrite(name.value()));
}
} }
void AddImgPvrGpuWhitelist(std::vector<BrokerFilePermission>* permissions) { void AddImgPvrGpuWhitelist(std::vector<BrokerFilePermission>* permissions) {
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include "gpu/config/gpu_info.h" #include "gpu/config/gpu_info.h"
#include "ui/gfx/buffer_format_util.h"
namespace { namespace {
void EnumerateGPUDevice(const gpu::GPUInfo::GPUDevice& device, void EnumerateGPUDevice(const gpu::GPUInfo::GPUDevice& device,
...@@ -251,6 +253,9 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const { ...@@ -251,6 +253,9 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
ImageDecodeAcceleratorSupportedProfiles ImageDecodeAcceleratorSupportedProfiles
image_decode_accelerator_supported_profiles; image_decode_accelerator_supported_profiles;
std::vector<gfx::BufferFormat>
supported_buffer_formats_for_allocation_and_texturing;
#if defined(USE_X11) #if defined(USE_X11)
VisualID system_visual; VisualID system_visual;
VisualID rgba_visual; VisualID rgba_visual;
...@@ -274,8 +279,7 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const { ...@@ -274,8 +279,7 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
EnumerateGPUDevice(secondary_gpu, enumerator); EnumerateGPUDevice(secondary_gpu, enumerator);
enumerator->BeginAuxAttributes(); enumerator->BeginAuxAttributes();
enumerator->AddTimeDeltaInSecondsF("initializationTime", enumerator->AddTimeDeltaInSecondsF("initializationTime", initialization_time);
initialization_time);
enumerator->AddBool("optimus", optimus); enumerator->AddBool("optimus", optimus);
enumerator->AddBool("amdSwitchable", amd_switchable); enumerator->AddBool("amdSwitchable", amd_switchable);
enumerator->AddString("pixelShaderVersion", pixel_shader_version); enumerator->AddString("pixelShaderVersion", pixel_shader_version);
...@@ -311,6 +315,8 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const { ...@@ -311,6 +315,8 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
#endif #endif
enumerator->AddInt("videoDecodeAcceleratorFlags", enumerator->AddInt("videoDecodeAcceleratorFlags",
video_decode_accelerator_capabilities.flags); video_decode_accelerator_capabilities.flags);
// TODO(crbug.com/966839): Fix the two supported profile dumping below.
for (const auto& profile : for (const auto& profile :
video_decode_accelerator_capabilities.supported_profiles) video_decode_accelerator_capabilities.supported_profiles)
EnumerateVideoDecodeAcceleratorSupportedProfile(profile, enumerator); EnumerateVideoDecodeAcceleratorSupportedProfile(profile, enumerator);
...@@ -325,6 +331,14 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const { ...@@ -325,6 +331,14 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
enumerator->AddInt64("rgbaVisual", rgba_visual); enumerator->AddInt64("rgbaVisual", rgba_visual);
#endif #endif
enumerator->AddBool("oopRasterizationSupported", oop_rasterization_supported); enumerator->AddBool("oopRasterizationSupported", oop_rasterization_supported);
std::string supported_formats;
for (const auto& format :
supported_buffer_formats_for_allocation_and_texturing) {
supported_formats += gfx::BufferFormatToString(format);
supported_formats += " ";
}
enumerator->AddString("supportedBufferFormatsForAllocationAndTexturing",
supported_formats);
enumerator->EndAuxAttributes(); enumerator->EndAuxAttributes();
} }
......
...@@ -24,6 +24,10 @@ ...@@ -24,6 +24,10 @@
typedef unsigned long VisualID; typedef unsigned long VisualID;
#endif #endif
namespace gfx {
enum class BufferFormat;
}
namespace gpu { namespace gpu {
// These values are persisted to logs. Entries should not be renumbered and // These values are persisted to logs. Entries should not be renumbered and
...@@ -330,6 +334,9 @@ struct GPU_EXPORT GPUInfo { ...@@ -330,6 +334,9 @@ struct GPU_EXPORT GPUInfo {
ImageDecodeAcceleratorSupportedProfiles ImageDecodeAcceleratorSupportedProfiles
image_decode_accelerator_supported_profiles; image_decode_accelerator_supported_profiles;
std::vector<gfx::BufferFormat>
supported_buffer_formats_for_allocation_and_texturing;
#if defined(USE_X11) #if defined(USE_X11)
VisualID system_visual; VisualID system_visual;
VisualID rgba_visual; VisualID rgba_visual;
......
...@@ -206,6 +206,7 @@ mojom("interfaces") { ...@@ -206,6 +206,7 @@ mojom("interfaces") {
":gpu_preferences_interface", ":gpu_preferences_interface",
"//mojo/public/mojom/base", "//mojo/public/mojom/base",
"//ui/gfx/geometry/mojo", "//ui/gfx/geometry/mojo",
"//ui/gfx/mojo",
] ]
} }
......
...@@ -8,6 +8,7 @@ module gpu.mojom; ...@@ -8,6 +8,7 @@ module gpu.mojom;
import "gpu/ipc/common/dx_diag_node.mojom"; import "gpu/ipc/common/dx_diag_node.mojom";
import "mojo/public/mojom/base/time.mojom"; import "mojo/public/mojom/base/time.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom"; import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/gfx/mojo/buffer_types.mojom";
// gpu::GPUInfo::GPUDevice // gpu::GPUInfo::GPUDevice
struct GpuDevice { struct GpuDevice {
...@@ -162,6 +163,9 @@ struct GpuInfo { ...@@ -162,6 +163,9 @@ struct GpuInfo {
array<ImageDecodeAcceleratorSupportedProfile> array<ImageDecodeAcceleratorSupportedProfile>
image_decode_accelerator_supported_profiles; image_decode_accelerator_supported_profiles;
array<gfx.mojom.BufferFormat>
supported_buffer_formats_for_allocation_and_texturing;
uint64 system_visual; uint64 system_visual;
uint64 rgba_visual; uint64 rgba_visual;
bool oop_rasterization_supported; bool oop_rasterization_supported;
......
...@@ -393,7 +393,9 @@ bool StructTraits<gpu::mojom::GpuInfoDataView, gpu::GPUInfo>::Read( ...@@ -393,7 +393,9 @@ bool StructTraits<gpu::mojom::GpuInfoDataView, gpu::GPUInfo>::Read(
data.ReadVideoEncodeAcceleratorSupportedProfiles( data.ReadVideoEncodeAcceleratorSupportedProfiles(
&out->video_encode_accelerator_supported_profiles) && &out->video_encode_accelerator_supported_profiles) &&
data.ReadImageDecodeAcceleratorSupportedProfiles( data.ReadImageDecodeAcceleratorSupportedProfiles(
&out->image_decode_accelerator_supported_profiles); &out->image_decode_accelerator_supported_profiles) &&
data.ReadSupportedBufferFormatsForAllocationAndTexturing(
&out->supported_buffer_formats_for_allocation_and_texturing);
} }
} // namespace mojo } // namespace mojo
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "gpu/ipc/common/dx_diag_node_struct_traits.h" #include "gpu/ipc/common/dx_diag_node_struct_traits.h"
#include "gpu/ipc/common/gpu_info.mojom.h" #include "gpu/ipc/common/gpu_info.mojom.h"
#include "ui/gfx/geometry/mojo/geometry_struct_traits.h" #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
#include "ui/gfx/mojo/buffer_types_struct_traits.h"
namespace mojo { namespace mojo {
...@@ -363,6 +364,12 @@ struct StructTraits<gpu::mojom::GpuInfoDataView, gpu::GPUInfo> { ...@@ -363,6 +364,12 @@ struct StructTraits<gpu::mojom::GpuInfoDataView, gpu::GPUInfo> {
return input.image_decode_accelerator_supported_profiles; return input.image_decode_accelerator_supported_profiles;
} }
static std::vector<gfx::BufferFormat>
supported_buffer_formats_for_allocation_and_texturing(
const gpu::GPUInfo& input) {
return input.supported_buffer_formats_for_allocation_and_texturing;
}
static uint64_t system_visual(const gpu::GPUInfo& input) { static uint64_t system_visual(const gpu::GPUInfo& input) {
#if defined(USE_X11) #if defined(USE_X11)
return input.system_visual; return input.system_visual;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#if defined(USE_OZONE) #if defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h" #include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#endif #endif
#if defined(OS_WIN) #if defined(OS_WIN)
...@@ -240,6 +241,10 @@ bool GpuInit::InitializeAndStartSandbox(base::CommandLine* command_line, ...@@ -240,6 +241,10 @@ bool GpuInit::InitializeAndStartSandbox(base::CommandLine* command_line,
.requires_mojo; .requires_mojo;
params.viz_display_compositor = features::IsVizDisplayCompositorEnabled(); params.viz_display_compositor = features::IsVizDisplayCompositorEnabled();
ui::OzonePlatform::InitializeForGPU(params); ui::OzonePlatform::InitializeForGPU(params);
gpu_info_.supported_buffer_formats_for_allocation_and_texturing =
ui::OzonePlatform::GetInstance()
->GetSurfaceFactoryOzone()
->GetSupportedFormatsForTexturing();
#endif #endif
#if BUILDFLAG(ENABLE_VULKAN) #if BUILDFLAG(ENABLE_VULKAN)
...@@ -439,6 +444,10 @@ void GpuInit::InitializeInProcess(base::CommandLine* command_line, ...@@ -439,6 +444,10 @@ void GpuInit::InitializeInProcess(base::CommandLine* command_line,
.requires_mojo; .requires_mojo;
params.viz_display_compositor = features::IsVizDisplayCompositorEnabled(); params.viz_display_compositor = features::IsVizDisplayCompositorEnabled();
ui::OzonePlatform::InitializeForGPU(params); ui::OzonePlatform::InitializeForGPU(params);
gpu_info_.supported_buffer_formats_for_allocation_and_texturing =
ui::OzonePlatform::GetInstance()
->GetSurfaceFactoryOzone()
->GetSupportedFormatsForTexturing();
ui::OzonePlatform::GetInstance()->AfterSandboxEntry(); ui::OzonePlatform::GetInstance()->AfterSandboxEntry();
#endif #endif
bool needs_more_info = true; bool needs_more_info = true;
......
...@@ -17,7 +17,6 @@ source_set("drm") { ...@@ -17,7 +17,6 @@ source_set("drm") {
"//base:base", "//base:base",
"//build/config/linux/libdrm", "//build/config/linux/libdrm",
"//ui/gfx:buffer_types", "//ui/gfx:buffer_types",
"//ui/gfx:memory_buffer",
] ]
} }
......
...@@ -7,7 +7,11 @@ ...@@ -7,7 +7,11 @@
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include "base/logging.h" #include "base/logging.h"
#include "ui/gfx/buffer_format_util.h"
#ifndef DRM_FORMAT_INVALID
// TODO(mcasas): Remove when uprevving //third_party/libdrm.
#define DRM_FORMAT_INVALID 0
#endif
namespace ui { namespace ui {
...@@ -19,6 +23,10 @@ int GetFourCCFormatFromBufferFormat(gfx::BufferFormat format) { ...@@ -19,6 +23,10 @@ int GetFourCCFormatFromBufferFormat(gfx::BufferFormat format) {
return DRM_FORMAT_R16; return DRM_FORMAT_R16;
case gfx::BufferFormat::RG_88: case gfx::BufferFormat::RG_88:
return DRM_FORMAT_GR88; return DRM_FORMAT_GR88;
case gfx::BufferFormat::BGR_565:
return DRM_FORMAT_RGB565;
case gfx::BufferFormat::RGBA_4444:
return DRM_FORMAT_INVALID;
case gfx::BufferFormat::RGBA_8888: case gfx::BufferFormat::RGBA_8888:
return DRM_FORMAT_ABGR8888; return DRM_FORMAT_ABGR8888;
case gfx::BufferFormat::RGBX_8888: case gfx::BufferFormat::RGBX_8888:
...@@ -31,18 +39,16 @@ int GetFourCCFormatFromBufferFormat(gfx::BufferFormat format) { ...@@ -31,18 +39,16 @@ int GetFourCCFormatFromBufferFormat(gfx::BufferFormat format) {
return DRM_FORMAT_XRGB2101010; return DRM_FORMAT_XRGB2101010;
case gfx::BufferFormat::RGBX_1010102: case gfx::BufferFormat::RGBX_1010102:
return DRM_FORMAT_XBGR2101010; return DRM_FORMAT_XBGR2101010;
case gfx::BufferFormat::BGR_565: case gfx::BufferFormat::RGBA_F16:
return DRM_FORMAT_RGB565; return DRM_FORMAT_INVALID;
case gfx::BufferFormat::UYVY_422: case gfx::BufferFormat::UYVY_422:
return DRM_FORMAT_UYVY; return DRM_FORMAT_UYVY;
case gfx::BufferFormat::YVU_420: case gfx::BufferFormat::YVU_420:
return DRM_FORMAT_YVU420; return DRM_FORMAT_YVU420;
case gfx::BufferFormat::YUV_420_BIPLANAR: case gfx::BufferFormat::YUV_420_BIPLANAR:
return DRM_FORMAT_NV12; return DRM_FORMAT_NV12;
default:
NOTREACHED() << gfx::BufferFormatToString(format);
return 0;
} }
return DRM_FORMAT_INVALID;
} }
gfx::BufferFormat GetBufferFormatFromFourCCFormat(int format) { gfx::BufferFormat GetBufferFormatFromFourCCFormat(int format) {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <utility> #include <utility>
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "third_party/khronos/EGL/egl.h" #include "third_party/khronos/EGL/egl.h"
#include "ui/gfx/buffer_format_util.h" #include "ui/gfx/buffer_format_util.h"
...@@ -16,6 +17,7 @@ ...@@ -16,6 +17,7 @@
#include "ui/gl/gl_surface_egl.h" #include "ui/gl/gl_surface_egl.h"
#include "ui/ozone/common/egl_util.h" #include "ui/ozone/common/egl_util.h"
#include "ui/ozone/common/gl_ozone_egl.h" #include "ui/ozone/common/gl_ozone_egl.h"
#include "ui/ozone/common/linux/drm_util_linux.h"
#include "ui/ozone/platform/drm/common/drm_util.h" #include "ui/ozone/platform/drm/common/drm_util.h"
#include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h" #include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h"
#include "ui/ozone/platform/drm/gpu/drm_window_proxy.h" #include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
...@@ -92,6 +94,41 @@ class GLOzoneEGLGbm : public GLOzoneEGL { ...@@ -92,6 +94,41 @@ class GLOzoneEGLGbm : public GLOzoneEGL {
DISALLOW_COPY_AND_ASSIGN(GLOzoneEGLGbm); DISALLOW_COPY_AND_ASSIGN(GLOzoneEGLGbm);
}; };
std::vector<gfx::BufferFormat> EnumerateSupportedBufferFormatsForTexturing() {
std::vector<gfx::BufferFormat> supported_buffer_formats;
// We cannot use FileEnumerator here because the sandbox is already closed.
constexpr char kRenderNodeFilePattern[] = "/dev/dri/renderD%d";
for (int i = 128; /* end on first card# that does not exist */; i++) {
base::FilePath dev_path(FILE_PATH_LITERAL(
base::StringPrintf(kRenderNodeFilePattern, i).c_str()));
base::ThreadRestrictions::ScopedAllowIO scoped_allow_io;
base::File dev_path_file(dev_path,
base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!dev_path_file.IsValid())
break;
gbm_device* device = gbm_create_device(dev_path_file.GetPlatformFile());
if (!device) {
LOG(ERROR) << "Couldn't create Gbm Device at " << dev_path.MaybeAsASCII();
return supported_buffer_formats;
}
for (int i = 0; i <= static_cast<int>(gfx::BufferFormat::LAST); ++i) {
const gfx::BufferFormat buffer_format = static_cast<gfx::BufferFormat>(i);
if (base::ContainsValue(supported_buffer_formats, buffer_format))
continue;
if (gbm_device_is_format_supported(
device, GetFourCCFormatFromBufferFormat(buffer_format),
GBM_BO_USE_TEXTURING)) {
supported_buffer_formats.push_back(buffer_format);
}
}
gbm_device_destroy(device);
}
return supported_buffer_formats;
}
} // namespace } // namespace
GbmSurfaceFactory::GbmSurfaceFactory(DrmThreadProxy* drm_thread_proxy) GbmSurfaceFactory::GbmSurfaceFactory(DrmThreadProxy* drm_thread_proxy)
...@@ -299,4 +336,9 @@ void GbmSurfaceFactory::SetGetProtectedNativePixmapDelegate( ...@@ -299,4 +336,9 @@ void GbmSurfaceFactory::SetGetProtectedNativePixmapDelegate(
get_protected_native_pixmap_callback_ = get_protected_native_pixmap_callback; get_protected_native_pixmap_callback_ = get_protected_native_pixmap_callback;
} }
std::vector<gfx::BufferFormat>
GbmSurfaceFactory::GetSupportedFormatsForTexturing() const {
return EnumerateSupportedBufferFormatsForTexturing();
}
} // namespace ui } // namespace ui
...@@ -74,6 +74,9 @@ class GbmSurfaceFactory : public SurfaceFactoryOzone { ...@@ -74,6 +74,9 @@ class GbmSurfaceFactory : public SurfaceFactoryOzone {
gfx::BufferFormat format, gfx::BufferFormat format,
gfx::NativePixmapHandle handle) override; gfx::NativePixmapHandle handle) override;
std::vector<gfx::BufferFormat> GetSupportedFormatsForTexturing()
const override;
private: private:
scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandleInternal( scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandleInternal(
gfx::AcceleratedWidget widget, gfx::AcceleratedWidget widget,
......
...@@ -100,4 +100,9 @@ void SurfaceFactoryOzone::SetGetProtectedNativePixmapDelegate( ...@@ -100,4 +100,9 @@ void SurfaceFactoryOzone::SetGetProtectedNativePixmapDelegate(
const GetProtectedNativePixmapCallback& const GetProtectedNativePixmapCallback&
get_protected_native_pixmap_callback) {} get_protected_native_pixmap_callback) {}
std::vector<gfx::BufferFormat>
SurfaceFactoryOzone::GetSupportedFormatsForTexturing() const {
return std::vector<gfx::BufferFormat>();
}
} // namespace ui } // namespace ui
...@@ -160,6 +160,13 @@ class OZONE_BASE_EXPORT SurfaceFactoryOzone { ...@@ -160,6 +160,13 @@ class OZONE_BASE_EXPORT SurfaceFactoryOzone {
const GetProtectedNativePixmapCallback& const GetProtectedNativePixmapCallback&
get_protected_native_pixmap_callback); get_protected_native_pixmap_callback);
// Enumerates the BufferFormats that the platform can allocate (and use for
// texturing) via CreateNativePixmap(), or returns empty if those could not be
// retrieved or the platform doesn't know in advance.
// Enumeration should not be assumed to take a trivial amount of time.
virtual std::vector<gfx::BufferFormat> GetSupportedFormatsForTexturing()
const;
protected: protected:
SurfaceFactoryOzone(); SurfaceFactoryOzone();
virtual ~SurfaceFactoryOzone(); virtual ~SurfaceFactoryOzone();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment