diff --git a/AutomatedTesting/Assets/BadAssets/three_same_named_nodes.fbx b/AutomatedTesting/Assets/BadAssets/three_same_named_nodes.fbx new file mode 100644 index 0000000000..8eadb16d86 --- /dev/null +++ b/AutomatedTesting/Assets/BadAssets/three_same_named_nodes.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:45b58009dc2f9340e08cafd5e68f142d15d77e19e7cef142933f2dff3cfb9293 +size 38352 diff --git a/Code/CryEngine/CryCommon/AABBSV.h b/Code/CryEngine/CryCommon/AABBSV.h deleted file mode 100644 index 4c1c277e35..0000000000 --- a/Code/CryEngine/CryCommon/AABBSV.h +++ /dev/null @@ -1,525 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : shadow volume AABB functionality for overlap testings - - -#ifndef CRYINCLUDE_CRYCOMMON_AABBSV_H -#define CRYINCLUDE_CRYCOMMON_AABBSV_H -#pragma once - -#include "Cry_Geo.h" - -struct Shadowvolume -{ - uint32 sideamount; - uint32 nplanes; - - Plane oplanes[10]; -}; - -namespace NAABB_SV -{ - //*************************************************************************************** - //*************************************************************************************** - //*** Calculate a ShadowVolume using an AABB and a point-light *** - //*************************************************************************************** - //*** The planes of the AABB facing away from the point-light are the far-planes *** - //*** of the ShadowVolume. There can be 3-6 far-planes. *** - //*************************************************************************************** - void AABB_ReceiverShadowVolume(const Vec3& PointLight, const AABB& Occluder, Shadowvolume& sv); - - //*************************************************************************************** - //*************************************************************************************** - //*** Calculate a ShadowVolume using an AABB and a point-light *** - //*************************************************************************************** - //*** The planes of the AABB facing the point-light are the near-planes of the *** - //*** the ShadowVolume. There can be 1-3 near-planes. *** - //*** The far-plane is defined by lightrange. *** - //*************************************************************************************** - void AABB_ShadowVolume(const Vec3& PointLight, const AABB& Occluder, Shadowvolume& sv, f32 lightrange); - - //*************************************************************************************** - //*** this is the "fast" version to check if an AABB is overlapping a shadowvolume *** - //*************************************************************************************** - bool Is_AABB_In_ShadowVolume(const Shadowvolume& sv, const AABB& Receiver); - - //*************************************************************************************** - //*** this is the "hierarchical" check *** - //*************************************************************************************** - char Is_AABB_In_ShadowVolume_hierarchical(const Shadowvolume& sv, const AABB& Receiver); -} - - - - - -inline void NAABB_SV::AABB_ReceiverShadowVolume(const Vec3& PointLight, const AABB& Occluder, Shadowvolume& sv) -{ - sv.sideamount = 0; - sv.nplanes = 0; - - //------------------------------------------------------------------------------ - //-- check if PointLight is in front of any occluder plane or inside occluder -- - //------------------------------------------------------------------------------ - uint32 front = 0; - if (PointLight.x < Occluder.min.x) - { - front |= 0x01; - } - if (PointLight.x > Occluder.max.x) - { - front |= 0x02; - } - if (PointLight.y < Occluder.min.y) - { - front |= 0x04; - } - if (PointLight.y > Occluder.max.y) - { - front |= 0x08; - } - if (PointLight.z < Occluder.min.z) - { - front |= 0x10; - } - if (PointLight.z > Occluder.max.z) - { - front |= 0x20; - } - - sv.sideamount = BoxSides[(front << 3) + 7]; - - uint32 back = front ^ 0x3f; - if (back & 0x01) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(-1, +0, +0), Occluder.min); - sv.nplanes++; - } - if (back & 0x02) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(+1, +0, +0), Occluder.max); - sv.nplanes++; - } - if (back & 0x04) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, -1, +0), Occluder.min); - sv.nplanes++; - } - if (back & 0x08) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +1, +0), Occluder.max); - sv.nplanes++; - } - if (back & 0x10) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +0, -1), Occluder.min); - sv.nplanes++; - } - if (back & 0x20) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +0, +1), Occluder.max); - sv.nplanes++; - } - - if (front == 0) - { - return; //light is inside occluder - } - //all 8 vertices of a AABB - Vec3 o[8] = - { - Vec3(Occluder.min.x, Occluder.min.y, Occluder.min.z), - Vec3(Occluder.max.x, Occluder.min.y, Occluder.min.z), - Vec3(Occluder.min.x, Occluder.max.y, Occluder.min.z), - Vec3(Occluder.max.x, Occluder.max.y, Occluder.min.z), - Vec3(Occluder.min.x, Occluder.min.y, Occluder.max.z), - Vec3(Occluder.max.x, Occluder.min.y, Occluder.max.z), - Vec3(Occluder.min.x, Occluder.max.y, Occluder.max.z), - Vec3(Occluder.max.x, Occluder.max.y, Occluder.max.z) - }; - - //--------------------------------------------------------------------- - //--- find the silhouette-vertices of the occluder-AABB --- - //--------------------------------------------------------------------- - uint32 p0 = BoxSides[(front << 3) + 0]; - uint32 p1 = BoxSides[(front << 3) + 1]; - uint32 p2 = BoxSides[(front << 3) + 2]; - uint32 p3 = BoxSides[(front << 3) + 3]; - uint32 p4 = BoxSides[(front << 3) + 4]; - uint32 p5 = BoxSides[(front << 3) + 5]; - - float a; - if (sv.sideamount == 4) - { - //sv.oplanes[sv.nplanes+0] = Plane::CreatePlane( o[p0],o[p1], PointLight ); - //sv.oplanes[sv.nplanes+1] = Plane::CreatePlane( o[p1],o[p2], PointLight ); - //sv.oplanes[sv.nplanes+2] = Plane::CreatePlane( o[p2],o[p3], PointLight ); - //sv.oplanes[sv.nplanes+3] = Plane::CreatePlane( o[p3],o[p0], PointLight ); - sv.sideamount = 0; - a = (o[p1] - o[p0]) | (o[p0] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p0], o[p1], PointLight); - sv.sideamount++; - } - a = (o[p2] - o[p1]) | (o[p1] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p1], o[p2], PointLight); - sv.sideamount++; - } - a = (o[p3] - o[p2]) | (o[p2] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p2], o[p3], PointLight); - sv.sideamount++; - } - a = (o[p0] - o[p3]) | (o[p3] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p3], o[p0], PointLight); - sv.sideamount++; - } - } - - if (sv.sideamount == 6) - { - //sv.oplanes[sv.nplanes+0] = Plane::CreatePlane( o[p0],o[p1], PointLight ); - //sv.oplanes[sv.nplanes+1] = Plane::CreatePlane( o[p1],o[p2], PointLight ); - //sv.oplanes[sv.nplanes+2] = Plane::CreatePlane( o[p2],o[p3], PointLight ); - //sv.oplanes[sv.nplanes+3] = Plane::CreatePlane( o[p3],o[p4], PointLight ); - //sv.oplanes[sv.nplanes+4] = Plane::CreatePlane( o[p4],o[p5], PointLight ); - //sv.oplanes[sv.nplanes+5] = Plane::CreatePlane( o[p5],o[p0], PointLight ); - - sv.sideamount = 0; - a = (o[p1] - o[p0]) | (o[p0] - PointLight); - assert(sv.nplanes + sv.sideamount < 10); - PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p0], o[p1], PointLight); - sv.sideamount++; - } - a = (o[p2] - o[p1]) | (o[p1] - PointLight); - assert(sv.nplanes + sv.sideamount < 10); - PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p1], o[p2], PointLight); - sv.sideamount++; - } - a = (o[p3] - o[p2]) | (o[p2] - PointLight); - assert(sv.nplanes + sv.sideamount < 10); - PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p2], o[p3], PointLight); - sv.sideamount++; - } - a = (o[p4] - o[p3]) | (o[p3] - PointLight); - assert(sv.nplanes + sv.sideamount < 10); - PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p3], o[p4], PointLight); - sv.sideamount++; - } - a = (o[p5] - o[p4]) | (o[p4] - PointLight); - assert(sv.nplanes + sv.sideamount < 10); - PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p4], o[p5], PointLight); - sv.sideamount++; - } - a = (o[p0] - o[p5]) | (o[p5] - PointLight); - assert(sv.nplanes + sv.sideamount < 10); - PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p5], o[p0], PointLight); - sv.sideamount++; - } - } -} - -inline void NAABB_SV::AABB_ShadowVolume(const Vec3& PointLight, const AABB& Occluder, Shadowvolume& sv, f32 lightrange) -{ - sv.sideamount = 0; - sv.nplanes = 0; - - //------------------------------------------------------------------------------ - //-- check if PointLight is in front of any occluder plane or inside occluder -- - //------------------------------------------------------------------------------ - uint32 front = 0; - if (PointLight.x < Occluder.min.x) - { - front |= 0x01; - } - if (PointLight.x > Occluder.max.x) - { - front |= 0x02; - } - if (PointLight.y < Occluder.min.y) - { - front |= 0x04; - } - if (PointLight.y > Occluder.max.y) - { - front |= 0x08; - } - if (PointLight.z < Occluder.min.z) - { - front |= 0x10; - } - if (PointLight.z > Occluder.max.z) - { - front |= 0x20; - } - if (front == 0) - { - return; //light is inside occluder - } - sv.sideamount = BoxSides[(front << 3) + 7]; - - if (front & 0x01) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(-1, +0, +0), Occluder.min); - sv.nplanes++; - } - if (front & 0x02) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(+1, +0, +0), Occluder.max); - sv.nplanes++; - } - if (front & 0x04) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, -1, +0), Occluder.min); - sv.nplanes++; - } - if (front & 0x08) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +1, +0), Occluder.max); - sv.nplanes++; - } - if (front & 0x10) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +0, -1), Occluder.min); - sv.nplanes++; - } - if (front & 0x20) - { - sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +0, +1), Occluder.max); - sv.nplanes++; - } - - //all 8 vertices of a AABB - Vec3 o[8] = - { - Vec3(Occluder.min.x, Occluder.min.y, Occluder.min.z), - Vec3(Occluder.max.x, Occluder.min.y, Occluder.min.z), - Vec3(Occluder.min.x, Occluder.max.y, Occluder.min.z), - Vec3(Occluder.max.x, Occluder.max.y, Occluder.min.z), - Vec3(Occluder.min.x, Occluder.min.y, Occluder.max.z), - Vec3(Occluder.max.x, Occluder.min.y, Occluder.max.z), - Vec3(Occluder.min.x, Occluder.max.y, Occluder.max.z), - Vec3(Occluder.max.x, Occluder.max.y, Occluder.max.z) - }; - - //--------------------------------------------------------------------- - //--- find the silhouette-vertices of the occluder-AABB --- - //--------------------------------------------------------------------- - uint32 p0 = BoxSides[(front << 3) + 0]; - uint32 p1 = BoxSides[(front << 3) + 1]; - uint32 p2 = BoxSides[(front << 3) + 2]; - uint32 p3 = BoxSides[(front << 3) + 3]; - uint32 p4 = BoxSides[(front << 3) + 4]; - uint32 p5 = BoxSides[(front << 3) + 5]; - - //the new center-position in world-space - Vec3 MiddleOfOccluder = (Occluder.max + Occluder.min) * 0.5f; - sv.oplanes[sv.nplanes] = Plane::CreatePlane((MiddleOfOccluder - PointLight).GetNormalized(), (MiddleOfOccluder - PointLight).GetNormalized() * lightrange + PointLight); - sv.nplanes++; - - float a; - if (sv.sideamount == 4) - { - sv.sideamount = 0; - a = (o[p1] - o[p0]) | (o[p0] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p0], o[p1], PointLight); - sv.sideamount++; - } - a = (o[p2] - o[p1]) | (o[p1] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p1], o[p2], PointLight); - sv.sideamount++; - } - a = (o[p3] - o[p2]) | (o[p2] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p2], o[p3], PointLight); - sv.sideamount++; - } - a = (o[p0] - o[p3]) | (o[p3] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p3], o[p0], PointLight); - sv.sideamount++; - } - } - - if (sv.sideamount == 6) - { - sv.sideamount = 0; - a = (o[p1] - o[p0]) | (o[p0] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p0], o[p1], PointLight); - sv.sideamount++; - } - a = (o[p2] - o[p1]) | (o[p1] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p1], o[p2], PointLight); - sv.sideamount++; - } - a = (o[p3] - o[p2]) | (o[p2] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p2], o[p3], PointLight); - sv.sideamount++; - } - a = (o[p4] - o[p3]) | (o[p3] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p3], o[p4], PointLight); - sv.sideamount++; - } - a = (o[p5] - o[p4]) | (o[p4] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p4], o[p5], PointLight); - sv.sideamount++; - } - a = (o[p0] - o[p5]) | (o[p5] - PointLight); - if (a) - { - sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p5], o[p0], PointLight); - sv.sideamount++; - } - } -} - -inline bool NAABB_SV::Is_AABB_In_ShadowVolume(const Shadowvolume& sv, const AABB& Receiver) -{ - uint32 pa = sv.sideamount + sv.nplanes; - - f32 d; - const Vec3* pAABB = &Receiver.min; - - union f32_u - { - float floatVal; - uint32 uintVal; - }; - - //------------------------------------------------------------------------------ - //---- check if receiver-AABB is in front of any of these planes ------ - //------------------------------------------------------------------------------ - for (uint32 x = 0; x < pa; x++) - { - d = sv.oplanes[x].d; - - //avoid breaking strict aliasing rules - f32_u ux; - ux.floatVal = sv.oplanes[x].n.x; - f32_u uy; - uy.floatVal = sv.oplanes[x].n.y; - f32_u uz; - uz.floatVal = sv.oplanes[x].n.z; - const uint32 bitX = ux.uintVal >> 31; - const uint32 bitY = uy.uintVal >> 31; - const uint32 bitZ = uz.uintVal >> 31; - - d += sv.oplanes[x].n.x * pAABB[bitX].x; - d += sv.oplanes[x].n.y * pAABB[bitY].y; - d += sv.oplanes[x].n.z * pAABB[bitZ].z; - if (d > 0) - { - return CULL_EXCLUSION; - } - } - return CULL_OVERLAP; -} - -inline char NAABB_SV::Is_AABB_In_ShadowVolume_hierarchical(const Shadowvolume& sv, const AABB& Receiver) -{ - uint32 pa = sv.sideamount + sv.nplanes; - const Vec3* pAABB = &Receiver.min; - - f32 dot1, dot2; - uint32 notOverlap = 0x80000000; // will be reset to 0 if there's at least one overlapping - - union f32_u - { - float floatVal; - uint32 uintVal; - }; - - //------------------------------------------------------------------------------ - //---- check if receiver-AABB is in front of any of these planes ------ - //------------------------------------------------------------------------------ - for (uint32 x = 0; x < pa; x++) - { - dot1 = dot2 = sv.oplanes[x].d; - - //avoid breaking strict aliasing rules - f32_u ux; - ux.floatVal = sv.oplanes[x].n.x; - f32_u uy; - uy.floatVal = sv.oplanes[x].n.y; - f32_u uz; - uz.floatVal = sv.oplanes[x].n.z; - const uint32 bitX = ux.uintVal >> 31; - const uint32 bitY = uy.uintVal >> 31; - const uint32 bitZ = uz.uintVal >> 31; - - dot1 += sv.oplanes[x].n.x * pAABB[0 + bitX].x; - dot2 += sv.oplanes[x].n.x * pAABB[1 - bitX].x; - dot1 += sv.oplanes[x].n.y * pAABB[0 + bitY].y; - dot2 += sv.oplanes[x].n.y * pAABB[1 - bitY].y; - dot1 += sv.oplanes[x].n.z * pAABB[0 + bitZ].z; - dot2 += sv.oplanes[x].n.z * pAABB[1 - bitZ].z; - PREFAST_SUPPRESS_WARNING(6001) f32_u d; - d.floatVal = dot1; - if (!(d.uintVal & 0x80000000)) - { - return CULL_EXCLUSION; - } - PREFAST_SUPPRESS_WARNING(6001) f32_u d2; - d2.floatVal = dot2; - notOverlap &= d2.uintVal; - } - if (notOverlap) - { - return CULL_INCLUSION; - } - return CULL_OVERLAP; -} - -#endif // CRYINCLUDE_CRYCOMMON_AABBSV_H - diff --git a/Code/CryEngine/CryCommon/Algorithm.h b/Code/CryEngine/CryCommon/Algorithm.h deleted file mode 100644 index 554fe7f507..0000000000 --- a/Code/CryEngine/CryCommon/Algorithm.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#ifndef CRYINCLUDE_CRYCOMMON_ALGORITHM_H -#define CRYINCLUDE_CRYCOMMON_ALGORITHM_H -#pragma once -//short hand for using stl algorithms. same syntax (from users perspective) of c++17 range library. Only the shorthand algorithms from range library(N4128) though. -//Not all algorithms are covered. Add any as you need them. It would be a fair amount of work to add them all, so I'm just adding them as needed. -//Note Android doesn't have non member cbegin and cend yet. - -#include -#include -#include - -namespace std17 -{ - template - void for_each(const Container& con, Callable callable) - { - std::for_each(begin(con), end(con), callable); - } - - template - bool any_of(const Container& con, UnaryPredicate pred) - { - return std::any_of(begin(con), end(con), pred); - } - - template - bool all_of(const Container& con, UnaryPredicate pred) - { - return std::all_of(begin(con), end(con), pred); - } - - template - bool none_of(const Container& con, UnaryPredicate pred) - { - return std::none_of(begin(con), end(con), pred); - } - - template - typename Container::iterator find_if(Container& con, UnaryPredicate pred) - { - return std::find_if(begin(con), end(con), pred); - } - - template - T accumulate(const Container& con, T init) - { - return std::accumulate(begin(con), end(con), init); - } - - template - T accumulate(const Container& con, T init, BinaryOperation binary_op) - { - return std::accumulate(begin(con), end(con), init, binary_op); - } - - template - auto count_if(const Container&con, UnaryPredicate pred)->decltype(std::count_if(begin(con), end(con), pred)) - { - return std::count_if(begin(con), end(con), pred); - } -} - -#endif // CRYINCLUDE_CRYCOMMON_ALGORITHM_H diff --git a/Code/CryEngine/CryCommon/Allocator.h b/Code/CryEngine/CryCommon/Allocator.h deleted file mode 100644 index 682de1e862..0000000000 --- a/Code/CryEngine/CryCommon/Allocator.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_ALLOCATOR_H -#define CRYINCLUDE_CRYCOMMON_ALLOCATOR_H -#pragma once - -#include "CryMemoryAllocator.h" - -//////////////////////////////////////////////////////////////////////// -// Allocator default implementation - -struct StdAllocator -{ - // Class-specific alloc/free/size functions. Use aligned versions only when necessary. - template - static void* Allocate(T*& p) - { - return p = NeedAlign() ? - (T*)CryModuleMemalign(sizeof(T), alignof(T)) : - (T*)CryModuleMalloc(sizeof(T)); - } - - template - static void Deallocate(T* p) - { - if (NeedAlign()) - { - CryModuleMemalignFree(p); - } - else - { - CryModuleFree(p); - } - } - - template - static size_t GetMemSize(const T* p) - { - return NeedAlign() ? - sizeof(T) + alignof(T) : - sizeof(T); - } - - template - void GetMemoryUsage(ICrySizer* pSizer) const { /*nothing*/} -protected: - - template - static bool NeedAlign() - { PREFAST_SUPPRESS_WARNING(6326); return alignof(T) > _ALIGNMENT; } -}; - -// Handy delete template function, for any allocator. -template -void Delete(TAlloc& alloc, T* ptr) -{ - if (ptr) - { - ptr->~T(); - alloc.Deallocate(ptr); - } -} - -#endif // CRYINCLUDE_CRYCOMMON_ALLOCATOR_H diff --git a/Code/CryEngine/CryCommon/CGFContent.h b/Code/CryEngine/CryCommon/CGFContent.h deleted file mode 100644 index 9c6ff391ef..0000000000 --- a/Code/CryEngine/CryCommon/CGFContent.h +++ /dev/null @@ -1,903 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Describe contents on CGF file. - - -#ifndef CRYINCLUDE_CRYCOMMON_CGFCONTENT_H -#define CRYINCLUDE_CRYCOMMON_CGFCONTENT_H -#pragma once - -#include // <> required for Interfuscator -#include // <> required for Interfuscator -#include -#include -#include -#include -#include - -#include //Required for LOD support for touch bending vegetation -#include //Required for LOD support for touch bending vegetation - -const int CGF_NODE_NAME_LENGTH = 64; -//END: Add LOD support for touch bending vegetation - -struct CMaterialCGF; -struct IConvertContext; - -#define CGF_NODE_NAME_LOD_PREFIX "$lod" - -////////////////////////////////////////////////////////////////////////// -// This structure represents CGF node. -////////////////////////////////////////////////////////////////////////// -struct CNodeCGF - : public _cfg_reference_target -{ - enum ENodeType - { - NODE_MESH, - NODE_LIGHT, - NODE_HELPER, - }; - enum EPhysicalizeFlags - { - ePhysicsalizeFlag_MeshNotNeeded = BIT(2), // When set physics data doesn't need additional Mesh indices or vertices. - ePhysicsalizeFlag_NoBreaking = BIT(3), // node is unsuitable for procedural 3d breaking - }; - - ENodeType type; - //START: Add LOD support for touch bending vegetation - char name[CGF_NODE_NAME_LENGTH]; - //END: Add LOD support for touch bending vegetation - string properties; - Matrix34 localTM; // Local space transformation matrix. - Matrix34 worldTM; // World space transformation matrix. - CNodeCGF* pParent; // Pointer to parent node. - CNodeCGF* pSharedMesh; // Not NULL if this node is sharing mesh and physics from referenced Node. - CMesh* pMesh; // Pointer to mesh loaded for this node. (Only when type == NODE_MESH) - - HelperTypes helperType; // Only relevant if type==NODE_HELPER - Vec3 helperSize; // Only relevant if type==NODE_HELPER - - CMaterialCGF* pMaterial; // Material node. - - // Physical data of the node with mesh. - int nPhysicalizeFlags; // Saved into the nFlags2 chunk member. - AZStd::vector physicalGeomData[4]; - int nPhysTriCount; // Not saved! only used for statistics in RC - - ////////////////////////////////////////////////////////////////////////// - // Used internally. - int nChunkId; // Chunk id as loaded from CGF. - int nParentChunkId; // Chunk id of parent Node. - int nObjectChunkId; // Chunk id of the corresponding mesh. - int pos_cont_id; // position controller chunk id - int rot_cont_id; // rotation controller chunk id - int scl_cont_id; // scale controller chunk id - ////////////////////////////////////////////////////////////////////////// - - // True if worldTM is identity. - bool bIdentityMatrix; - // True when this node is invisible physics proxy. - bool bPhysicsProxy; - - // These values are not saved, but are only used for loading empty mesh chunks. - struct MeshInfo - { - int nVerts; - int nIndices; - int nSubsets; - Vec3 bboxMin; - Vec3 bboxMax; - float fGeometricMean; - }; - MeshInfo meshInfo; - - CrySkinVtx* pSkinInfo; // for skinning with skeleton meshes (deformable objects) - - ////////////////////////////////////////////////////////////////////////// - // Constructor. - ////////////////////////////////////////////////////////////////////////// - void Init() - { - type = NODE_MESH; - localTM.SetIdentity(); - worldTM.SetIdentity(); - pParent = 0; - pSharedMesh = 0; - pMesh = 0; - pMaterial = 0; - helperType = HP_POINT; - helperSize.Set(0, 0, 0); - nPhysicalizeFlags = 0; - nChunkId = 0; - nParentChunkId = 0; - nObjectChunkId = 0; - pos_cont_id = rot_cont_id = scl_cont_id = 0; - bIdentityMatrix = true; - bPhysicsProxy = false; - pSkinInfo = 0; - nPhysTriCount = 0; - - ZeroStruct(meshInfo); - } - - CNodeCGF() - { - Init(); - } - - explicit CNodeCGF(_cfg_reference_target::DeleteFncPtr pDeleteFnc) - : _cfg_reference_target(pDeleteFnc) - { - Init(); - } - - ~CNodeCGF() - { - if (!pSharedMesh) - { - delete pMesh; - } - if (pSkinInfo) - { - delete[] pSkinInfo; - } - } -}; - - -////////////////////////////////////////////////////////////////////////// -// structures for skinning -////////////////////////////////////////////////////////////////////////// - -struct TFace -{ - uint16 i0, i1, i2; - TFace() {} - TFace(uint16 v0, uint16 v1, uint16 v2) { i0 = v0; i1 = v1; i2 = v2; } - TFace(const CryFace& face) { i0 = aznumeric_caster(face[0]); i1 = aznumeric_caster(face[1]); i2 = aznumeric_caster(face[2]); } - void operator = (const TFace& f) { i0 = f.i0; i1 = f.i1; i2 = f.i2; } - void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const{} - AUTO_STRUCT_INFO -}; - -struct PhysicalProxy -{ - uint32 ChunkID; - DynArray m_arrPoints; - DynArray m_arrIndices; - DynArray m_arrMaterials; -}; - -struct MorphTargets -{ - uint32 MeshID; - string m_strName; - DynArray m_arrIntMorph; - DynArray m_arrExtMorph; -}; - -typedef MorphTargets* MorphTargetsPtr; - -struct IntSkinVertex -{ - Vec3 __obsolete0; // thin/fat vertex position. must be removed in the next RC refactoring - Vec3 pos; // vertex-position of model.2 - Vec3 __obsolete2; // thin/fat vertex position. must be removed in the next RC refactoring - uint16 boneIDs[4]; - f32 weights[4]; - ColorB color; //index for blend-array - void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const{} - AUTO_STRUCT_INFO -}; - - - -////////////////////////////////////////////////////////////////////////// -// TCB Controller implementation. -////////////////////////////////////////////////////////////////////////// - - -// retrieves the position and orientation (in the logarithmic space, i.e. instead of quaternion, its logarithm is returned) -// may be optimal for motion interpolation -struct PQLog -{ - Vec3 vPos; - Vec3 vRotLog; // logarithm of the rotation - void blendPQ (const PQLog& pqFrom, const PQLog& pqTo, f32 fBlend); - void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const{} -}; - -struct CControllerType -{ - uint16 m_controllertype; - uint16 m_index; - CControllerType() - { - m_controllertype = 0xffff; - m_index = 0xffff; - } -}; - -struct TCBFlags -{ - uint8 f0, f1; - TCBFlags() { f0 = f1 = 0; } -}; - -struct CStoredSkinningInfo -{ - int32 m_nTicksPerFrame; - f32 m_secsPerTick; - int32 m_nStart; - int32 m_nEnd; - f32 m_Speed; - f32 m_Distance; - f32 m_Slope; - int m_nAssetFlags; - f32 m_LHeelStart, m_LHeelEnd; - f32 m_LToe0Start, m_LToe0End; - f32 m_RHeelStart, m_RHeelEnd; - f32 m_RToe0Start, m_RToe0End; - Vec3 m_MoveDirection; // raw storage - - CStoredSkinningInfo() - : m_Speed(-1.0f) - , m_Distance(-1.0f) - , m_nAssetFlags(0) - , m_LHeelStart(-10000.0f) - , m_LHeelEnd(-10000.0f) - , m_LToe0Start(-10000.0f) - , m_LToe0End(-10000.0f) - , m_RHeelStart(-10000.0f) - , m_RHeelEnd(-10000.0f) - , m_RToe0Start(-10000.0f) - , m_RToe0End(-10000.0f) - , m_Slope(-1.0f) - { - } - AUTO_STRUCT_INFO -}; - - - -// structure for recreating controllers -struct CControllerInfo -{ - uint32 m_nControllerID; - uint32 m_nPosKeyTimeTrack; - uint32 m_nPosTrack; - uint32 m_nRotKeyTimeTrack; - uint32 m_nRotTrack; - - CControllerInfo() - : m_nControllerID(~0) - , m_nPosKeyTimeTrack(~0) - , m_nPosTrack(~0) - , m_nRotKeyTimeTrack(~0) - , m_nRotTrack(~0) {} - - AUTO_STRUCT_INFO -}; - -struct MeshCollisionInfo -{ - AABB m_aABB; - OBB m_OBB; - Vec3 m_Pos; - DynArray m_arrIndexes; - int32 m_iBoneId; - - MeshCollisionInfo() - { - // This didn't help much. - // The BBs are reset to opposite infinites, - // but never clamped/grown by any member points. - m_aABB.min.zero(); - m_aABB.max.zero(); - m_OBB.m33.SetIdentity(); - m_OBB.h.zero(); - m_OBB.c.zero(); - m_Pos.zero(); - } - void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(m_arrIndexes); - } -}; - - - -struct SJointsAimIK_Rot -{ - const char* m_strJointName; - int16 m_nJointIdx; - int16 m_nPosIndex; - uint8 m_nPreEvaluate; - uint8 m_nAdditive; - int16 m_nRotJointParentIdx; - SJointsAimIK_Rot() - { - m_strJointName = 0; - m_nJointIdx = -1; - m_nPosIndex = -1; - m_nPreEvaluate = 0; - m_nAdditive = 0; - m_nRotJointParentIdx = -1; - }; - void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const{} -}; - -struct SJointsAimIK_Pos -{ - const char* m_strJointName; - int16 m_nJointIdx; - uint8 m_nAdditive; - uint8 m_nEmpty; - SJointsAimIK_Pos() - { - m_strJointName = 0; - m_nJointIdx = -1; - m_nAdditive = 0; - m_nEmpty = 0; - }; - void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const{} -}; - - -struct DirectionalBlends -{ - string m_AnimToken; - uint32 m_AnimTokenCRC32; - const char* m_strParaJointName; - int16 m_nParaJointIdx; - int16 m_nRotParaJointIdx; - const char* m_strStartJointName; - int16 m_nStartJointIdx; - int16 m_nRotStartJointIdx; - const char* m_strReferenceJointName; - int32 m_nReferenceJointIdx; - DirectionalBlends() - { - m_AnimTokenCRC32 = 0; - m_strParaJointName = 0; - m_nParaJointIdx = -1; - m_nRotParaJointIdx = -1; - m_strStartJointName = 0; - m_nStartJointIdx = -1; - m_nRotStartJointIdx = -1; - m_strReferenceJointName = 0; - m_nReferenceJointIdx = 1; //by default we use the Pelvis - }; - void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const {} -}; - - -struct CSkinningInfo - : public _reference_target_t -{ - DynArray m_arrBonesDesc; //animation-bones - - DynArray m_LookIK_Rot; //rotational joints used for Look-IK - DynArray m_LookIK_Pos; //positional joints used for Look-IK - DynArray m_LookDirBlends; //positional joints used for Look-IK - - DynArray m_AimIK_Rot; //rotational joints used for Aim-IK - DynArray m_AimIK_Pos; //positional joints used for Aim-IK - DynArray m_AimDirBlends; //positional joints used for Aim-IK - - - DynArray m_arrPhyBoneMeshes; //collision proxi - DynArray m_arrMorphTargets; - DynArray m_arrIntFaces; - DynArray m_arrIntVertices; - DynArray m_arrExt2IntMap; - DynArray m_arrBoneEntities; //physical-bones - DynArray m_arrCollisions; - - uint32 m_numChunks{ 0 }; - bool m_bRotatedMorphTargets; - bool m_bProperBBoxes; - - CSkinningInfo() - : m_bRotatedMorphTargets(false) - , m_bProperBBoxes(false) {} - - ~CSkinningInfo() - { - for (DynArray::iterator it = m_arrMorphTargets.begin(), end = m_arrMorphTargets.end(); it != end; ++it) - { - delete *it; - } - } - - int32 GetJointIDByName(const char* strJointName) const - { - uint32 numJoints = m_arrBonesDesc.size(); - for (uint32 i = 0; i < numJoints; i++) - { - if (_stricmp(m_arrBonesDesc[i].m_arrBoneName, strJointName) == 0) - { - return i; - } - } - return -1; - } - - // Return name of bone from bone table, return zero id nId is out of range - const char* GetJointNameByID(int32 nJointID) const - { - int32 numJoints = m_arrBonesDesc.size(); - if (nJointID >= 0 && nJointID < numJoints) - { - return m_arrBonesDesc[nJointID].m_arrBoneName; - } - return ""; // invalid bone id - } -}; - -////////////////////////////////////////////////////////////////////////// -// This structure represents Material inside CGF. -////////////////////////////////////////////////////////////////////////// -struct CMaterialCGF - : public _cfg_reference_target -{ - char name[128]; // Material name; - int nFlags; // Material flags. - int nPhysicalizeType; - bool bOldMaterial; - float shOpacity; - - // Array of sub materials. - DynArray subMaterials; - - ////////////////////////////////////////////////////////////////////////// - // Used internally. - int nChunkId; - ////////////////////////////////////////////////////////////////////////// - - void Init() - { - nFlags = 0; - nChunkId = 0; - bOldMaterial = false; - nPhysicalizeType = PHYS_GEOM_TYPE_DEFAULT; - shOpacity = 1.f; - } - - CMaterialCGF() { Init(); } - - explicit CMaterialCGF(_cfg_reference_target::DeleteFncPtr pDeleteFnc) - : _cfg_reference_target(pDeleteFnc) - { Init(); } -}; - -////////////////////////////////////////////////////////////////////////// -// Info about physicalization of the CGF. -////////////////////////////////////////////////////////////////////////// -struct CPhysicalizeInfoCGF -{ - bool bWeldVertices; - float fWeldTolerance; // Min Distance between vertices when they collapse to single vertex if bWeldVertices enabled. - - // breakable physics - int nGranularity; - int nMode; - - Vec3* pRetVtx; - int nRetVtx; - int* pRetTets; - int nRetTets; - - CPhysicalizeInfoCGF() - : bWeldVertices(true) - , fWeldTolerance(0.01f) - , nMode(-1) - , nGranularity(-1) - , pRetVtx(0) - , nRetVtx(0) - , pRetTets(0) - , nRetTets(0){} - - ~CPhysicalizeInfoCGF() - { - if (pRetVtx) - { - delete []pRetVtx; - pRetVtx = 0; - } - if (pRetTets) - { - delete []pRetTets; - pRetTets = 0; - } - } -}; - - -////////////////////////////////////////////////////////////////////////// -// Serialized skinnable foliage data -////////////////////////////////////////////////////////////////////////// - -#define NODE_PROPERTY_STIFFNESS "stiffness" -#define NODE_PROPERTY_DAMPING "damping" -#define NODE_PROPERTY_THICKNESS "thickness" - -struct SSpineRC -{ - SSpineRC() - : pVtx(nullptr) - , pSegDim(nullptr) - , nVtx(0) - , len(0) - , pBoneIDs(nullptr) - , parentBoneID(-1) - , pStiffness(nullptr) - , pDamping(nullptr) - , pThickness(nullptr) {} - - ~SSpineRC() - { - if (pVtx) - { - delete[] pVtx; - } - if (pSegDim) - { - delete[] pSegDim; - } - if (pBoneIDs) - { - delete[] pBoneIDs; - } - if (pStiffness) - { - delete[] pStiffness; - } - if (pDamping) - { - delete[] pDamping; - } - if (pThickness) - { - delete[] pThickness; - } - } - - /// Add Skinned Geometry (.CGF) export type (for touch bending vegetation) - static float GetDefaultStiffness() { return 0.5f; } - static float GetDefaultDamping() { return 0.5f; } - static float GetDefaultThickness() { return 0.03f; } - - Vec3* pVtx; - Vec4* pSegDim; - int nVtx; - float len; - Vec3 navg; - - int parentBoneID; - int* pBoneIDs; - - //Per Bone parameters. - float* pStiffness; - float* pDamping; - float* pThickness; - - int iAttachSpine; - int iAttachSeg; -}; - -struct SFoliageInfoCGF -{ - SFoliageInfoCGF() { nSpines = 0; pSpines = 0; pBoneMapping = 0; } - ~SFoliageInfoCGF() - { - if (pSpines) - { - for (int i = 1; i < nSpines; i++) // spines 1..n-1 use the same buffer, so make sure they don't delete it - { - pSpines[i].pVtx = nullptr; - pSpines[i].pSegDim = nullptr; - pSpines[i].pBoneIDs = nullptr; - pSpines[i].pStiffness = nullptr; - pSpines[i].pDamping = nullptr; - pSpines[i].pThickness = nullptr; - } - delete[] pSpines; - } - - SAFE_DELETE_ARRAY(pBoneMapping); - - AZStd::unordered_map::iterator iter = boneMappings.begin(); - while (iter != boneMappings.end()) - { - if (iter->second != nullptr) - { - SAFE_DELETE_ARRAY(iter->second->pBoneMapping); - } - iter++; - } - - } - - SSpineRC* pSpines; - int nSpines; - - ///Bone mappings for each LOD level - AZStd::unordered_map boneMappings; - - ///Bone mapping for legacy format - struct SMeshBoneMapping_uint8* pBoneMapping; - int nSkinnedVtx; - - DynArray chunkBoneIds; -}; - - -////////////////////////////////////////////////////////////////////////// -struct CExportInfoCGF -{ - bool bMergeAllNodes; - bool bUseCustomNormals; - bool bCompiledCGF; - bool bHavePhysicsProxy; - bool bHaveAutoLods; - bool bNoMesh; - bool bWantF32Vertices; - bool b8WeightsPerVertex; - - /// Prevent reprocessing skinning data for skinned CGF - bool bSkinnedCGF; - - bool bFromColladaXSI; - bool bFromColladaMAX; - bool bFromColladaMAYA; - - unsigned int rc_version[4]; // Resource compiler version. - char rc_version_string[16]; // Version as a string. - - unsigned int authorToolVersion; -}; - -////////////////////////////////////////////////////////////////////////// -// This class contain all info loaded from the CGF file. -////////////////////////////////////////////////////////////////////////// -class CContentCGF -{ -public: - ////////////////////////////////////////////////////////////////////////// - CContentCGF(const char* filename) - { - azstrcpy(m_filename, AZ_ARRAY_SIZE(m_filename), filename); - memset(&m_exportInfo, 0, sizeof(m_exportInfo)); - m_exportInfo.bMergeAllNodes = true; - m_exportInfo.bUseCustomNormals = false; - m_exportInfo.bWantF32Vertices = false; - m_exportInfo.b8WeightsPerVertex = false; - m_exportInfo.bSkinnedCGF = false; - m_pCommonMaterial = 0; - m_bConsoleFormat = false; - m_pOwnChunkFile = 0; - } - - ////////////////////////////////////////////////////////////////////////// - virtual ~CContentCGF() - { - // Free nodes. - m_nodes.clear(); - if (m_pOwnChunkFile) - { - m_pOwnChunkFile->Release(); - } - } - - ////////////////////////////////////////////////////////////////////////// - const char* GetFilename() const - { - return m_filename; - } - - void SetFilename(const char* filename) - { - azstrcpy(m_filename, AZ_ARRAY_SIZE(m_filename), filename); - } - - ////////////////////////////////////////////////////////////////////////// - // Access to CGF nodes. - void AddNode(CNodeCGF* pNode) - { - m_nodes.push_back(pNode); - } - - int GetNodeCount() const - { - return m_nodes.size(); - } - - CNodeCGF* GetNode(int i) - { - return m_nodes[i]; - } - - const CNodeCGF* GetNode(int i) const - { - return m_nodes[i]; - } - - void ClearNodes() - { - m_nodes.clear(); - } - - void RemoveNode(CNodeCGF* pNode) - { - assert(pNode); - for (int i = 0; i < m_nodes.size(); ++i) - { - if (m_nodes[i] == pNode) - { - pNode->pParent = 0; - m_nodes.erase(i); - break; - } - } - } - ////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - // Access to CGF materials. - void AddMaterial(CMaterialCGF* pNode) - { - m_materials.push_back(pNode); - } - - int GetMaterialCount() const - { - return m_materials.size(); - } - - CMaterialCGF* GetMaterial(int i) - { - return m_materials[i]; - } - - void ClearMaterials() - { - m_materials.clear(); - } - - CMaterialCGF* GetCommonMaterial() const - { - return m_pCommonMaterial; - } - - void SetCommonMaterial(CMaterialCGF* pMtl) - { - m_pCommonMaterial = pMtl; - } - - DynArray& GetUsedMaterialIDs() - { - return m_usedMaterialIds; - } - - const DynArray& GetUsedMaterialIDs() const - { - return m_usedMaterialIds; - } - - ////////////////////////////////////////////////////////////////////////// - - CPhysicalizeInfoCGF* GetPhysicalizeInfo() - { - return &m_physicsInfo; - } - - const CPhysicalizeInfoCGF* GetPhysicalizeInfo() const - { - return &m_physicsInfo; - } - - CExportInfoCGF* GetExportInfo() - { - return &m_exportInfo; - } - - const CExportInfoCGF* GetExportInfo() const - { - return &m_exportInfo; - } - - CSkinningInfo* GetSkinningInfo() - { - return &m_SkinningInfo; - } - - const CSkinningInfo* GetSkinningInfo() const - { - return &m_SkinningInfo; - } - - SFoliageInfoCGF* GetFoliageInfo() - { - return &m_foliageInfo; - } - - bool GetConsoleFormat() - { - return m_bConsoleFormat; - } - - bool ValidateMeshes(const char** const ppErrorDescription) const - { - for (int i = 0; i < m_nodes.size(); ++i) - { - const CNodeCGF* const pNode = m_nodes[i]; - if (pNode && pNode->pMesh && (!pNode->pMesh->Validate(ppErrorDescription))) - { - return false; - } - } - return true; - } - - // Set chunk file that this CGF owns. - void SetChunkFile(IChunkFile* pChunkFile) - { - m_pOwnChunkFile = pChunkFile; - } - -public: - bool m_bConsoleFormat; - -private: - char m_filename[260]; - CSkinningInfo m_SkinningInfo; - DynArray<_smart_ptr > m_nodes; - DynArray<_smart_ptr > m_materials; - DynArray m_usedMaterialIds; - _smart_ptr m_pCommonMaterial; - - CPhysicalizeInfoCGF m_physicsInfo; - CExportInfoCGF m_exportInfo; - SFoliageInfoCGF m_foliageInfo; - - IChunkFile* m_pOwnChunkFile; -}; - -namespace AZ -{ - namespace SceneAPI - { - namespace DataTypes - { - class IAnimationGroup; - } - } -} - -// Asset Writer interface for writing CContentCGF content to asset file -struct IAssetWriter -{ - virtual ~IAssetWriter() - { - } - - virtual bool WriteCGF(CContentCGF* content) = 0; - virtual bool WriteCHR(CContentCGF* content, IConvertContext* convertContext) = 0; - virtual bool WriteSKIN(CContentCGF* content, IConvertContext* convertContext, bool exportMorphTargets) = 0; -}; - - -#endif // CRYINCLUDE_CRYCOMMON_CGFCONTENT_H diff --git a/Code/CryEngine/CryCommon/CGFContent_info.cpp b/Code/CryEngine/CryCommon/CGFContent_info.cpp deleted file mode 100644 index 27d61c2f62..0000000000 --- a/Code/CryEngine/CryCommon/CGFContent_info.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "TypeInfo_impl.h" -#include "CGFContent.h" - -STRUCT_INFO_BEGIN(TFace) -STRUCT_VAR_INFO(i0, TYPE_INFO(uint16)) -STRUCT_VAR_INFO(i1, TYPE_INFO(uint16)) -STRUCT_VAR_INFO(i2, TYPE_INFO(uint16)) -STRUCT_INFO_END(TFace) - -STRUCT_INFO_BEGIN(IntSkinVertex) -STRUCT_VAR_INFO(__obsolete0, TYPE_INFO(Vec3)) -STRUCT_VAR_INFO(pos, TYPE_INFO(Vec3)) -STRUCT_VAR_INFO(__obsolete2, TYPE_INFO(Vec3)) -STRUCT_VAR_INFO(boneIDs, TYPE_ARRAY(4, TYPE_INFO(uint16))) -STRUCT_VAR_INFO(weights, TYPE_ARRAY(4, TYPE_INFO(f32))) -STRUCT_VAR_INFO(color, TYPE_INFO(ColorB)) -STRUCT_INFO_END(IntSkinVertex) - -STRUCT_INFO_BEGIN(CStoredSkinningInfo) -STRUCT_VAR_INFO(m_nTicksPerFrame, TYPE_INFO(int32)) -STRUCT_VAR_INFO(m_secsPerTick, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_nStart, TYPE_INFO(int32)) -STRUCT_VAR_INFO(m_nEnd, TYPE_INFO(int32)) -STRUCT_VAR_INFO(m_Speed, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_Distance, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_Slope, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_nAssetFlags, TYPE_INFO(int)) -STRUCT_VAR_INFO(m_LHeelStart, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_LHeelEnd, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_LToe0Start, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_LToe0End, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_RHeelStart, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_RHeelEnd, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_RToe0Start, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_RToe0End, TYPE_INFO(f32)) -STRUCT_VAR_INFO(m_MoveDirection, TYPE_INFO(Vec3)) -STRUCT_INFO_END(CStoredSkinningInfo) - -STRUCT_INFO_BEGIN(CControllerInfo) -STRUCT_VAR_INFO(m_nControllerID, TYPE_INFO(uint32)) -STRUCT_VAR_INFO(m_nPosKeyTimeTrack, TYPE_INFO(uint32)) -STRUCT_VAR_INFO(m_nPosTrack, TYPE_INFO(uint32)) -STRUCT_VAR_INFO(m_nRotKeyTimeTrack, TYPE_INFO(uint32)) -STRUCT_VAR_INFO(m_nRotTrack, TYPE_INFO(uint32)) -STRUCT_INFO_END(CControllerInfo) - -STRUCT_INFO_BEGIN(UCol) -STRUCT_VAR_INFO(dcolor, TYPE_INFO(uint32)) -STRUCT_INFO_END(UCol) - -STRUCT_INFO_BEGIN(SVF_P3S_C4B_T2S) -STRUCT_VAR_INFO(xyz, TYPE_INFO(Vec3f16)) -STRUCT_VAR_INFO(color, TYPE_INFO(UCol)) -STRUCT_VAR_INFO(st, TYPE_INFO(Vec2f16)) -STRUCT_INFO_END(SVF_P3S_C4B_T2S) diff --git a/Code/CryEngine/CryCommon/CountedValue.h b/Code/CryEngine/CryCommon/CountedValue.h deleted file mode 100644 index 8ff3c5639c..0000000000 --- a/Code/CryEngine/CryCommon/CountedValue.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : A wrapper that counts the number of times the wrapped object -// has been set This is useful for netserializing an object -// that might be given a new value that s the same as the old value - - -#ifndef CRYINCLUDE_CRYCOMMON_COUNTEDVALUE_H -#define CRYINCLUDE_CRYCOMMON_COUNTEDVALUE_H -#pragma once - - -template -struct CountedValue -{ -public: - CountedValue() - : m_lastProducedId(0) - , m_lastConsumedId(0) {} - - typedef uint32 TCountedID; - - void SetAndDirty(const T& value) - { - m_value = value; - ++m_lastProducedId; - CRY_ASSERT(m_lastProducedId > 0); - } - - const T* GetLatestValue() - { - bool bHasNewValue = IsDirty(); // check for dirtiness before updating ids - m_lastConsumedId = m_lastProducedId; - - return bHasNewValue ? &m_value : NULL; - } - - inline bool IsDirty() const - { - return m_lastProducedId != m_lastConsumedId; - } - - const T& Peek() const - { - return m_value; - } - - TCountedID GetLatestID() const - { - return m_lastProducedId; - } - - // This method should only be used to update the object during serialization! - void UpdateDuringSerializationOnly(const T& value, TCountedID lastProducedId) - { - m_value = value; - m_lastProducedId = lastProducedId; - } - -private: - TCountedID m_lastProducedId; - TCountedID m_lastConsumedId; - T m_value; -}; - -#endif // CRYINCLUDE_CRYCOMMON_COUNTEDVALUE_H diff --git a/Code/CryEngine/CryCommon/CrtDebugStats.h b/Code/CryEngine/CryCommon/CrtDebugStats.h deleted file mode 100644 index 6f03d33c18..0000000000 --- a/Code/CryEngine/CryCommon/CrtDebugStats.h +++ /dev/null @@ -1,160 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// support for leak dumping and statistics gathering using vs Crt Debug -// should be included in every DLL below DllMain() -#ifndef CRYINCLUDE_CRYCOMMON_CRTDEBUGSTATS_H -#define CRYINCLUDE_CRYCOMMON_CRTDEBUGSTATS_H -#pragma once - -#ifdef WIN32 -#ifdef _DEBUG - - -#include -#include // CryLogAlways -#include - -// copied from DBGINT.H (not a public header!) - -#define nNoMansLandSize 4 - -typedef struct _CrtMemBlockHeader -{ - struct _CrtMemBlockHeader* pBlockHeaderNext; - struct _CrtMemBlockHeader* pBlockHeaderPrev; - char* szFileName; - int nLine; - size_t nDataSize; - int nBlockUse; - long lRequest; - unsigned char gap[nNoMansLandSize]; - /* followed by: - * unsigned char data[nDataSize]; - * unsigned char anotherGap[nNoMansLandSize]; - */ -} _CrtMemBlockHeader; - -struct SFileInfo -{ - int blocks; - INT_PTR bytes; //AMD Port - SFileInfo(INT_PTR b) { blocks = 1; bytes = b; }; //AMD Port -}; - -_CrtMemState lastcheckpoint; -bool checkpointset = false; - -extern "C" void __declspec(dllexport) CheckPoint() -{ - _CrtMemCheckpoint(&lastcheckpoint); - checkpointset = true; -}; - -bool pairgreater(const std::pair& elem1, const std::pair& elem2) -{ - return elem1.second.bytes > elem2.second.bytes; -} - -extern "C" void __declspec(dllexport) UsageSummary([[maybe_unused]] ILog * log, char* modulename, int* extras) -{ - _CrtMemState state; - - if (checkpointset) - { - _CrtMemState recent; - _CrtMemCheckpoint(&recent); - _CrtMemDifference(&state, &lastcheckpoint, &recent); - } - else - { - _CrtMemCheckpoint(&state); - }; - - INT_PTR numblocks = state.lCounts[_NORMAL_BLOCK]; //AMD Port - INT_PTR totalalloc = state.lSizes[_NORMAL_BLOCK]; //AMD Port - - check_convert(extras[0]) = totalalloc; - check_convert(extras[1]) = numblocks; - - CryLogAlways("$5---------------------------------------------------------------------------------------------------"); - - if (!numblocks) - { - CryLogAlways("$3Module %s has no memory in use", modulename); - return; - } - ; - - CryLogAlways("$5Usage summary for module %s", modulename); - CryLogAlways("%d kbytes (peak %d) in %d objects of %d average bytes\n", - totalalloc / 1024, state.lHighWaterCount / 1024, numblocks, numblocks ? totalalloc / numblocks : 0); - CryLogAlways("%d kbytes allocated over time\n", state.lTotalCount / 1024); - - typedef std::map FileMap; - FileMap fm; - - for (_CrtMemBlockHeader* h = state.pBlockHeader; h; h = h->pBlockHeaderNext) - { - if (_BLOCK_TYPE(h->nBlockUse) != _NORMAL_BLOCK) - { - continue; - } - string s = h->szFileName ? h->szFileName : "NO_SOURCE"; - if (h->nLine > 0) - { - char buf[16]; - sprintf_s(buf, "_%d", h->nLine); - s += buf; - } - FileMap::iterator it = fm.find(s); - if (it != fm.end()) - { - (*it).second.blocks++; - (*it).second.bytes += h->nDataSize; - } - else - { - fm.insert(FileMap::value_type(s, SFileInfo(h->nDataSize))); - }; - } - ; - - typedef std::vector< std::pair > FileVector; - FileVector fv; - for (FileMap::iterator it = fm.begin(); it != fm.end(); ++it) - { - fv.push_back((*it)); - } - std::sort(fv.begin(), fv.end(), pairgreater); - - for (FileVector::iterator it = fv.begin(); it != fv.end(); ++it) - { - CryLogAlways("%6d kbytes / %6d blocks allocated from %s\n", - (*it).second.bytes / 1024, (*it).second.blocks, (*it).first.c_str()); - } - ; -}; - -#endif // _DEBUG - -#if !defined(_RELEASE) && !defined(_DLL) && defined(HANDLE) -extern "C" HANDLE _crtheap; -extern "C" HANDLE __declspec(dllexport) GetDLLHeap() { - return _crtheap; -}; -#endif - -#endif // WIN32 - -#endif // CRYINCLUDE_CRYCOMMON_CRTDEBUGSTATS_H diff --git a/Code/CryEngine/CryCommon/CryArray.h b/Code/CryEngine/CryCommon/CryArray.h index 793201cf40..73a9a9ec38 100644 --- a/Code/CryEngine/CryCommon/CryArray.h +++ b/Code/CryEngine/CryCommon/CryArray.h @@ -15,7 +15,7 @@ #define CRYINCLUDE_CRYCOMMON_CRYARRAY_H #pragma once -#include // <> required for Interfuscator +#include "CryLegacyAllocator.h" //--------------------------------------------------------------------------- // Convenient iteration macros @@ -91,8 +91,6 @@ Public classes: Array StaticArray DynArray - FastDynArray - FixedDynArray StaticDynArray Support classes are placed in namespaces NArray and NAlloc to reduce global name usage. @@ -612,13 +610,6 @@ namespace NAlloc //--------------------------------------------------------------------------- // Allocators for DynArray. - // No reallocation, for use in FixedDynArray - struct NullAlloc - { - static void* alloc(void* pMem, [[maybe_unused]] size_t& nSize, [[maybe_unused]] size_t nAlign, [[maybe_unused]] bool bSlack = false) - { return pMem; } - }; - // Standard CryModule memory allocation, using aligned versions struct ModuleAlloc { @@ -655,128 +646,15 @@ namespace NAlloc // Standard allocator for DynArray stores a compatibility pointer in the memory typedef AllocCompatible StandardAlloc; - - // Allocator using specific heaps - struct GeneralHeapAlloc - : ModuleAlloc - { - IGeneralMemoryHeap* m_pHeap; - - GeneralHeapAlloc() - : m_pHeap(0) {} - - explicit GeneralHeapAlloc(IGeneralMemoryHeap* pHeap) - : m_pHeap(pHeap) {} - - void* alloc(void* pMem, size_t& nSize, size_t nAlign, bool bSlack = false) const - { - if (m_pHeap) - { - if (pMem) - { - if (!nSize) - { - // Dealloc - m_pHeap->Free(pMem); - return 0; - } - } - else if (nSize) - { - // Alloc - if (bSlack) - { - nSize = realloc_size(nSize); - } - return m_pHeap->Memalign(nAlign, nSize, ""); - } - } - - return ModuleAlloc::alloc(pMem, nSize, nAlign, bSlack); - } - }; }; //--------------------------------------------------------------------------- // Storage schemes for dynamic arrays namespace NArray { - /*--------------------------------------------------------------------------- - // STORAGE prototype for DynArray - // Extends ArrayStorage with resizing functionality. - - struct DynStorage - { - struct Store: ArrayStorage::Store - { - I capacity() const; - size_t get_alloc_size() const; - void resize_raw( I new_size, bool allow_slack ); - }; - }; - ---------------------------------------------------------------------------*/ - - //--------------------------------------------------------------------------- - // FastDynStorage: STORAGE scheme for DynArray. - // Simple extension to ArrayStorage: size & capacity fields are inline, 3 words storage, fast access. - - template - struct FastDynStorage - { - template - struct Store - : private A - , public ArrayStorage::Store - { - typedef ArrayStorage::Store super_type; - - using super_type::m_aElems; - using super_type::m_nCount; - - // Construction. - Store() - : m_nCapacity(0) - { - } - - Store(const A& a) - : A(a) - , m_nCapacity(0) - { - } - - I capacity() const - { return m_nCapacity; } - - size_t get_alloc_size() const - { return NAlloc::get_alloc_size(*this, m_aElems, capacity() * sizeof(T), alignof(T)); } - - void resize_raw(I new_size, bool allow_slack = false) - { - if (allow_slack ? new_size > capacity() : new_size != capacity()) - { - m_nCapacity = new_size; - m_aElems = NAlloc::reallocate(static_cast(*this), m_aElems, m_nCount, m_nCapacity, alignof(T), allow_slack); - } - set_size(new_size); - } - - protected: - - I m_nCapacity; - - void set_size(I new_size) - { - assert(new_size >= 0 && new_size <= capacity()); - m_nCount = new_size; - } - }; - }; - //--------------------------------------------------------------------------- // SmallDynStorage: STORAGE scheme for DynArray. // Array is just a single pointer, size and capacity information stored before the array data. - // Slightly slower than FastDynStorage, optimal for saving space, especially when array likely to be empty. template struct SmallDynStorage @@ -1459,35 +1337,6 @@ struct LegacyDynArray } }; - -//--------------------------------------------------------------------------- - -template -struct FastDynArray - : DynArray< T, I, NArray::FastDynStorage > -{ -}; - -template -struct FixedDynArray - : LegacyDynArray< T, I, NArray::FastDynStorage > -{ - typedef NArray::ArrayStorage::Store S; - - void set(void* elems, I mem_size) - { - this->m_aElems = (T*)elems; - this->m_nCapacity = mem_size / sizeof(T); - this->m_nCount = 0; - } - void set(Array array) - { - this->m_aElems = array.begin(); - this->m_nCapacity = array.size(); - this->m_nCount = 0; - } -}; - template struct StaticDynArray : LegacyDynArray< T, I, NArray::StaticDynStorage > diff --git a/Code/CryEngine/CryCommon/CryCustomTypes.h b/Code/CryEngine/CryCommon/CryCustomTypes.h index e8f83145eb..25578ce9cc 100644 --- a/Code/CryEngine/CryCommon/CryCustomTypes.h +++ b/Code/CryEngine/CryCommon/CryCustomTypes.h @@ -1207,23 +1207,4 @@ protected: uint nPrefixLength; }; - -// Define an irregular enum with TypeInfo - -#define DEFINE_ENUM_VALS(EType, TInt, ...) \ - struct EType \ - { \ - enum E { __VA_ARGS__ }; \ - DEFINE_ENUM_VALUE(EType, E, TInt) \ - ILINE static uint Count() { return TypeInfo().Count(); } \ - static const CEnumInfo& TypeInfo() { \ - static char enum_str[] = #__VA_ARGS__; \ - static LegacyDynArray Elems; \ - CEnumDef::SInit::Init(Elems); \ - CEnumDef::SInit __VA_ARGS__; \ - static CEnumInfo info( #EType, Elems, enum_str); \ - return info; \ - } \ - }; - #endif // CRYINCLUDE_CRYCOMMON_CRYCUSTOMTYPES_H diff --git a/Code/CryEngine/CryCommon/CryFixedArray.h b/Code/CryEngine/CryCommon/CryFixedArray.h deleted file mode 100644 index 58bdd2b14f..0000000000 --- a/Code/CryEngine/CryCommon/CryFixedArray.h +++ /dev/null @@ -1,309 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -/* -CryFixedArray.h - - no longer support being created on the stack (since the alignment code was changed to support adding CryFixedArrays into stl::vectors) - - performs construction or destruction only on elements as they become live/dead or are moved around during the RemoveAt() reshuffle - - just a range checked equivelant of a standard array - - for now only allows push_back() population of array - - if using as a class member variable ensure to put the CryFixedArrays after all other member variables at the bottom of your class - to ensure all members stay on the same cacheline -*/ - -#ifndef CRYINCLUDE_CRYCOMMON_CRYFIXEDARRAY_H -#define CRYINCLUDE_CRYCOMMON_CRYFIXEDARRAY_H -#pragma once - -#define DEBUG_CRYFIXED_ARRAY _DEBUG - -template< - unsigned int align > -struct CryFixedArrayDatum -{ -}; - -template<> -struct CryFixedArrayDatum< 4 > -{ - typedef uint32 TDatum; -}; - -template<> -struct CryFixedArrayDatum< 8 > -{ - typedef uint64 TDatum; -}; - -template -class CryFixedArray -{ -protected: - enum - { - ALIGN = MAX(alignof(T), sizeof(unsigned int)) - }; // ALIGN at least sizeof(unsigned int) - - typedef typename CryFixedArrayDatum< ALIGN >::TDatum TDatum; - - uint32 m_curSize[ sizeof (TDatum) / sizeof (uint32) ]; // Padded for alignment - - TDatum m_data[(N * sizeof(T) + (sizeof(TDatum) - 1)) / sizeof(TDatum)]; // simple debugging - in VS: just add to a watch as "(T*)m_data, " to see the array. ie. "(int*)m_data, 5" - the size of the array has to be a literal int - -public: - typedef T* iterator; - typedef const T* const_iterator; - - CryFixedArray() - { -#if DEBUG_CRYFIXED_ARRAY - if (((uintptr_t)m_data & (ALIGN - 1)) != 0) - { - CryLogAlways("CryFixedArray() error - data is not aligned. This may happen if you are creating a CryFixedArray on the stack, which isn't supported."); - } -#endif - CRY_ASSERT_MESSAGE(((uintptr_t)m_data & (ALIGN - 1)) == 0, "CryFixedArray() error - data is not aligned. This may happen if you are creating a CryFixedArray on the stack, which isn't supported."); - m_curSize[0] = 0; - } - - CryFixedArray(const CryFixedArray& other) - { - // doesn't require clear() this is newly constructed - m_curSize[0] = other.m_curSize[0]; - - int size = m_curSize[0]; - for (int i = 0; i < size; i++) - { - T& ele = operator[](i); - const T& otherEle = other.operator[](i); - new (&ele)T(otherEle); // placement new - } - } - - CryFixedArray& operator=(const CryFixedArray& other) - { - if (this != &other) - { - clear(); // necessary to avoid potentially leaking within existing elements - - m_curSize[0] = other.m_curSize[0]; - - int size = m_curSize[0]; - for (int i = 0; i < size; i++) - { - T& ele = operator[](i); - const T& otherEle = other.operator[](i); - //ele = otherEle; // assignment instead of placement new to keep type of operation consistent - this cannot be done until this is rewritten to assign over existing elements and deconstruct any left overs, and placement new any new elements - new (&ele)T(otherEle); // placement new - } - } - - return *this; - } - - virtual ~CryFixedArray() - { - clear(); - } - - ILINE T& at(unsigned int i) - { -#if DEBUG_CRYFIXED_ARRAY - if (i < size()) - { - return alias_cast(m_data)[i]; - } - else - { - // Log is required now as its possible to turn off assert output logging, yet you really want to know if this is happening!!!! - CryLogAlways("CryFixedArray::at(i=%d) failed as i is out of range of curSize=%d (maxSize=%d) - forcing a crash", i, m_curSize[0], N); - CRY_ASSERT_MESSAGE(0, string().Format("CryFixedArray::at(i=%d) failed as i is out of range of curSize=%d (maxSize=%d)", i, m_curSize[0], N)); - abort(); // better option than dereferncing a nullptr? - } -#else - return alias_cast(m_data)[i]; -#endif - } - - ILINE const T& at(unsigned int i) const - { -#if DEBUG_CRYFIXED_ARRAY - if (i < size()) - { - return alias_cast(m_data)[i]; - } - else - { - // Log is required now as its possible to turn off assert output logging, yet you really want to know if this is happening!!!! - CryLogAlways("CryFixedArray::at(i=%d) failed as i is out of range of curSize=%d (maxSize=%d) - forcing a crash", i, m_curSize[0], N); - CRY_ASSERT_MESSAGE(0, string().Format("CryFixedArray::at(i=%d) failed as i is out of range of curSize=%d (maxSize=%d)", i, m_curSize[0], N)); - abort(); // better option than dereferncing a nullptr? - } -#else - return alias_cast(m_data)[i]; -#endif - } - - ILINE const T& operator[](unsigned int i) const - { - return at(i); - } - - ILINE T& operator[](unsigned int i) - { - return at(i); - } - - ILINE void clear() - { - for (uint32 i = 0; i < m_curSize[0]; i++) - { - T& ele = operator[](i); - ele.~T(); - } - m_curSize[0] = 0; -#if DEBUG_CRYFIXED_ARRAY - memset(m_data, 0, N * sizeof(T)); -#endif - } - - ILINE iterator begin() - { - return alias_cast(m_data); - } - ILINE const_iterator begin() const - { - return alias_cast(m_data); - } - ILINE iterator end() - { - return &(alias_cast(m_data))[m_curSize[0]]; - } - ILINE const_iterator end() const - { - return &(alias_cast(m_data))[m_curSize[0]]; - } - - ILINE unsigned int max_size() const { return N; } - ILINE unsigned int size() const { return m_curSize[0]; } - ILINE bool empty() const { return size() == 0; } - ILINE unsigned int isfull() const { return (size() == max_size()); } - - // allows you to push back default constructed elements - ILINE void push_back () - { - unsigned int curSize = size(); - if (curSize < N) - { - T* newT = &(alias_cast(m_data))[curSize]; - new (newT) T(); - - m_curSize[0]++; - } - else - { - CryLogAlways("CryFixedArray::push_back() failing as array of size %u is full - NOT adding element", N); - CRY_ASSERT_TRACE(0, ("CryFixedArray::push_back() failing as array of size %u is full - NOT adding element", N)); - } - } - - ILINE void push_back (const T& ele) - { - unsigned int curSize = size(); - if (curSize < N) - { - T* newT = &(alias_cast(m_data))[curSize]; - new (newT) T(ele); // placement new copy constructor - setup vtable etc - - m_curSize[0]++; - } - else - { - CryLogAlways("CryFixedArray::push_back() failing as array of size %u is full - NOT adding element", N); - CRY_ASSERT_TRACE(0, ("CryFixedArray::push_back() failing as array of size %u is full - NOT adding element", N)); - } - } - - ILINE void pop_back() - { - if (size() > 0) - { - back().~T(); // destruct back - m_curSize[0]--; - } - else - { - CryLogAlways("CryFixedArray::pop_back() failed as array is empty"); - CRY_ASSERT_MESSAGE(0, "CryFixedArray::pop_back() failed as array is empty"); - } - } - -protected: - ILINE const T& backEx() const - { -#if DEBUG_CRYFIXED_ARRAY - if (m_curSize[0] > 0) - { - return (alias_cast(m_data))[m_curSize[0] - 1]; - } - else - { - CryLogAlways("CryFixedArray::back() failed as array is empty"); - CRY_ASSERT_MESSAGE(0, "CryFixedArray::back() failed as array is empty"); - abort(); // better option than dereferncing a nullptr? - } -#else - return (alias_cast(m_data))[m_curSize[0] - 1]; -#endif - } - -public: - ILINE const T& back() const - { - return backEx(); - } - - ILINE T& back() - { - return (T&)(backEx()); - } - - // if returns true then an element has been swapped into the new element[i] and as such may need updating to reflect its new location in memory - ILINE bool removeAt(uint32 i) - { - bool swappedElement = false; - - if (i < m_curSize[0]) - { - if (i != m_curSize[0] - 1) - { - operator[](i).~T(); // destruct element being removed - - // copy back() into element i - T* newT = &(alias_cast(m_data))[i]; - new (newT) T(back()); // placement new copy constructor - setup vtable etc - - swappedElement = true; - } - pop_back(); // will destruct back() - } - else - { - CryLog("CryFixedArray::removeAt() failed as i=%d is out of range of curSize=%d", i, m_curSize[0]); - CRY_ASSERT_MESSAGE(0, string().Format("CryFixedArray::removeAt() failed as i=%d is out of range of curSize=%d", i, m_curSize[0])); - } - return swappedElement; - } -}; - -#endif // CRYINCLUDE_CRYCOMMON_CRYFIXEDARRAY_H diff --git a/Code/CryEngine/CryCommon/CryFixedString.h b/Code/CryEngine/CryCommon/CryFixedString.h index 9c522ad078..cabcc7d06f 100644 --- a/Code/CryEngine/CryCommon/CryFixedString.h +++ b/Code/CryEngine/CryCommon/CryFixedString.h @@ -2019,21 +2019,6 @@ inline CryStackStringT CryStackStringT::Tokenize(const_str charSet, return CryStackStringT(); } -////////////////////////////////////////////////////////////////////////// -// Specialization providing efficient move semantics for array classes. -template -bool raw_movable(const CryStackStringT& str) -{ - return false; -} - -template -void move_init(CryStackStringT& dest, CryStackStringT& source) -{ - dest.move(source); -} - - #if defined(_RELEASE) #define ASSERT_LEN (void)(0) #define ASSERT_WLEN (void)(0) diff --git a/Code/CryEngine/CryCommon/CryMemoryAllocator.h b/Code/CryEngine/CryCommon/CryMemoryAllocator.h deleted file mode 100644 index b9003fc6fa..0000000000 --- a/Code/CryEngine/CryCommon/CryMemoryAllocator.h +++ /dev/null @@ -1,274 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. -/* - * Part of this code coming from STLPort alloc - * - * Copyright (c) 1996,1997 - * Silicon Graphics Computer Systems, Inc. - * - * Copyright (c) 1997 - * Moscow Center for SPARC Technology - * - * Copyright (c) 1999 - * Boris Fomitchev - * - * - */ - -#ifndef CRYINCLUDE_CRYCOMMON_CRYMEMORYALLOCATOR_H -#define CRYINCLUDE_CRYCOMMON_CRYMEMORYALLOCATOR_H -#pragma once - -#include - -#define CRY_STL_ALLOC - -#if defined(LINUX64) || defined(APPLE) -#include -#endif - -#include // memset - -// DON't USE _MAX_BYTES as identifier for Max Bytes, STLPORT defines the same enum -// this leads to situation where the wrong enum is choosen in different compilation units -// which in case leads to errors(The stlport one is defined as 128) -#if defined (__OS400__) || defined (_WIN64) || defined(MAC) || defined(LINUX64) -enum {_ALIGNMENT = 16, _ALIGN_SHIFT = 4, __MAX_BYTES = 512, NFREELISTS=32, ADDRESSSPACE = 2 * 1024 * 1024, ADDRESS_SHIFT = 40}; -#else -enum {_ALIGNMENT = 8, _ALIGN_SHIFT = 3, __MAX_BYTES = 512, NFREELISTS = 64, ADDRESSSPACE = 2 * 1024 * 1024, ADDRESS_SHIFT = 20}; -#endif /* __OS400__ */ - -#define CRY_MEMORY_ALLOCATOR - -#define S_FREELIST_INDEX(__bytes) ((__bytes - size_t(1)) >> (int)_ALIGN_SHIFT) - -class _Node_alloc_obj { -public: - _Node_alloc_obj * _M_next; -}; - -#if defined (_WIN64) || defined(APPLE) || defined(LINUX64) -#define MASK_COUNT 0x000000FFFFFFFFFF -#define MASK_VALUE 0xFFFFFF -#define MASK_NEXT 0xFFFFFFFFFF000000 -#define MASK_SHIFT 24 -#else -#define MASK_COUNT 0x000FFFFF -#define MASK_VALUE 0xFFF -#define MASK_NEXT 0xFFFFF000 -#define MASK_SHIFT 12 -#endif - -#define NUM_OBJ 64 - -struct _Obj_Address { - // short int * _M_next; - // short int - size_t GetNext(size_t pBase) { - return pBase +(size_t)(_M_value >> MASK_SHIFT); - } - - //size_t GetNext() { - // return (size_t)(_M_value >> 20); - //} - - size_t GetCount() { - return _M_value & MASK_VALUE; - } - - void SetNext(/*void **/size_t pNext) { - _M_value &= MASK_COUNT; - _M_value |= (size_t)pNext << MASK_SHIFT; - } - - void SetCount(size_t count) { - _M_value &= MASK_NEXT; - _M_value |= count & MASK_VALUE; - } -private: - size_t _M_value; - // short int * _M_end; -}; - -//struct _Node_Allocations_Tree { -// enum { eListSize = _Size / (sizeof(void *) * _Num_obj); }; -// _Obj_Address * _M_allocations_list[eListSize]; -// int _M_Count; -// _Node_Allocations_Tree * _M_next; -//}; - -template -struct _Node_Allocations_Tree { - //Pointer to the end of the memory block - char *_M_end; - - enum { eListSize = _Size / (sizeof(void *) * NUM_OBJ) }; - // List of allocations - _Obj_Address _M_allocations_list[eListSize]; - int _M_allocations_count; - //Pointer to the next memory block - _Node_Allocations_Tree *_M_Block_next; -}; - - -struct _Node_alloc_Mem_block_Huge { - //Pointer to the end of the memory block - char *_M_end; - // number - int _M_count; - _Node_alloc_Mem_block_Huge *_M_next; -}; - -template -struct _Node_alloc_Mem_block { - //Pointer to the end of the memory block - char *_M_end; - //Pointer to the next memory block - _Node_alloc_Mem_block_Huge *_M_huge_block; - _Node_alloc_Mem_block *_M_next; -}; - - -// Allocators! -enum EAllocFreeType -{ - eCryDefaultMalloc, - eCryMallocCryFreeCRTCleanup, -}; - -template -struct Node_Allocator -{ - inline void * pool_alloc(size_t size) - { - return CryModuleMalloc(size); - }; - inline void * cleanup_alloc(size_t size) - { - return CryCrtMalloc(size); - }; - inline size_t pool_free(void * ptr) - { - CryModuleFree(ptr); - return 0; - }; - inline void cleanup_free(void * ptr) - { - CryCrtFree(ptr); - }; - - inline size_t getSize(void * ptr) - { - return CryCrtSize(ptr); - } -}; - -// partial -template <> -struct Node_Allocator -{ - inline void * pool_alloc(size_t size) - { - return CryCrtMalloc(size); - }; - inline void * cleanup_alloc(size_t size) - { - return CryCrtMalloc(size); - }; - inline size_t pool_free(void * ptr) - { - size_t n = CryCrtSize(ptr); - CryCrtFree(ptr); - return n; - }; - inline void cleanup_free(void * ptr) - { - CryCrtFree(ptr); - }; - inline size_t getSize(void * ptr) - { - return CryCrtSize(ptr); - } - -}; - -// partial -template <> -struct Node_Allocator -{ - inline void * pool_alloc(size_t size) - { - return CryCrtMalloc(size); - }; - inline void * cleanup_alloc(size_t size) - { - return CryCrtMalloc(size); - }; - inline size_t pool_free(void * ptr) - { - return CryCrtFree(ptr); - }; - inline void cleanup_free(void * ptr) - { - CryCrtFree(ptr); - }; - inline size_t getSize(void * ptr) - { - return CryCrtSize(ptr); - } - -}; - -#include "MultiThread.h" - -struct InternalCriticalSectionDummy { - char padding[128]; -} ; - -inline void CryInternalCreateCriticalSection(void * pCS) -{ - CryCreateCriticalSectionInplace(pCS); -} - -// A class that forward node allocator calls directly to CRT -struct cry_crt_node_allocator -{ - static const size_t MaxSize = ~0; - - static void *alloc(size_t __n) - { - return CryCrtMalloc(__n); - } - static size_t dealloc( void *p ) - { - return CryCrtFree(p); - } - static void *allocate(size_t __n) - { - return alloc(__n); - } - static void *allocate(size_t __n, [[maybe_unused]] size_t nAlignment) - { - return alloc(__n); - } - static size_t deallocate(void *__p) - { - return dealloc(__p); - } - void cleanup() {} -}; - - -//#endif // WIN32|DEBUG - -#endif // CRYINCLUDE_CRYCOMMON_CRYMEMORYALLOCATOR_H diff --git a/Code/CryEngine/CryCommon/CryMemoryManager.h b/Code/CryEngine/CryCommon/CryMemoryManager.h deleted file mode 100644 index b3f8ba7c8e..0000000000 --- a/Code/CryEngine/CryCommon/CryMemoryManager.h +++ /dev/null @@ -1,295 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Defines functions for CryEngine custom memory manager. - -#pragma once - -// Section dictionary -#if defined(AZ_RESTRICTED_PLATFORM) -#define CRYMEMORYMANAGER_H_SECTION_TRAITS 1 -#define CRYMEMORYMANAGER_H_SECTION_ALLOCPOLICY 2 -#endif - -#include -// Traits -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYMEMORYMANAGER_H_SECTION_TRAITS - #include AZ_RESTRICTED_FILE(CryMemoryManager_h) -#else -#if !defined(APPLE) -#define CRYMEMORYMANAGER_H_TRAIT_INCLUDE_MALLOC_H 1 -#endif -#if defined(LINUX) || defined(APPLE) -#define CRYMEMORYMANAGER_H_TRAIT_INCLUDE_NEW_NOT_NEW_H 1 -#endif -#if !defined(LINUX) && !defined(APPLE) -#define CRYMEMORYMANAGER_H_TRAIT_INCLUDE_CRTDBG_H 1 -#endif -#if !defined(APPLE) -#define CRYMEMORYMANAGER_H_TRAIT_USE_CRTCHECKMEMORY 1 -#endif -#endif - -#include "platform.h" - -#include -#include - -#if defined(APPLE) || defined(ANDROID) - #include // memalign -#endif // defined(APPLE) - -#ifndef STLALLOCATOR_CLEANUP -#define STLALLOCATOR_CLEANUP -#endif - -#define _CRY_DEFAULT_MALLOC_ALIGNMENT 4 - -#if CRYMEMORYMANAGER_H_TRAIT_INCLUDE_MALLOC_H - #include -#endif - -#if defined(__cplusplus) -#if CRYMEMORYMANAGER_H_TRAIT_INCLUDE_NEW_NOT_NEW_H - #include -#else - #include -#endif -#endif - - #ifdef CRYSYSTEM_EXPORTS - #define CRYMEMORYMANAGER_API DLL_EXPORT - #else - #define CRYMEMORYMANAGER_API DLL_IMPORT - #endif - -#ifdef __cplusplus - -#if defined(_DEBUG) && CRYMEMORYMANAGER_H_TRAIT_INCLUDE_CRTDBG_H - #include -#endif //_DEBUG - -#include "LegacyAllocator.h" - -namespace CryMemory -{ - // checks if the heap is valid in debug; in release, this function shouldn't be called - // returns non-0 if it's valid and 0 if not valid - ILINE int IsHeapValid() - { - #if (defined(_DEBUG) && !defined(RELEASE_RUNTIME) && CRYMEMORYMANAGER_H_TRAIT_USE_CRTCHECKMEMORY) || (defined(DEBUG_MEMORY_MANAGER)) - return _CrtCheckMemory(); - #else - return true; - #endif - } - - inline void* AllocPages(size_t size) - { - const size_t alignment = AZ_PAGE_SIZE; - void* ret = AZ::AllocatorInstance::Get().Allocate(size, alignment, 0, "AllocPages", __FILE__, __LINE__); - return ret; - } - - inline void FreePages(void* p, size_t size) - { - const size_t alignment = AZ_PAGE_SIZE; - AZ::AllocatorInstance::Get().DeAllocate(p, size, alignment); - } -} - -////////////////////////////////////////////////////////////////////////// - -#endif //__cplusplus - -struct ICustomMemoryHeap; -class IGeneralMemoryHeap; -class IPageMappingHeap; -class IMemoryAddressRange; - -// Description: -// Interfaces that allow access to the CryEngine memory manager. -struct IMemoryManager -{ - typedef unsigned char HeapHandle; - enum - { - BAD_HEAP_HANDLE = 0xFF - }; - - struct SProcessMemInfo - { - uint64 PageFaultCount; - uint64 PeakWorkingSetSize; - uint64 WorkingSetSize; - uint64 QuotaPeakPagedPoolUsage; - uint64 QuotaPagedPoolUsage; - uint64 QuotaPeakNonPagedPoolUsage; - uint64 QuotaNonPagedPoolUsage; - uint64 PagefileUsage; - uint64 PeakPagefileUsage; - - uint64 TotalPhysicalMemory; - int64 FreePhysicalMemory; - - uint64 TotalVideoMemory; - int64 FreeVideoMemory; - }; - - enum EAllocPolicy - { - eapDefaultAllocator, - eapPageMapped, - eapCustomAlignment, -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYMEMORYMANAGER_H_SECTION_ALLOCPOLICY - #include AZ_RESTRICTED_FILE(CryMemoryManager_h) -#endif - }; - - virtual ~IMemoryManager(){} - - virtual bool GetProcessMemInfo(SProcessMemInfo& minfo) = 0; - - ////////////////////////////////////////////////////////////////////////// - // Heap Tracing API - virtual HeapHandle TraceDefineHeap(const char* heapName, size_t size, const void* pBase) = 0; - virtual void TraceHeapAlloc(HeapHandle heap, void* mem, size_t size, size_t blockSize, const char* sUsage, const char* sNameHint = 0) = 0; - virtual void TraceHeapFree(HeapHandle heap, void* mem, size_t blockSize) = 0; - virtual void TraceHeapSetColor(uint32 color) = 0; - virtual uint32 TraceHeapGetColor() = 0; - virtual void TraceHeapSetLabel(const char* sLabel) = 0; - ////////////////////////////////////////////////////////////////////////// - - // Create an instance of ICustomMemoryHeap - virtual ICustomMemoryHeap* const CreateCustomMemoryHeapInstance(EAllocPolicy const eAllocPolicy) = 0; - virtual IGeneralMemoryHeap* CreateGeneralExpandingMemoryHeap(size_t upperLimit, size_t reserveSize, const char* sUsage) = 0; - virtual IGeneralMemoryHeap* CreateGeneralMemoryHeap(void* base, size_t sz, const char* sUsage) = 0; - - virtual IMemoryAddressRange* ReserveAddressRange(size_t capacity, const char* sName) = 0; - virtual IPageMappingHeap* CreatePageMappingHeap(size_t addressSpace, const char* sName) = 0; -}; - -// Global function implemented in CryMemoryManager_impl.h -IMemoryManager* CryGetIMemoryManager(); - -// Summary: -// Structure filled by call to CryModuleGetMemoryInfo(). -struct CryModuleMemoryInfo -{ - uint64 requested; - // Total Ammount of memory allocated. - uint64 allocated; - // Total Ammount of memory freed. - uint64 freed; - // Total number of memory allocations. - int num_allocations; - // Allocated in CryString. - uint64 CryString_allocated; - // Allocated in STL. - uint64 STL_allocated; - // Amount of memory wasted in pools in stl (not usefull allocations). - uint64 STL_wasted; -}; - -struct CryReplayInfo -{ - uint64 uncompressedLength; - uint64 writtenLength; - uint32 trackingSize; - const char* filename; -}; - -////////////////////////////////////////////////////////////////////////// -// Extern declarations of globals inside CrySystem. -////////////////////////////////////////////////////////////////////////// -#ifdef __cplusplus -extern "C" { -#endif //__cplusplus - - -void* CryMalloc(size_t size, size_t& allocated, size_t alignment); -void* CryRealloc(void* memblock, size_t size, size_t& allocated, size_t& oldsize, size_t alignment); -size_t CryFree(void* p, size_t alignment); -size_t CryGetMemSize(void* p, size_t size); -int CryStats(char* buf); -void CryFlushAll(); -void CryCleanup(); -int CryGetUsedHeapSize(); -int CryGetWastedHeapSize(); -size_t CrySystemCrtGetUsedSpace(); -CRYMEMORYMANAGER_API void CryGetIMemoryManagerInterface(void** pIMemoryManager); - -#ifdef __cplusplus -} -#endif //__cplusplus - -////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////// -// Cry Memory Manager accessible in all build modes. -////////////////////////////////////////////////////////////////////////// -#if !defined(USING_CRY_MEMORY_MANAGER) -#define USING_CRY_MEMORY_MANAGER -#endif - -#include "CryLegacyAllocator.h" - - -template -inline T* CryAlignedNew(Args&& ... args) -{ - void* pAlignedMemory = CryModuleMemalign(sizeof(T), std::alignment_of::value); - return new(pAlignedMemory) T(std::forward(args) ...); -} - -// This utility function should be used for allocating arrays of objects with specific alignment requirements on the heap. -// Note: The caller must remember the number of items in the array, since CryAlignedDeleteArray needs this information. -template -inline T* CryAlignedNewArray(size_t count) -{ - T* const pAlignedMemory = reinterpret_cast(CryModuleMemalign(sizeof(T) * count, std::alignment_of::value)); - T* pCurrentItem = pAlignedMemory; - for (size_t i = 0; i < count; ++i, ++pCurrentItem) - { - new(static_cast(pCurrentItem))T(); - } - return pAlignedMemory; -} - -// Utility function that frees an object previously allocated with CryAlignedNew. -template -inline void CryAlignedDelete(T* pObject) -{ - if (pObject) - { - pObject->~T(); - CryModuleMemalignFree(pObject); - } -} - -// Utility function that frees an array of objects previously allocated with CryAlignedNewArray. -// The same count used to allocate the array must be passed to this function. -template -inline void CryAlignedDeleteArray(T* pObject, size_t count) -{ - if (pObject) - { - for (size_t i = 0; i < count; ++i) - { - (pObject + i)->~T(); - } - CryModuleMemalignFree(pObject); - } -} diff --git a/Code/CryEngine/CryCommon/CryMemoryManager_impl.h b/Code/CryEngine/CryCommon/CryMemoryManager_impl.h deleted file mode 100644 index fdb4f5665e..0000000000 --- a/Code/CryEngine/CryCommon/CryMemoryManager_impl.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Provides implementation for CryMemoryManager globally defined functions. -// This file included only by platform_impl.cpp, do not include it directly in code! - - -#pragma once - -#ifdef AZ_MONOLITHIC_BUILD - #include // <> required for Interfuscator -#endif // AZ_MONOLITHIC_BUILD - -#include "CryLibrary.h" - -#include - -#define DLL_ENTRY_GETMEMMANAGER "CryGetIMemoryManagerInterface" - -// Resolve IMemoryManager by looking in this DLL, then loading and rummaging through -// CrySystem. Cache the result per DLL, because this is not quick. -IMemoryManager* CryGetIMemoryManager() -{ - static AZ::EnvironmentVariable memMan = nullptr; - if (!memMan) - { - memMan = AZ::Environment::FindVariable("CryIMemoryManagerInterface"); - AZ_Assert(memMan, "Unable to find CryIMemoryManagerInterface via AZ::Environment"); - } - return *memMan; -} diff --git a/Code/CryEngine/CryCommon/CryName.h b/Code/CryEngine/CryCommon/CryName.h index 699525f958..0fb34c9532 100644 --- a/Code/CryEngine/CryCommon/CryName.h +++ b/Code/CryEngine/CryCommon/CryName.h @@ -19,7 +19,6 @@ #include #include #include -#include #include class CNameTable; diff --git a/Code/CryEngine/CryCommon/CrySizer.h b/Code/CryEngine/CryCommon/CrySizer.h index fc45438209..62b1acf489 100644 --- a/Code/CryEngine/CryCommon/CrySizer.h +++ b/Code/CryEngine/CryCommon/CrySizer.h @@ -48,8 +48,6 @@ struct SPipTangents; #include // workaround for Amd64 compiler #endif -#include // <> required for Interfuscator. IResourceCollector - namespace AZ { class Vector3; @@ -335,20 +333,6 @@ public: } } - template - void AddObject(const TArray& rVector) - { - if (!this->AddObject(rVector.begin(), rVector.capacity() * sizeof(T))) - { - return; - } - - for (int i = 0, end = rVector.size(); i < end; ++i) - { - this->AddObject(rVector[i]); - } - } - template void AddObject(const PodArray& rVector) { @@ -427,11 +411,6 @@ public: return AddObject (&rObject, sizeof(T)); } - // used to collect the assets needed for streaming and to gather statistics - // always returns a valid reference - virtual IResourceCollector* GetResourceCollector() = 0; - virtual void SetResourceCollector(IResourceCollector* pColl) = 0; - bool Add (const char* szText) { return AddObject(szText, strlen(szText) + 1); diff --git a/Code/CryEngine/CryCommon/CryThreadSafeRendererContainer.h b/Code/CryEngine/CryCommon/CryThreadSafeRendererContainer.h deleted file mode 100644 index aaf5a0889f..0000000000 --- a/Code/CryEngine/CryCommon/CryThreadSafeRendererContainer.h +++ /dev/null @@ -1,634 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Specialized Container for Renderer data with the following proberties: -// - Created during the 3DEngine Update, comsumed in the renderer in the following frame -// - This Container is very restricted and likely not optimal for other situations - - -#ifndef CRYINCLUDE_CRYCOMMON_CRYTHREADSAFERENDERERCONTAINER_H -#define CRYINCLUDE_CRYCOMMON_CRYTHREADSAFERENDERERCONTAINER_H -#pragma once - - -// This container is specialized for data which is generated in the 3DEngine and consumed by the renderer -// in the following frame due to multithreaded rendering. To be useable by Jobs as well as other Threads -// some very specific desing choices were taken: -// First of the underlying continous memory block is only resized during a call to 'CoalesceMemory' -// to prevent freeing a memory block which could be used by another thread. -// If new memory is requiered, a page of 4 KB is allocated and used as a temp storage till the next -// call to 'CoalesceMemory' which then copies all page memory into one continous block. -// Also all threading relevant functions are implemented LockLess to prevent lock contention and make -// this container useable from Jobs -// -// Right now, the main usage pattern of this container is by the RenderThread, who calls at the beginning -// of its frame 'CoalesceMemory', since then we can be sure that the 3DEngine has finished creating it's elements. -// -// Since the main purpose of this container is multi-threading adding of elements, a slight change was done to the -// push_back interface compared to std::vector: -// All implemented push_back variants can return a pointer into the storage (safe since no memory is freed during adding) -// and a index for this elements. This is done since calling operator[] could be expensive when called before 'CoalesceMemory' -// -// For ease of implementation (and a little bit of speed), this container only supports POD types (which can be copied with memcpy) -// also note that this container only supports push_back (and resize back to 0) and no pop back due cost (performance and code complexity) of supporting lock-free in parallel pop_back -#define TSRC_ALIGN _MS_ALIGN(128) - -template -class TSRC_ALIGN CThreadSafeRendererContainer -{ -public: - CThreadSafeRendererContainer(); - ~CThreadSafeRendererContainer(); - - //NOTE: be aware that these valus can potentially change if some objects are added in parallel - size_t size() const; - size_t empty() const; - size_t capacity() const; - - //NOTE: be aware that this operator can be more expensive if the memory was not coalesced before - T& operator[](size_t n); - const T& operator[](size_t n) const; - - T* push_back_new(); - T* push_back_new(size_t& nIndex); - - void push_back(const T&); - void push_back(const T&, size_t& nIndex); - - // NOTE: These functions are changing the size of the continous memory block and thus are *not* thread-safe - void clear(); - void resize(size_t n); - void reserve(size_t n); - - void CoalesceMemory(); - - void GetMemoryUsage(ICrySizer*) const; - - // disable copy/assignment - CThreadSafeRendererContainer(const CThreadSafeRendererContainer& rOther) = delete; - CThreadSafeRendererContainer& operator=(const CThreadSafeRendererContainer& rOther) = delete; - -private: - - ///////////////////////////////////// - // Struct to represent a memory chunk - // used in fallback allocations during 'Fill' phase - class CMemoryPage - { - public: - // size of a page to allocate, the CMemoryPage is just the header, - // the actual object data is stored in the 4KB chunk right - // after the header (while keeping the requiered alignment and so on) - enum - { - nMemoryPageSize = 4096 - }; - - CMemoryPage(); - - // allocation functions - static CMemoryPage* AllocateNewPage(); - bool TryAllocateElement(size_t& nIndex, T*& pObj); - - // access to the elements - T& GetElement(size_t n); - T* GetData() const; - - // information about the page (NOTE: not thread-safe in all combinations) - size_t Size() const; - size_t Capacity() const; - size_t GetDataSize() const; - - CMemoryPage* m_pNext; // Pointer to next entry in single-linked list of CMemoryPages - - private: - LONG m_nSize; // Number of elements currently in the page - LONG m_nCapacity; // Number of elements which could fit into the page - T* m_arrData; // Element memory, from the same memory chunk right after the CMemoryPage class - }; - - - ///////////////////////////////////// - // Private functions which do the lock-less updating - T* push_back_impl(size_t& nIndex); - bool try_append_to_continous_memory(size_t& nIndex, T*& pObj); - - T& GetMemoryPageElement(size_t n); - - - ///////////////////////////////////// - // Private Member Variables - T* m_arrData; // Storage for the continous memory part, during coalescing resized to hold all page memory - LONG m_nCapacity; // Avaible Memory in continous memory part, if exhausted during 'Fill' phase, pages as temp memory chunks are allocated - - CMemoryPage* m_pMemoryPages; // Single linked list of memory chunks, used for fallback allocations during 'Fill' phase (to prevent changing the continous memory block during 'Fill' - - LONG m_nSize; // Number of elements currently in the container, can be larger than m_nCapacity due the nonContinousPages - - bool m_bElementAccessSafe; // bool to indicate if we are currently doing a 'CoalasceMemory' step, during which some operations are now allowed -} _ALIGN(128); - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - - -/////////////////////////////////////////////////////////////////////////////// -template -inline CThreadSafeRendererContainer::CThreadSafeRendererContainer() - : m_arrData(NULL) - , m_nCapacity(0) - , m_pMemoryPages(NULL) - , m_nSize(0) - , m_bElementAccessSafe(true) -{ -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline CThreadSafeRendererContainer::~CThreadSafeRendererContainer() -{ - clear(); -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeRendererContainer::size() const -{ - return *const_cast(&m_nSize); -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeRendererContainer::empty() const -{ - return *const_cast(&m_nSize) == 0; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeRendererContainer::capacity() const -{ - // capacity of continous memory block - LONG nCapacity = m_nCapacity; - - // add capacity of all memory pages - CMemoryPage* pCurrentMemoryPage = m_pMemoryPages; - while (pCurrentMemoryPage) - { - nCapacity += pCurrentMemoryPage->Capacity(); - pCurrentMemoryPage = pCurrentMemoryPage->m_pNext; - } - - return nCapacity; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline T& CThreadSafeRendererContainer::operator[](size_t n) -{ - assert(m_bElementAccessSafe); - T* pRet = NULL; - -#if !defined(NULL_RENDERER) - assert((LONG)n < m_nSize); -#endif - if ((LONG)n < m_nCapacity) - { - pRet = &m_arrData[n]; - } - else - { - pRet = &GetMemoryPageElement(n); - } - return *pRet; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline const T& CThreadSafeRendererContainer::operator[](size_t n) const -{ - return const_cast(const_cast*>(this)->operator[](n)); -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline T* CThreadSafeRendererContainer::push_back_new() -{ - assert(m_bElementAccessSafe); - size_t nUnused = ~0; - return push_back_impl(nUnused); -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline T* CThreadSafeRendererContainer::push_back_new(size_t& nIndex) -{ - assert(m_bElementAccessSafe); - return push_back_impl(nIndex); -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeRendererContainer::push_back(const T& rObj) -{ - assert(m_bElementAccessSafe); - size_t nUnused = ~0; - T* pObj = push_back_impl(nUnused); - *pObj = rObj; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeRendererContainer::push_back(const T& rObj, size_t& nIndex) -{ - assert(m_bElementAccessSafe); - T* pObj = push_back_impl(nIndex); - *pObj = rObj; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeRendererContainer::clear() -{ - assert(m_bElementAccessSafe); - // free continous part - CryModuleMemalignFree(m_arrData); - m_arrData = NULL; - - // free non-continous pages if we have some - CMemoryPage* pCurrentMemoryPage = m_pMemoryPages; - while (pCurrentMemoryPage) - { - CMemoryPage* pOldPage = pCurrentMemoryPage; - pCurrentMemoryPage = pCurrentMemoryPage->m_pNext; - CryModuleFree(pOldPage); - } - m_pMemoryPages = NULL; - - m_nSize = 0; - m_nCapacity = 0; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeRendererContainer::resize(size_t n) -{ - assert(m_bElementAccessSafe); - CoalesceMemory(); - size_t nOldSize = m_nSize; - m_nSize = n; - - if ((LONG)n <= m_nCapacity) - { - return; - } - - T* arrOldData = m_arrData; - m_arrData = reinterpret_cast(CryModuleMemalign(n * sizeof(T), alignof(T))); - memcpy(m_arrData, arrOldData, nOldSize * sizeof(T)); - memset(&m_arrData[m_nCapacity], 0, (n - m_nCapacity) * sizeof(T)); - CryModuleMemalignFree(arrOldData); - - m_nCapacity = n; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeRendererContainer::reserve(size_t n) -{ - assert(m_bElementAccessSafe); - CoalesceMemory(); - if ((LONG)n <= m_nCapacity) - { - return; - } - - T* arrOldData = m_arrData; - m_arrData = reinterpret_cast(CryModuleMemalign(n * sizeof(T), alignof(T))); - memcpy(m_arrData, arrOldData, m_nSize * sizeof(T)); - memset(&m_arrData[m_nCapacity], 0, (n - m_nCapacity) * sizeof(T)); - CryModuleMemalignFree(arrOldData); - - m_nCapacity = n; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline bool CThreadSafeRendererContainer::try_append_to_continous_memory(size_t& nIndex, T*& pObj) -{ - assert(m_bElementAccessSafe); - LONG nSize = ~0; - LONG nCapacity = ~0; - do - { - // read volatile the new size - nSize = *const_cast(&m_nSize); - nCapacity = *const_cast(&m_nCapacity); - - if (nSize >= nCapacity) - { - return false; - } - } while (CryInterlockedCompareExchange(alias_cast(&m_nSize), nSize + 1, nSize) != nSize); - nIndex = nSize; - pObj = &m_arrData[nSize]; - - return true; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline T* CThreadSafeRendererContainer::push_back_impl(size_t& nIndex) -{ - assert(m_bElementAccessSafe); - T* pObj = NULL; - - // non atomic check to see if there is space in the continous array - if (try_append_to_continous_memory(nIndex, pObj)) - { - return pObj; - } - - // exhausted continous memory, falling back to page allocation - for (;; ) - { - assert(m_bElementAccessSafe); - size_t nPageBaseIndex = 0; - - // traverse the page list till the first page with free memory - CMemoryPage* pCurrentMemoryPage = m_pMemoryPages; - while (pCurrentMemoryPage) - { - size_t nAvaibleElements = pCurrentMemoryPage->Capacity() - pCurrentMemoryPage->Size(); - if (nAvaibleElements) - { - break; - } - - // no memory in this page, go to the next one - nPageBaseIndex += pCurrentMemoryPage->Capacity(); - pCurrentMemoryPage = pCurrentMemoryPage->m_pNext; - } - - // try to allocate a element on this page - if (pCurrentMemoryPage && pCurrentMemoryPage->TryAllocateElement(nIndex, pObj)) - { - // update global elements counter - CryInterlockedIncrement(alias_cast(&m_nSize)); - - // adjust in-page-index to global index - nIndex += nPageBaseIndex + m_nCapacity; - return pObj; - } - else - { - // all pages are empty, allocate and link a new one - CMemoryPage* pNewPage = CMemoryPage::AllocateNewPage(); - - void* volatile* ppLastMemoryPageAddress = NULL; - do - { - // find place to link in page - CMemoryPage* pLastMemoryPage = m_pMemoryPages; - ppLastMemoryPageAddress = alias_cast(&m_pMemoryPages); - - while (pLastMemoryPage) - { - ppLastMemoryPageAddress = alias_cast(&(pLastMemoryPage->m_pNext)); - pLastMemoryPage = pLastMemoryPage->m_pNext; - } - } while (CryInterlockedCompareExchangePointer(ppLastMemoryPageAddress, pNewPage, NULL) != NULL); - } - } -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline T& CThreadSafeRendererContainer::GetMemoryPageElement(size_t n) -{ - assert(m_bElementAccessSafe); - size_t nFirstListIndex = m_nCapacity; - CMemoryPage* pCurrentMemoryPage = m_pMemoryPages; - - size_t nPageCapacity = pCurrentMemoryPage->Capacity(); - while (n >= (nFirstListIndex + nPageCapacity)) - { - // this is threadsafe because we assume that if we want to get element 'n' - // the clientcode did already fill the container up to element 'n' - // thus up to 'n', m_pNonContinousList will have valid pages - // NOTE: This is not safe when trying to read a element behind the valid - // range (same as std::vector) - nFirstListIndex += nPageCapacity; - pCurrentMemoryPage = pCurrentMemoryPage->m_pNext; - - // update page capacity, since it can differe due alignment - nPageCapacity = pCurrentMemoryPage->Capacity(); - } - - return pCurrentMemoryPage->GetElement(n - nFirstListIndex); -} - -/////////////////////////////////////////////////////////////////////////////// -// When not not in the 'Fill' phase, it is safe to colace all page entries into one continous memory block -template -inline void CThreadSafeRendererContainer::CoalesceMemory() -{ - assert(m_bElementAccessSafe); - if (m_pMemoryPages == NULL) - { - return; // nothing to do - } - // mark state as not accessable - m_bElementAccessSafe = false; - -#if !defined(NDEBUG) - size_t nOldSize = m_nSize; -#endif - - // compute required memory - size_t nRequieredElements = 0; - { - CMemoryPage* pCurrentMemoryPage = m_pMemoryPages; - while (pCurrentMemoryPage) - { - nRequieredElements += pCurrentMemoryPage->Size(); - pCurrentMemoryPage = pCurrentMemoryPage->m_pNext; - } - } - - T* arrOldData = m_arrData; - m_arrData = reinterpret_cast(CryModuleMemalign((m_nCapacity + nRequieredElements) * sizeof(T), alignof(T))); - memcpy(m_arrData, arrOldData, m_nCapacity * sizeof(T)); - CryModuleMemalignFree(arrOldData); - - // copy page data into continous memory block - { - size_t nBeginToFillIndex = m_nCapacity; - CMemoryPage* pCurrentMemoryPage = m_pMemoryPages; - while (pCurrentMemoryPage) - { - // copy data - memcpy(&m_arrData[nBeginToFillIndex], pCurrentMemoryPage->GetData(), pCurrentMemoryPage->GetDataSize()); - nBeginToFillIndex += pCurrentMemoryPage->Size(); - - // free page - CMemoryPage* pOldPage = pCurrentMemoryPage; - pCurrentMemoryPage = pCurrentMemoryPage->m_pNext; - CryModuleFree(pOldPage); - } - - m_pMemoryPages = NULL; - } - - assert(nOldSize == m_nSize); - m_nCapacity += nRequieredElements; - - // the container can be used again - m_bElementAccessSafe = true; -} - -/////////////////////////////////////////////////////////////////////////////// -// Collect information about used memory -template -void CThreadSafeRendererContainer::GetMemoryUsage(ICrySizer* pSizer) const -{ - pSizer->AddObject(m_arrData, m_nCapacity * sizeof(T)); - - CMemoryPage* pCurrentMemoryPage = m_pMemoryPages; - while (pCurrentMemoryPage) - { - pSizer->AddObject(pCurrentMemoryPage, CMemoryPage::nMemoryPageSize); - pCurrentMemoryPage = pCurrentMemoryPage->m_pNext; - } -} - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -template -inline CThreadSafeRendererContainer::CMemoryPage::CMemoryPage() - : m_pNext(NULL) - , m_nSize(0) -{ - // compute offset for actual data - size_t nObjectAlignment = alignof(T); - UINT_PTR nMemoryBlockBegin = alias_cast(this); - UINT_PTR nMemoryBlockEnd = alias_cast(this) + nMemoryPageSize; - - nMemoryBlockBegin += sizeof(CMemoryPage); - nMemoryBlockBegin = (nMemoryBlockBegin + nObjectAlignment - 1) & ~(nObjectAlignment - 1); - - // compute number of avaible elements - assert(nMemoryBlockEnd > nMemoryBlockBegin); - m_nCapacity = (LONG)((nMemoryBlockEnd - nMemoryBlockBegin) / sizeof(T)); - - // store pointer to store data to - m_arrData = alias_cast(nMemoryBlockBegin); -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline typename CThreadSafeRendererContainer::CMemoryPage * CThreadSafeRendererContainer::CMemoryPage::AllocateNewPage() -{ - void* pNewPageMemoryChunk = CryModuleMalloc(nMemoryPageSize); - assert(pNewPageMemoryChunk != NULL); - - memset(pNewPageMemoryChunk, 0, nMemoryPageSize); - CMemoryPage* pNewPage = new(pNewPageMemoryChunk) CMemoryPage(); - return pNewPage; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline bool CThreadSafeRendererContainer::CMemoryPage::TryAllocateElement(size_t & nIndex, T * &pObj) -{ - LONG nSize = ~0; - LONG nCapacity = ~0; - do - { - // read volatile the new size - nSize = *const_cast(&m_nSize); - nCapacity = *const_cast(&m_nCapacity); - // stop trying if this page is full - if (nSize >= nCapacity) - { - return false; - } - } while (CryInterlockedCompareExchange(alias_cast(&m_nSize), nSize + 1, nSize) != nSize); - - //Note: this is the index in the page and it is adjusted in the calling context - nIndex = nSize; - pObj = &m_arrData[nSize]; - - return true; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline T&CThreadSafeRendererContainer::CMemoryPage::GetElement(size_t n) -{ - assert((LONG)n < m_nSize); - assert(m_nSize <= m_nCapacity); - return m_arrData[n]; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline T * CThreadSafeRendererContainer::CMemoryPage::GetData() const -{ - return m_arrData; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeRendererContainer::CMemoryPage::Size() const -{ - return m_nSize; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeRendererContainer::CMemoryPage::GetDataSize() const -{ - return m_nSize * sizeof(T); -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeRendererContainer::CMemoryPage::Capacity() const -{ - return m_nCapacity; -} - -#endif // CRYINCLUDE_CRYCOMMON_CRYTHREADSAFERENDERERCONTAINER_H diff --git a/Code/CryEngine/CryCommon/CryThreadSafeWorkerContainer.h b/Code/CryEngine/CryCommon/CryThreadSafeWorkerContainer.h deleted file mode 100644 index 418b363ca1..0000000000 --- a/Code/CryEngine/CryCommon/CryThreadSafeWorkerContainer.h +++ /dev/null @@ -1,602 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Specialized Container for Renderer data with the following properties: -// Created during the 3DEngine Update, consumed in the renderer in the following frame -// This Container is very restricted and likely not optimal for other situations - - -#ifndef CRYINCLUDE_CRYCOMMON_CRYTHREADSAFEWORKERCONTAINER_H -#define CRYINCLUDE_CRYCOMMON_CRYTHREADSAFEWORKERCONTAINER_H -#pragma once - - -#include "platform.h" -#include - -#include -#include -#include - - -// -// !!! BE CAREFULL WHEN USING THIS CONTAINER !!! -// -// --- Properties: --- -// - Stores data local to worker thread to avoid thread-safety semantics -// - Allows for a single non-worker thread to be tracked which is stored in m_workers[0] -// Hence: As m_workers[0] is shared between all non-worker threads, ensure that only one additional non-worker thread may access this container e.g. MainThread -// - Coalesce memory to obtain a continues memory block -// - Coalesce memory to for faster element access to a continues memory block -// -// --- Restrictions:--- -// - The workers own the memory structure -// - The coalesced memory stores a copy of the workers used memory -// Hence: Be careful when altering data within the coalesced memory. -// If the templated element is a pointer type than altering the memory pointed to, is not be an issue -// If the templated element is of type class or struct than ensure that data changes are done on the worker local data and not on the coalesced memory. Use worker encoded indices to do so. -// - -template -class CThreadSafeWorkerContainer -{ -public: - struct SDefaultNoOpFunctor - { - ILINE void operator()(T* pData) const{} - }; - - struct SDefaultDestructorFunctor - { - ILINE void operator()(T* pData) const - { - pData->~T(); - } - }; - -public: - CThreadSafeWorkerContainer(); - ~CThreadSafeWorkerContainer(); - - void Init(); - void SetNonWorkerThreadID(threadID nThreadId) { m_foreignThreadId = nThreadId; } - - // Safe access of elements for calling thread via operator[] - uint32 ConvertToEncodedWorkerId_threadlocal(uint32 nIndex) const; - - // Returns the number of threads that can use this container, including the one non-worker-thread. - uint32 GetNumWorkers() const; - - // Returns the Worker ID for the current thread. Ranges from 0 to GetNumWorkers()-1. - // Note, WorkerId is not the same thing as JobManager's WorkerThreadId. - uint32 GetWorkerId_threadlocal() const; - - //NOTE: be aware that these values can potentially change if some objects are added in parallel - size_t size() const; - size_t empty() const; - size_t capacity() const; - - size_t size_threadlocal() const; - size_t empty_threadlocal() const; - size_t capacity_threadlocal() const; - - //NOTE: be aware that this operator is more expensive if the memory was not coalesced before - T& operator[](size_t n); - const T& operator[](size_t n) const; - - T* push_back_new(); - T* push_back_new(size_t& nIndex); - - void push_back(const T& rObj); - void push_back(const T& rObj, size_t& nIndex); - - // NOTE: These functions are changing the size of the continous memory block and thus are *not* thread-safe - void clear(); - template< class OnElementDeleteFunctor> - void clear(const OnElementDeleteFunctor& rFunctor = CThreadSafeWorkerContainer::SDefaultNoOpFunctor()); - void erase(const T& rObj); - void resize(size_t n); - void reserve(size_t n); - - // *not* thread-safe functions - void PrefillContainer(T* pElement, size_t numElements); - void CoalesceMemory(); - - void GetMemoryUsage(ICrySizer* pSizer) const; - -private: - - void clear(AZStd::true_type); - void clear(AZStd::false_type); - - class SWorker - { - public: - AZ_CLASS_ALLOCATOR(SWorker, AZ::LegacyAllocator, 0); - - SWorker() - : m_dataSize(0) {} - - uint32 m_dataSize; - AZStd::vector m_data; - } _ALIGN(128); - - T* push_back_impl(size_t& nIndex); - void ReserverCoalescedMemory(size_t n); - - threadID m_foreignThreadId; // OS thread ID of the non-job-manager-worker-thread allowed to use this container, too. - - AZStd::vector m_workers; // Holds data for each thread that can use this container. A non-worker-thread (Main) has data stored at 0. Actual worker threads range from 1 to m_nNumWorkers-1 - uint32 m_nNumWorkers = 0; // The number of threads that can use this container, including one non-worker-thread. - - uint32 m_coalescedArrCapacity; - T* m_coalescedArr; - bool m_isCoalesced; -}; - -/////////////////////////////////////////////////////////////////////////////// -template -inline CThreadSafeWorkerContainer::CThreadSafeWorkerContainer() - : m_nNumWorkers(0) - , m_coalescedArrCapacity(0) - , m_coalescedArr(0) - , m_isCoalesced(false) -{ -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline CThreadSafeWorkerContainer::~CThreadSafeWorkerContainer() -{ - clear(); - m_workers.clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::Init() -{ - m_nNumWorkers = AZ::JobContext::GetGlobalContext()->GetJobManager().GetNumWorkerThreads() + 1; - m_workers.resize(m_nNumWorkers); - - m_foreignThreadId = THREADID_NULL; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeWorkerContainer::size() const -{ - uint32 totalSize = 0; - for (int i = 0; i < m_nNumWorkers; ++i) - { - totalSize += m_workers[i].m_dataSize; - } - return totalSize; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeWorkerContainer::empty() const -{ - return size() == 0; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeWorkerContainer::capacity() const -{ - uint32 totalCapacity = 0; - for (int i = 0; i < m_nNumWorkers; ++i) - { - totalCapacity += m_workers[i].m_data.capacity(); - } - return totalCapacity; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeWorkerContainer::size_threadlocal() const -{ - const uint32 nWorkerThreadId = GetWorkerId_threadlocal(); - return m_workers[nWorkerThreadId].m_dataSize; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeWorkerContainer::empty_threadlocal() const -{ - const uint32 nWorkerThreadId = GetWorkerId_threadlocal(); - return m_workers[nWorkerThreadId].m_data.empty(); -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline size_t CThreadSafeWorkerContainer::capacity_threadlocal() const -{ - const uint32 nWorkerThreadId = GetWorkerId_threadlocal(); - return m_workers[nWorkerThreadId].m_data.capacity(); -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline T& CThreadSafeWorkerContainer::operator[](size_t n) -{ - const uint32 nHasWorkerEncodedIndex = (n & 0x80000000) >> 31; - - IF ((m_isCoalesced && !nHasWorkerEncodedIndex), 1) - { - AZ_Assert(m_coalescedArr, "null array"); - AZ_Assert(n < m_coalescedArrCapacity, "Index out of bounds"); - return m_coalescedArr[n]; - } - else - { - const uint32 nWorkerThreadId = (n & 0x7F00007F) >> 24; // Mask bit 24-30 (0 is starting bit) - const uint32 nOffset = (n & ~0xFF000000); // Mask out top 8 bits - - // Encoded offset into worker local array - if (nHasWorkerEncodedIndex) - { - return m_workers[nWorkerThreadId].m_data[nOffset]; - } - else // None-coalesced and none worker encoded offset - { - uint32 nTotalOffset = nOffset; - for (int i = 0; i < m_nNumWorkers; ++i) - { - SWorker& worker = m_workers[i]; - - if (nTotalOffset < worker.m_dataSize) - { - return worker.m_data[nTotalOffset]; - } - else - { - nTotalOffset -= worker.m_dataSize; - } - } - - // Out of bound access detected! - CRY_ASSERT_MESSAGE(false, "CThreadSafeWorkerContainer::operator[] - Out of bounds access"); - __debugbreak(); - AZ_Assert(m_coalescedArr, "null array"); - AZ_Assert(m_coalescedArrCapacity > 0, "Index out of bounds"); - return m_coalescedArr[0]; - } - } -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline const T& CThreadSafeWorkerContainer::operator[](size_t n) const -{ - return const_cast(const_cast*>(this)->operator[](n)); -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline T* CThreadSafeWorkerContainer::push_back_new() -{ - size_t unused = ~0; - return push_back_impl(unused); -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline T* CThreadSafeWorkerContainer::push_back_new(size_t& nIndex) -{ - return push_back_impl(nIndex); -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::push_back(const T& rObj) -{ - size_t nUnused = ~0; - T* pObj = push_back_impl(nUnused); - *pObj = rObj; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::push_back(const T& rObj, size_t& nIndex) -{ - T* pObj = push_back_impl(nIndex); - *pObj = rObj; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::clear() -{ - clear(typename std::is_destructible::type()); -} - -template -void CThreadSafeWorkerContainer::clear(AZStd::true_type) -{ - clear(SDefaultDestructorFunctor()); -} - -template -void CThreadSafeWorkerContainer::clear(AZStd::false_type) -{ - clear(SDefaultNoOpFunctor()); -} -/////////////////////////////////////////////////////////////////////////////// -template -template -inline void CThreadSafeWorkerContainer::clear(const OnElementDeleteFunctor& rFunctor) -{ - // Reset worker data - for (int i = 0; i < m_nNumWorkers; ++i) - { - // Delete elements - uint32 nSize = m_workers[i].m_data.size(); - for (int j = 0; j < nSize; ++j) - { - // Call on element delete functor - // Note: Default functor will do nothing with the element - rFunctor(&m_workers[i].m_data[j]); - } - - m_workers[i].m_data.clear(); - m_workers[i].m_dataSize = 0; - } - - // Reset container data - if (m_coalescedArr) - { - CryModuleMemalignFree(m_coalescedArr); - } - - m_coalescedArr = 0; - m_coalescedArrCapacity = 0; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::erase(const T& rObj) -{ - for (int i = 0; i < m_nNumWorkers; ++i) - { - typename std::vector::iterator iter = m_workers[i].m_data.begin(); - typename std::vector::iterator iterEnd = m_workers[i].m_data.end(); - - for (; iter != iterEnd; ++iter) - { - if (rObj == *iter) - { - m_workers[i].m_data.erase(iter); - --m_workers[i].m_dataSize; - m_isCoalesced = false; - return; - } - } - } -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::resize(size_t n) -{ - CoalesceMemory(); - - uint32 nSizePerWorker = n / m_nNumWorkers; - uint32 nExcessSize = n % m_nNumWorkers; - - // Resize workers evenly - for (int i = 0; i < m_nNumWorkers; ++i) - { - uint32 nWorkerSize = nSizePerWorker + nExcessSize; - - if (nWorkerSize > m_workers[i].m_data.size()) - { - m_workers[i].m_data.resize(nWorkerSize); - } - - m_workers[i].m_dataSize = nWorkerSize; - nExcessSize = 0; // First worker creates excess items - } - - ReserverCoalescedMemory(n); -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::reserve(size_t n) -{ - CoalesceMemory(); - - uint32 nSizePerWorker = n / m_nNumWorkers; - uint32 nExcessSize = n % m_nNumWorkers; - - // Resize workers evenly - for (int i = 0; i < m_nNumWorkers; ++i) - { - uint32 nWorkerSize = nSizePerWorker + nExcessSize; - - if (nWorkerSize > m_workers[i].m_data.size()) - { - m_workers[i].m_data.resize(nWorkerSize); - } - - nExcessSize = 0; // First worker creates excess items - } - - ReserverCoalescedMemory(n); -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::PrefillContainer(T* pElement, size_t numElements) -{ - reserve(numElements); - - uint32 nOffset = 0; - uint32 nNumItemPerWorker = numElements / m_nNumWorkers; - uint32 nNumExcessItems = numElements % m_nNumWorkers; - - // Store items evenly in workers - for (int i = 0; i < m_nNumWorkers; ++i) - { - uint32 nNumItems = nNumItemPerWorker + nNumExcessItems; - for (int j = 0; j < nNumItems; ++j) - { - m_workers[i].m_data[j] = pElement[nOffset + j]; - } - - m_workers[i].m_dataSize = nNumItems; - nOffset += nNumItems; - nNumExcessItems = 0; // First worker stores excess items - } - - m_isCoalesced = false; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::CoalesceMemory() -{ - if (m_isCoalesced) - { - return; - } - - // Ensure enough memory exists - uint32 minSizeNeeded = 0; - for (int i = 0; i < m_nNumWorkers; ++i) - { - minSizeNeeded += m_workers[i].m_dataSize; - } - - IF (minSizeNeeded >= m_coalescedArrCapacity, 0) - { - ReserverCoalescedMemory(minSizeNeeded + (minSizeNeeded / 4)); - } - - // Copy data to coalesced array - uint32 nOffest = 0; - for (int i = 0; i < m_nNumWorkers; ++i) - { - SWorker& rWorker = m_workers[i]; - if (rWorker.m_dataSize == 0) - { - continue; - } - AZ_Assert((nOffest + rWorker.m_dataSize) <= m_coalescedArrCapacity, "Index out of bounds"); - memcpy(m_coalescedArr + nOffest, &rWorker.m_data[0], sizeof(T) * rWorker.m_dataSize); - nOffest += rWorker.m_dataSize; - } - - m_isCoalesced = true; -} - -/////////////////////////////////////////////////////////////////////////////// -template -uint32 CThreadSafeWorkerContainer::ConvertToEncodedWorkerId_threadlocal(uint32 nIndex) const -{ - const uint32 workerId = GetWorkerId_threadlocal(); - assert(nIndex < m_workers[workerId].m_dataSize); - return (uint32)((1 << 31) | (workerId << 24) | nIndex); -} - -////////////////////////////////////////////////////////////////////////// -template -uint32 CThreadSafeWorkerContainer::GetNumWorkers() const -{ - return m_nNumWorkers; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::GetMemoryUsage(ICrySizer* pSizer) const -{ - pSizer->AddObject(m_coalescedArr, m_coalescedArrCapacity * sizeof(T)); - - for (int i = 0; i < m_nNumWorkers; ++i) - { - pSizer->AddContainer(m_workers[i].m_data); - } -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline void CThreadSafeWorkerContainer::ReserverCoalescedMemory(size_t n) -{ - if (n <= m_coalescedArrCapacity) - { - return; - } - - T* arrOldData = m_coalescedArr; - m_coalescedArr = reinterpret_cast(CryModuleMemalign(n * sizeof(T), alignof(T))); - memcpy(m_coalescedArr, arrOldData, m_coalescedArrCapacity * sizeof(T)); - if (arrOldData) - { - CryModuleMemalignFree(arrOldData); - } - m_coalescedArrCapacity = n; -} - -/////////////////////////////////////////////////////////////////////////////// -template -inline T* CThreadSafeWorkerContainer::push_back_impl(size_t& nIndex) -{ - // Avoid writing to thread share resource and take hit of 'if statement to avoid false-sharing between threads - IF (m_isCoalesced, 0) - { - m_isCoalesced = false; - } - - // Get worker id - const uint32 nWorkerThreadId = GetWorkerId_threadlocal(); - - SWorker& activeWorker = m_workers[nWorkerThreadId]; - - // Ensure enough space - if (activeWorker.m_dataSize >= activeWorker.m_data.size()) - { - activeWorker.m_data.resize(activeWorker.m_data.size() + (activeWorker.m_data.size() / 2) + 1); - } - - // Encode worker local offset into index and return - T* retItem = &activeWorker.m_data[activeWorker.m_dataSize]; - nIndex = (size_t)((1 << 31) | (nWorkerThreadId << 24) | activeWorker.m_dataSize); - ++activeWorker.m_dataSize; - return retItem; -} - -template -uint32 CThreadSafeWorkerContainer::GetWorkerId_threadlocal() const -{ - const uint32 workerThreadId = AZ::JobContext::GetGlobalContext()->GetJobManager().GetWorkerThreadId(); - - if (workerThreadId == AZ::JobManager::InvalidWorkerThreadId) - { - // Only one non-worker thread is allowed, so check to see if this is that thread. - - const threadID currentThreadId = CryGetCurrentThreadId(); - if (m_foreignThreadId != currentThreadId) - { - CryFatalError("Trying to access CThreadSafeWorkerContainer from an unspecified non-worker thread. The only non-worker threadId with access rights: %" PRI_THREADID ". Current threadId: %" PRI_THREADID, m_foreignThreadId, currentThreadId); - } - } - - // Non-worker has id of ~0 ... add +1 to shift to 0. Worker0 will use slot 1 etc. - static_assert(AZ::JobManager::InvalidWorkerThreadId == ~0u, "Assumptions about InvalidWorkerId no longer hold true"); - return workerThreadId + 1; -} - - -#endif // CRYINCLUDE_CRYCOMMON_CRYTHREADSAFEWORKERCONTAINER_H diff --git a/Code/CryEngine/CryCommon/CustomMemoryHeap.h b/Code/CryEngine/CryCommon/CustomMemoryHeap.h deleted file mode 100644 index 2cb0c70713..0000000000 --- a/Code/CryEngine/CryCommon/CustomMemoryHeap.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef __CustomMemoryHeap_h__ -#define __CustomMemoryHeap_h__ -#pragma once - -#include "IMemory.h" - -class CCustomMemoryHeap; - -////////////////////////////////////////////////////////////////////////// -class CCustomMemoryHeapBlock - : public ICustomMemoryBlock -{ -public: - CCustomMemoryHeapBlock(CCustomMemoryHeap* pHeap); - virtual ~CCustomMemoryHeapBlock(); - - ////////////////////////////////////////////////////////////////////////// - // IMemoryBlock - ////////////////////////////////////////////////////////////////////////// - virtual void* GetData(); - virtual int GetSize() { return m_nSize; } - ////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - // ICustomMemoryBlock - ////////////////////////////////////////////////////////////////////////// - virtual void CopyMemoryRegion(void* pOutputBuffer, size_t nOffset, size_t nSize); - ////////////////////////////////////////////////////////////////////////// - -private: - friend class CCustomMemoryHeap; - CCustomMemoryHeap* m_pHeap; - string m_sUsage; - void* m_pData; - uint32 m_nGPUHandle; - size_t m_nSize; -}; - -////////////////////////////////////////////////////////////////////////// -class CCustomMemoryHeap - : public ICustomMemoryHeap -{ -public: - - explicit CCustomMemoryHeap(IMemoryManager::EAllocPolicy const eAllocPolicy); - ~CCustomMemoryHeap(); - - ////////////////////////////////////////////////////////////////////////// - // ICustomMemoryHeap - ////////////////////////////////////////////////////////////////////////// - virtual ICustomMemoryBlock* AllocateBlock(size_t const nAllocateSize, char const* const sUsage, size_t const nAlignment = 16); - virtual void GetMemoryUsage(ICrySizer* pSizer); - virtual size_t GetAllocated(); - ////////////////////////////////////////////////////////////////////////// - - void DeallocateBlock(CCustomMemoryHeapBlock* pBlock); - -private: - - friend class CCustomMemoryHeapBlock; - int m_nAllocatedSize; - IMemoryManager::EAllocPolicy m_eAllocPolicy; - IMemoryManager::HeapHandle m_nTraceHeapHandle; -}; - -#endif // __CustomMemoryHeap_h__ diff --git a/Code/CryEngine/CryCommon/HeapAllocator.h b/Code/CryEngine/CryCommon/HeapAllocator.h index c0001ea497..4dfd9f66ec 100644 --- a/Code/CryEngine/CryCommon/HeapAllocator.h +++ b/Code/CryEngine/CryCommon/HeapAllocator.h @@ -420,7 +420,6 @@ namespace stl { nInterval++; nCount = 0; - assert(CryMemory::IsHeapValid()); } #endif } diff --git a/Code/CryEngine/CryCommon/IEntityRenderState.h b/Code/CryEngine/CryCommon/IEntityRenderState.h index 29b1bdc463..3e8f1dce4e 100644 --- a/Code/CryEngine/CryCommon/IEntityRenderState.h +++ b/Code/CryEngine/CryCommon/IEntityRenderState.h @@ -572,7 +572,6 @@ struct IVoxelObject : public IRenderNode { // - virtual struct IMemoryBlock* GetCompiledData(EEndian eEndian) = 0; virtual void SetCompiledData(void* pData, int nSize, uint8 ucChildId, EEndian eEndian) = 0; virtual void SetObjectName(const char* pName) = 0; virtual void SetMatrix(const Matrix34& mat) = 0; diff --git a/Code/CryEngine/CryCommon/IFont.h b/Code/CryEngine/CryCommon/IFont.h index 2706c350a3..7e2a3480b1 100644 --- a/Code/CryEngine/CryCommon/IFont.h +++ b/Code/CryEngine/CryCommon/IFont.h @@ -145,6 +145,7 @@ struct STextDrawContext Vec2 m_size; Vec2i m_requestSize; float m_widthScale; + float m_lineSpacing; float m_clipX; float m_clipY; @@ -175,6 +176,7 @@ struct STextDrawContext , m_size(16.0f, 16.0f) , m_requestSize(static_cast(m_size.x), static_cast(m_size.y)) , m_widthScale(1.0f) + , m_lineSpacing(0.f) , m_clipX(0) , m_clipY(0) , m_clipWidth(0) @@ -209,11 +211,13 @@ struct STextDrawContext void SetTransform(const Matrix34& transform) { m_transform = transform; } void SetBaseState(int baseState) { m_baseState = baseState; } void SetOverrideViewProjMatrices(bool overrideViewProjMatrices) { m_overrideViewProjMatrices = overrideViewProjMatrices; } + void SetLineSpacing(float lineSpacing) { m_lineSpacing = lineSpacing; } float GetCharWidth() const { return m_size.x; } float GetCharHeight() const { return m_size.y; } float GetCharWidthScale() const { return m_widthScale; } int GetFlags() const { return m_drawTextFlags; } + float GetLineSpacing() const { return m_lineSpacing; } bool IsColorOverridden() const { return m_colorOverride.a != 0; } }; diff --git a/Code/CryEngine/CryCommon/IGeneralMemoryHeap.h b/Code/CryEngine/CryCommon/IGeneralMemoryHeap.h deleted file mode 100644 index 7a9c0c8ebf..0000000000 --- a/Code/CryEngine/CryCommon/IGeneralMemoryHeap.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_IGENERALMEMORYHEAP_H -#define CRYINCLUDE_CRYCOMMON_IGENERALMEMORYHEAP_H -#pragma once - -namespace AZ -{ - class IAllocator; -} - -class IGeneralMemoryHeap -{ -public: - // - virtual bool Cleanup() = 0; - - virtual int AddRef() = 0; - virtual int Release() = 0; - - virtual bool IsInAddressRange(void* ptr) const = 0; - - virtual void* Calloc(size_t nmemb, size_t size, const char* sUsage) = 0; - virtual void* Malloc(size_t sz, const char* sUsage) = 0; - - // Attempts to free the allocation. Returns the size of the allocation if successful, 0 if the heap doesn't own the address. - virtual size_t Free(void* ptr) = 0; - virtual void* Realloc(void* ptr, size_t sz, const char* sUsage) = 0; - virtual void* ReallocAlign(void* ptr, size_t size, size_t alignment, const char* sUsage) = 0; - virtual void* Memalign(size_t boundary, size_t size, const char* sUsage) = 0; - - virtual AZ::IAllocator* GetAllocator() const = 0; - - // Get the size of the allocation. Returns 0 if the ptr doesn't belong to the heap. - virtual size_t UsableSize(void* ptr) const = 0; - // -protected: - virtual ~IGeneralMemoryHeap() {} -}; - -#endif // CRYINCLUDE_CRYCOMMON_IGENERALMEMORYHEAP_H diff --git a/Code/CryEngine/CryCommon/IImageHandler.h b/Code/CryEngine/CryCommon/IImageHandler.h deleted file mode 100644 index 3f2e0c871b..0000000000 --- a/Code/CryEngine/CryCommon/IImageHandler.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#ifndef CRYINCLUDE_CRYCOMMON_IIMAGEHANDLER_H -#define CRYINCLUDE_CRYCOMMON_IIMAGEHANDLER_H -#pragma once - -#include - -/** -Utility for loading and saving images. only works with RGB data(no alpha), and lossless compressed tiff files for now. -*/ -struct IImageHandler -{ - struct IImage - { - virtual ~IImage() {} - - virtual const std::vector& GetData() const = 0; - virtual int GetWidth() const = 0; - virtual int GetHeight() const = 0; - }; - - virtual ~IImageHandler() {} - - ///data must be RGB, 3 bytes per pixel. - virtual std::unique_ptr CreateImage(std::vector&& data, int width, int height) const = 0; - virtual std::unique_ptr LoadImage(const char* filename) const = 0; - virtual bool SaveImage(IImage* image, const char* filename) const = 0; - virtual std::unique_ptr CreateDiffImage(IImage* image1, IImage* image2) const = 0; - virtual float CalculatePSNR(IImage* diffIimage) const = 0; -}; -#endif // CRYINCLUDE_CRYCOMMON_IIMAGEHANDLER_H diff --git a/Code/CryEngine/CryCommon/ILZ4Decompressor.h b/Code/CryEngine/CryCommon/ILZ4Decompressor.h deleted file mode 100644 index c136a7518d..0000000000 --- a/Code/CryEngine/CryCommon/ILZ4Decompressor.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Provides the interface for the lz4 hc decompress wrapper - -#ifndef CRYINCLUDE_CRYCOMMON_ILZ4DECOMPRESSOR_H -#define CRYINCLUDE_CRYCOMMON_ILZ4DECOMPRESSOR_H -#pragma once - - -struct ILZ4Decompressor -{ -protected: - virtual ~ILZ4Decompressor() {}; // use Release() - -public: - virtual bool DecompressData(const char* pIn, char* pOut, const uint outputSize) const = 0; - - virtual void Release() = 0; -}; - -#endif // CRYINCLUDE_CRYCOMMON_ILZ4DECOMPRESSOR_H diff --git a/Code/CryEngine/CryCommon/IMemory.h b/Code/CryEngine/CryCommon/IMemory.h deleted file mode 100644 index a3b1dc1c2c..0000000000 --- a/Code/CryEngine/CryCommon/IMemory.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_IMEMORY_H -#define CRYINCLUDE_CRYCOMMON_IMEMORY_H -#pragma once - -#include -#include // <> required for Interfuscator -#include - -struct IMemoryBlock - : public CMultiThreadRefCount -{ - // - virtual void* GetData() = 0; - virtual int GetSize() = 0; - // -}; -TYPEDEF_AUTOPTR(IMemoryBlock); - -////////////////////////////////////////////////////////////////////////// -struct ICustomMemoryBlock - : public IMemoryBlock -{ - // Copy region from from source memory to the specified output buffer - virtual void CopyMemoryRegion(void* pOutputBuffer, size_t nOffset, size_t nSize) = 0; -}; - -////////////////////////////////////////////////////////////////////////// -struct ICustomMemoryHeap - : public CMultiThreadRefCount -{ - // - virtual ICustomMemoryBlock* AllocateBlock(size_t const nAllocateSize, char const* const sUsage, size_t const nAlignment = 16) = 0; - virtual void GetMemoryUsage(ICrySizer* pSizer) = 0; - virtual size_t GetAllocated() = 0; - // -}; - -class IMemoryAddressRange -{ -public: - // - virtual void Release() = 0; - - virtual char* GetBaseAddress() const = 0; - virtual size_t GetPageCount() const = 0; - virtual size_t GetPageSize() const = 0; - - virtual void* MapPage(size_t pageIdx) = 0; - virtual void UnmapPage(size_t pageIdx) = 0; - // -protected: - virtual ~IMemoryAddressRange() {} -}; - -class IPageMappingHeap -{ -public: - // - virtual void Release() = 0; - - virtual size_t GetGranularity() const = 0; - virtual bool IsInAddressRange(void* ptr) const = 0; - - virtual size_t FindLargestFreeBlockSize() const = 0; - - virtual void* Map(size_t sz) = 0; - virtual void Unmap(void* ptr, size_t sz) = 0; - // -protected: - virtual ~IPageMappingHeap() {} -}; - -#endif // CRYINCLUDE_CRYCOMMON_IMEMORY_H diff --git a/Code/CryEngine/CryCommon/IRenderer.h b/Code/CryEngine/CryCommon/IRenderer.h index bb8f8fa572..be72e69864 100644 --- a/Code/CryEngine/CryCommon/IRenderer.h +++ b/Code/CryEngine/CryCommon/IRenderer.h @@ -1510,7 +1510,6 @@ struct IRenderer // Summary: // Loads lightmap for name. virtual int EF_LoadLightmap (const char* name) = 0; - virtual bool EF_RenderEnvironmentCubeHDR (int size, Vec3& Pos, TArray& vecData) = 0; // Summary: // Starts using of the shaders (return first index for allow recursions). @@ -1547,7 +1546,6 @@ struct IRenderer virtual int EF_AddDeferredLight(const CDLight& pLight, float fMult, const SRenderingPassInfo& passInfo, const SRendItemSorter& rendItemSorter) = 0; virtual uint32 EF_GetDeferredLightsNum(eDeferredLightType eLightType = eDLT_DeferredLight) = 0; virtual void EF_ClearDeferredLightsList() = 0; - virtual TArray* EF_GetDeferredLights(const SRenderingPassInfo& passInfo, eDeferredLightType eLightType = eDLT_DeferredLight) = 0; virtual uint8 EF_AddDeferredClipVolume(const IClipVolume* pClipVolume) = 0; virtual bool EF_SetDeferredClipVolumeBlendData(const IClipVolume* pClipVolume, const SClipVolumeBlendInfo& blendInfo) = 0; diff --git a/Code/CryEngine/CryCommon/IResourceCollector.h b/Code/CryEngine/CryCommon/IResourceCollector.h deleted file mode 100644 index a3c88f507b..0000000000 --- a/Code/CryEngine/CryCommon/IResourceCollector.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_IRESOURCECOLLECTOR_H -#define CRYINCLUDE_CRYCOMMON_IRESOURCECOLLECTOR_H -#pragma once - - -// used to collect the assets needed for streaming and to gather statistics -struct IResourceCollector -{ - // - // Arguments: - // dwMemSize 0xffffffff if size is unknown - // Returns: - // true=new resource was added, false=resource was already registered - virtual bool AddResource(const char* szFileName, const uint32 dwMemSize) = 0; - - // Arguments: - // szFileName - needs to be registered before with AddResource() - // pInstance - must not be 0 - virtual void AddInstance(const char* szFileName, void* pInstance) = 0; - // - // Arguments: - // szFileName - needs to be registered before with AddResource() - virtual void OpenDependencies(const char* szFileName) = 0; - // - virtual void CloseDependencies() = 0; - - // Resets the internal data structure for the resource collector. - virtual void Reset() = 0; - // -protected: - virtual ~IResourceCollector() {} -}; - - -class NullResCollector - : public IResourceCollector -{ -public: - virtual bool AddResource([[maybe_unused]] const char* szFileName, [[maybe_unused]] const uint32 dwMemSize) { return true; } - virtual void AddInstance([[maybe_unused]] const char* szFileName, [[maybe_unused]] void* pInstance) {} - virtual void OpenDependencies([[maybe_unused]] const char* szFileName) {} - virtual void CloseDependencies() {} - virtual void Reset() {} - - virtual ~NullResCollector() {} -}; - - -#endif // CRYINCLUDE_CRYCOMMON_IRESOURCECOLLECTOR_H - - diff --git a/Code/CryEngine/CryCommon/IResourceManager.h b/Code/CryEngine/CryCommon/IResourceManager.h deleted file mode 100644 index 482cb30a5e..0000000000 --- a/Code/CryEngine/CryCommon/IResourceManager.h +++ /dev/null @@ -1,84 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Interface to the Resource Manager - - -#ifndef CRYINCLUDE_CRYCOMMON_IRESOURCEMANAGER_H -#define CRYINCLUDE_CRYCOMMON_IRESOURCEMANAGER_H -#pragma once - -namespace AZ::IO -{ - struct IResourceList; -} - -struct SLayerPakStats -{ - struct SEntry - { - string name; - size_t nSize; - string status; - bool bStreaming; - }; - typedef std::vector TEntries; - TEntries m_entries; - - size_t m_MaxSize; - size_t m_UsedSize; -}; - -////////////////////////////////////////////////////////////////////////// -// IResource manager interface -////////////////////////////////////////////////////////////////////////// -struct IResourceManager -{ - // - virtual ~IResourceManager(){} - // Called by level system to set the level folder - virtual void PrepareLevel(const char* sLevelFolder, const char* sLevelName) = 0; - // Called by level system after the level has been unloaded. - virtual void UnloadLevel() = 0; - // Call to get current level resource list. - virtual AZ::IO::IResourceList* GetLevelResourceList() = 0; - // Load pak file from level cache to memory. - // sBindRoot is a path in virtual file system, where new pak will be mapper to (ex. LevelCache/mtl) - virtual bool LoadLevelCachePak(const char* sPakName, const char* sBindRoot, bool bOnlyDuringLevelLoading = true) = 0; - // Unloads level cache pak file from memory. - virtual void UnloadLevelCachePak(const char* sPakName) = 0; - - //Loads the pak file for mode switching into memory e.g. Single player mode to Multiplayer mode - virtual bool LoadModeSwitchPak(const char* sPakName, const bool multiplayer) = 0; - //Unloads the mode switching pak file - virtual void UnloadModeSwitchPak(const char* sPakName, const char* sResourceListName, const bool multiplayer) = 0; - - // Load general pak file to memory. - virtual bool LoadPakToMemAsync(const char* pPath, bool bLevelLoadOnly) = 0; - // Unload all aync paks - virtual void UnloadAllAsyncPaks() = 0; - // Load pak file from active layer to memory. - virtual bool LoadLayerPak(const char* sLayerName) = 0; - // Unloads layer pak file from memory if no more references. - virtual void UnloadLayerPak(const char* sLayerName) = 0; - // Retrieve stats on the layer pak - virtual void GetLayerPakStats(SLayerPakStats& stats, bool bCollectAllStats) const = 0; - - // Return time it took to load and precache the level. - virtual CTimeValue GetLastLevelLoadTime() const = 0; - - virtual void GetMemoryStatistics(ICrySizer* pSizer) = 0; - // -}; - -#endif // CRYINCLUDE_CRYCOMMON_IRESOURCEMANAGER_H diff --git a/Code/CryEngine/CryCommon/ISerialize.h b/Code/CryEngine/CryCommon/ISerialize.h index 9ca4fb665c..5fb0d9a3aa 100644 --- a/Code/CryEngine/CryCommon/ISerialize.h +++ b/Code/CryEngine/CryCommon/ISerialize.h @@ -20,7 +20,6 @@ #include #include -#include "CountedValue.h" #include "MiniQueue.h" #include #include @@ -471,58 +470,6 @@ public: } } - template - void Value(const char* name, CountedValue& countedValue) - { - if (!BeginOptionalGroup(name, true)) - { - return; - } - if (IsWriting()) - { - T rawValue = countedValue.Peek(); - Value("Value", rawValue); - typename CountedValue::TCountedID rawId = countedValue.GetLatestID(); - Value("Id", rawId, 'ui32'); - } - - if (IsReading()) - { - T rawValue; - Value("Value", rawValue); - typename CountedValue::TCountedID rawId; - Value("Id", rawId, 'ui32'); - countedValue.UpdateDuringSerializationOnly(rawValue, rawId); - } - EndGroup(); - } - - template - void Value(const char* name, CountedValue& countedValue, int policy) - { - if (!BeginOptionalGroup(name, true)) - { - return; - } - if (IsWriting()) - { - T rawValue = countedValue.Peek(); - Value("Value", rawValue, policy); - typename CountedValue::TCountedID rawId = countedValue.GetLatestID(); - Value("Id", rawId, 'ui32'); - } - - if (IsReading()) - { - T rawValue; - Value("Value", rawValue, policy); - typename CountedValue::TCountedID rawId; - Value("Id", rawId, 'ui32'); - countedValue.UpdateDuringSerializationOnly(rawValue, rawId); - } - EndGroup(); - } - bool ValueChar(const char* name, char* buffer, int len) { string temp; diff --git a/Code/CryEngine/CryCommon/IShader.h b/Code/CryEngine/CryCommon/IShader.h index 5f5209992e..c74d981864 100644 --- a/Code/CryEngine/CryCommon/IShader.h +++ b/Code/CryEngine/CryCommon/IShader.h @@ -36,8 +36,6 @@ #include #include -#include - struct IMaterial; class CRendElementBase; class CRenderObject; @@ -2238,74 +2236,6 @@ struct SShaderTexSlots } }; -struct SShaderGenBit -{ - SShaderGenBit() - { - m_Mask = 0; - m_Flags = 0; - m_nDependencySet = 0; - m_nDependencyReset = 0; - m_NameLength = 0; - m_dwToken = 0; - } - string m_ParamName; - string m_ParamProp; - string m_ParamDesc; - int m_NameLength; - uint64 m_Mask; - uint32 m_Flags; - uint32 m_dwToken; - std::vector m_PrecacheNames; - std::vector m_DependSets; - std::vector m_DependResets; - uint32 m_nDependencySet; - uint32 m_nDependencyReset; - - void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(m_ParamName); - pSizer->AddObject(m_ParamProp); - pSizer->AddObject(m_ParamDesc); - pSizer->AddObject(m_PrecacheNames); - pSizer->AddObject(m_DependSets); - pSizer->AddObject(m_DependResets); - } -}; - -struct SShaderGen -{ - uint32 m_nRefCount; - TArray m_BitMask; - SShaderGen() - { - m_nRefCount = 1; - } - ~SShaderGen() - { - uint32 i; - for (i = 0; i < m_BitMask.Num(); i++) - { - SShaderGenBit* pBit = m_BitMask[i]; - SAFE_DELETE(pBit); - } - m_BitMask.Free(); - } - void Release() - { - m_nRefCount--; - if (!m_nRefCount) - { - delete this; - } - } - - void GetMemoryUsage(ICrySizer* pSizer) const - { - pSizer->AddObject(m_BitMask); - } -}; - //=================================================================================== enum EShaderType @@ -2570,7 +2500,6 @@ public: virtual void SetFlags2(int Flags) = 0; virtual void ClearFlags2(int Flags) = 0; virtual bool Reload(int nFlags, const char* szShaderName) = 0; - virtual TArray* GetREs (int nTech) = 0; virtual AZStd::vector& GetPublicParams() = 0; virtual int GetTexId () = 0; virtual ITexture* GetBaseTexture(int* nPass, int* nTU) = 0; @@ -2579,7 +2508,6 @@ public: virtual ECull GetCull(void) = 0; virtual int Size(int Flags) = 0; virtual uint64 GetGenerationMask() = 0; - virtual SShaderGen* GetGenerationParams() = 0; virtual size_t GetNumberOfUVSets() = 0; virtual int GetTechniqueID(int nTechnique, int nRegisteredTechnique) = 0; virtual AZ::Vertex::Format GetVertexFormat(void) = 0; diff --git a/Code/CryEngine/CryCommon/IStreamEngine.h b/Code/CryEngine/CryCommon/IStreamEngine.h deleted file mode 100644 index 0536e1f486..0000000000 --- a/Code/CryEngine/CryCommon/IStreamEngine.h +++ /dev/null @@ -1,493 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// This is the prototypes of interfaces that will be used for asynchronous -// I/O (streaming). -// THIS IS NOT FINAL AND IS SUBJECT TO CHANGE WITHOUT NOTICE - -// Some excerpts explaining basic ideas behind streaming design here: - -/* - * The idea is that the data loaded is ready for usage and ideally doesn't need further transformation, - * therefore the client allocates the buffer (to avoid extra copy). All the data transformations should take place in the Resource Compiler. If you have to allocate a lot of small memory objects, you should revise this strategy in favor of one big allocation (again, that will be read directly from the compiled file). - * Anyway, we can negotiate that the streaming engine allocates this memory. - * In the end, it could make use of a memory pool, and copying data is not the bottleneck in our engine - * - * The client should take care of all fast operations. Looking up file size should be fast on the virtual - * file system in a pak file, because the directory should be preloaded in memory - */ - -#ifndef CRYINCLUDE_CRYCOMMON_ISTREAMENGINE_H -#define CRYINCLUDE_CRYCOMMON_ISTREAMENGINE_H -#pragma once - - -#include -#include "smartptr.h" -#include "CryThread.h" - -#include "IStreamEngineDefs.h" - -class IStreamCallback; -class ICrySizer; - -#define STREAM_TASK_TYPE_AUDIO_ALL ((1 << eStreamTaskTypeMusic) | (1 << eStreamTaskTypeSound) | (1 << eStreamTaskTypeFSBCache)) - -// Description: -// This is used as parameter to the asynchronous read function -// all the unnecessary parameters go here, because there are many of them. -struct StreamReadParams -{ -public: - StreamReadParams() - { - memset(this, 0, sizeof(*this)); - ePriority = estpNormal; - } - - StreamReadParams ( - DWORD_PTR _dwUserData, - EStreamTaskPriority _ePriority = estpNormal, - unsigned _nLoadTime = 0, - unsigned _nMaxLoadTime = 0, - unsigned _nOffset = 0, - unsigned _nSize = 0, - void* _pBuffer = NULL, - unsigned _nFlags = 0 - ) - : dwUserData (_dwUserData) - , ePriority(_ePriority) - , nPerceptualImportance(0) - , nLoadTime(_nLoadTime) - , nMaxLoadTime(_nMaxLoadTime) - , pBuffer (_pBuffer) - , nOffset (_nOffset) - , nSize (_nSize) - , eMediaType(eStreamSourceTypeUnknown) - , nFlags (_nFlags) - { - } - - // Summary: - // File name. - //const char* szFile; - - // Summary: - // The callback. - //IStreamCallback* pAsyncCallback; - - // Summary: - // The user data that'll be used to call the callback. - DWORD_PTR dwUserData; - - // The priority of this read - EStreamTaskPriority ePriority; - - // Value from 0-255 of the perceptual importance of the task (used for debugging task sheduling) - uint8 nPerceptualImportance; - - // Description: - // The desirable loading time, in milliseconds, from the time of call - // 0 means as fast as possible (desirably in this frame). - unsigned nLoadTime; - - // Description: - // The maximum load time, in milliseconds. 0 means forever. If the read lasts longer, it can be discarded. - // WARNING: avoid too small max times, like 1-10 ms, because many loads will be discarded in this case. - unsigned nMaxLoadTime; - - // Description: - // The buffer into which to read the file or the file piece - // if this is NULL, the streaming engine will supply the buffer. - // Notes: - // DO NOT USE THIS BUFFER during read operation! DO NOT READ from it, it can lead to memory corruption! - void* pBuffer; - - // Description: - // Offset in the file to read; if this is not 0, then the file read - // occurs beginning with the specified offset in bytes. - // The callback interface receives the size of already read data as nSize - // and generally behaves as if the piece of file would be a file of its own. - unsigned nOffset; - - // Description: - // Number of bytes to read; if this is 0, then the whole file is read, - // if nSize == 0 && nOffset != 0, then the file from the offset to the end is read. - // If nSize != 0, then the file piece from nOffset is read, at most nSize bytes - // (if less, an error is reported). So, from nOffset byte to nOffset + nSize - 1 byte in the file. - unsigned nSize; - - // Description: - // Media type to use when starting file request - if wrong, the request may take longer to complete - EStreamSourceMediaType eMediaType; - - // Description: - // The combination of one or several flags from the stream engine general purpose flags. - // See also: - // IStreamEngine::EFlags - unsigned nFlags; -}; - -struct StreamReadBatchParams -{ - StreamReadBatchParams() - : tSource((EStreamTaskType)0) - , szFile(NULL) - , pCallback(NULL) - { - } - - EStreamTaskType tSource; - const char* szFile; - IStreamCallback* pCallback; - StreamReadParams params; -}; - -struct IStreamEngineListener -{ - // - virtual ~IStreamEngineListener() {} - - virtual void OnStreamEnqueue(const void* pReq, const char* filename, EStreamTaskType source, const StreamReadParams& readParams) = 0; - virtual void OnStreamComputedSortKey(const void* pReq, uint64 key) = 0; - virtual void OnStreamBeginIO(const void* pReq, uint32 compressSize, uint32 readSize, EStreamSourceMediaType mediaType) = 0; - virtual void OnStreamEndIO(const void* pReq) = 0; - virtual void OnStreamBeginInflate(const void* pReq) = 0; - virtual void OnStreamEndInflate(const void* pReq) = 0; - virtual void OnStreamBeginAsyncCallback(const void* pReq) = 0; - virtual void OnStreamEndAsyncCallback(const void* pReq) = 0; - virtual void OnStreamDone(const void* pReq) = 0; - virtual void OnStreamPreempted(const void* pReq) = 0; - virtual void OnStreamResumed(const void* pReq) = 0; - // -}; - -// Description: -// The highest level. There is only one StreamingEngine in the application -// and it controls all I/O streams. -struct IStreamEngine -{ -public: - - - enum EJobType - { - ejtStarted = 1 << 0, - ejtPending = 1 << 1, - ejtFinished = 1 << 2, - }; - - // Summary: - // General purpose flags. - enum EFlags - { - // Description: - // If this is set only asynchronous callback will be called. - FLAGS_NO_SYNC_CALLBACK = BIT(0), - // Description: - // If this is set the file will be read from disc directly, instead of from the pak system. - FLAGS_FILE_ON_DISK = BIT(1), - // Description: - // Ignore the tmp out of streaming memory for this request - FLAGS_IGNORE_TMP_OUT_OF_MEM = BIT(2), - // Description: - // External buffer is write only - FLAGS_WRITE_ONLY_EXTERNAL_BUFFER = BIT(3), - }; - - // - // Description: - // Starts asynchronous read from the specified file (the file may be on a - // virtual file system, in pak or zip file or wherever). - // Reads the file contents into the given buffer, up to the given size. - // Upon success, calls success callback. If the file is truncated or for other - // reason can not be read, calls error callback. The callback can be NULL (in this case, the client should poll - // the returned IReadStream object; the returned object must be locked for that) - // NOTE: the error/success/ progress callbacks can also be called from INSIDE this function. - // Arguments: - // tSource - - // szFile - - // pCallback - - // pParams - PLACEHOLDER for the future additional parameters (like priority), or really - // a pointer to a structure that will hold the parameters if there are too many of them. - // Return Value: - // IReadStream is reference-counted and will be automatically deleted if you don't refer to it; - // if you don't store it immediately in an auto-pointer, it may be deleted as soon as on the next line of code, - // because the read operation may complete immediately inside StartRead() and the object is self-disposed - // as soon as the callback is called. - // Remarks: - // In some implementations disposal of the old pointers happen synchronously - // (in the main thread) outside StartRead() (it happens in the entity update), - // so you're guaranteed that it won't trash inside the calling function. However, this may change in the future - // and you'll be required to assign it to IReadStream immediately (StartRead will return IReadStream_AutoPtr then). - // See also: - // IReadStream,IReadStream_AutoPtr - virtual IReadStreamPtr StartRead (const EStreamTaskType tSource, const char* szFile, IStreamCallback* pCallback = NULL, const StreamReadParams* pParams = NULL) = 0; - - // Pass a callback to preRequestCallback if you need to execute code right before the requests get enqueued; the callback is called only once per execution - virtual size_t StartBatchRead(IReadStreamPtr* pStreamsOut, const StreamReadBatchParams* pReqs, size_t numReqs, AZStd::function* preRequestCallback = nullptr) = 0; - - // Call this methods before/after submitting large number of new requests. - virtual void BeginReadGroup() = 0; - virtual void EndReadGroup() = 0; - - // Pause/resumes streaming of specific data types. - // nPauseTypesBitmask is a bit mask of data types (ex, 1< -}; - -// Description: -// This is the file "handle" that can be used to query the status -// of the asynchronous operation on the file. The same object may be returned -// for the same file to multiple clients. -// Notes: -// It will actually represent the asynchronous object in memory, and will be -// thread-safe reference-counted (both AddRef() and Release() will be virtual -// and thread-safe, just like the others) -// Example: -// USE: -// IReadStream_AutoPtr pReadStream = pStreamEngine->StartRead ("bla.xxx", this); -// OR: -// pStreamEngine->StartRead ("MusicSystem","bla.xxx", this); -class IReadStream -{ -public: - // - // Summary: - // Increment ref count, returns new count - virtual int AddRef() = 0; - // Summary: - // Decrement ref count, returns new count - virtual int Release() = 0; - // Summary: - // Returns true if the file read was not successful. - virtual bool IsError() = 0; - // Return Value: - // True if the file read was completed successfully. - // Summary: - // Checks IsError to check if the whole requested file (piece) was read. - virtual bool IsFinished() = 0; - // Description: - // Returns the number of bytes read so far (the whole buffer size if IsFinished()) - // Arguments: - // bWait - if == true, then waits until the pending I/O operation completes. - // Return Value: - // The total number of bytes read (if it completes successfully, returns the size of block being read) - virtual unsigned int GetBytesRead(bool bWait = false) = 0; - // Description: - // Returns the buffer into which the data has been or will be read - // at least GetBytesRead() bytes in this buffer are guaranteed to be already read. - // Notes: - // DO NOT USE THIS BUFFER during read operation! DO NOT READ from it, it can lead to memory corruption! - virtual const void* GetBuffer () = 0; - - // Description: - // Returns the transparent DWORD that was passed in the StreamReadParams::dwUserData field - // of the structure passed in the call to IStreamEngine::StartRead. - // See also: - // StreamReadParams::dwUserData,IStreamEngine::StartRead - virtual DWORD_PTR GetUserData() = 0; - - // Summary: - // Set user defined data into stream's params. - virtual void SetUserData(DWORD_PTR dwUserData) = 0; - - // Description: - // Tries to stop reading the stream; this is advisory and may have no effect - // but the callback will not be called after this. If you just destructing object, - // dereference this object and it will automatically abort and release all associated resources. - virtual void Abort() = 0; - - // Description: - // Tries to stop reading the stream, as long as IO or the async callback is not currently - // in progress. - virtual bool TryAbort() = 0; - - // Summary: - // Unconditionally waits until the callback is called. - // if nMaxWaitMillis is not negative wait for the specified ammount of milliseconds then exit. - // Example: - // If the stream hasn't yet finish, it's guaranteed that the user-supplied callback - // is called before return from this function (unless no callback was specified). - virtual void Wait(int nMaxWaitMillis = -1) = 0; - - // Summary: - // Returns stream params. - virtual const StreamReadParams& GetParams() const = 0; - - // Summary: - // Returns caller type. - virtual const EStreamTaskType GetCallerType() const = 0; - - // Summary: - // Returns media type used to satisfy request - only valid once stream has begun read. - virtual EStreamSourceMediaType GetMediaType() const = 0; - - // Summary: - // Returns pointer to callback routine(can be NULL). - virtual IStreamCallback* GetCallback() const = 0; - - // Summary: - // Returns IO error #. - virtual unsigned GetError() const = 0; - - // Summary: - // Returns IO error name - virtual const char* GetErrorName() const = 0; - - // Summary: - // Returns stream name. - virtual const char* GetName() const = 0; - - // Summary: - // Free temporary memory allocated for this stream, when not needed anymore. - // Can be called from Async callback, to free memory earlier, not waiting for synchrounus callback. - virtual void FreeTemporaryMemory() = 0; - // - -protected: - // Summary: - // The clients are not allowed to destroy this object directly; only via Release(). - virtual ~IReadStream() {} -}; - -TYPEDEF_AUTOPTR(IReadStream); - -// Description: -// CryPak supports asynchronous reading through this interface. The callback -// is called from the main thread in the frame update loop. -// -// The callback receives packets through StreamOnComplete() and -// StreamOnProgress(). The second one can be used to update the asset based -// on the partial data that arrived. the callback that will be called by the -// streaming engine must be implemented by all clients that want to use -// StreamingEngine services -// Remarks: -// the pStream interface is guaranteed to be locked (have reference count > 0) -// while inside the function, but can vanish any time outside the function. -// If you need it, keep it from the beginning (after call to StartRead()) -// some or all callbacks MAY be called from inside IStreamEngine::StartRead() -// -// Example: -// -// IStreamEngine *pStreamEngine = g_pISystem->GetStreamEngine(); // get streaming engine -// IStreamCallback *pAsyncCallback = &MyClass; // user -// -// StreamReadParams params; -// -// params.dwUserData = 0; -// params.nSize = 0; -// params.pBuffer = NULL; -// params.nLoadTime = 10000; -// params.nMaxLoadTime = 10000; -// -// pStreamEngine->StartRead( .. pAsyncCallback .. params .. ); // registers callback -// -class IStreamCallback -{ -public: - // - virtual ~IStreamCallback(){} - - // Description: - // Signals that the file length for the request has been found, and that storage is needed - // Either a pointer to a block of nSize bytes can be returned, into which the file will be - // streamed, or NULL can be returned, in which case temporary memory will be allocated - // internally by the stream engine (which will be freed upon job completion). - virtual void* StreamOnNeedStorage ([[maybe_unused]] IReadStream* pStream, [[maybe_unused]] unsigned nSize, [[maybe_unused]] bool& bAbortOnFailToAlloc) {return NULL; } - - // Description: - // Signals that reading the requested data has completed (with or without error). - // This callback is always called, whether an error occurs or not. - // pStream will signal either IsFinished() or IsError() and will hold the (perhaps partially) read data until this interface is released. - // GetBytesRead() will return the size of the file (the completely read buffer) in case of successful operation end - // or the size of partially read data in case of error (0 if nothing was read). - // Pending status is true during this callback, because the callback itself is the part of IO operation. - // nError == 0 : Success - // nError != 0 : Error code - virtual void StreamAsyncOnComplete ([[maybe_unused]] IReadStream* pStream, [[maybe_unused]] unsigned nError) {} - - // Description: - // Signals that reading the requested data has completed (with or without error). - // This callback is always called, whether an error occurs or not. - // pStream will signal either IsFinished() or IsError() and will hold the (perhaps partially) read data until this interface is released. - // GetBytesRead() will return the size of the file (the completely read buffer) in case of successful operation end - // or the size of partially read data in case of error (0 if nothing was read). - // Pending status is true during this callback, because the callback itself is the part of IO operation. - // nError == 0 : Success - // nError != 0 : Error code - virtual void StreamOnComplete ([[maybe_unused]] IReadStream* pStream, [[maybe_unused]] unsigned nError) {} - // -}; - -#endif // CRYINCLUDE_CRYCOMMON_ISTREAMENGINE_H diff --git a/Code/CryEngine/CryCommon/IStreamEngineDefs.h b/Code/CryEngine/CryCommon/IStreamEngineDefs.h deleted file mode 100644 index e931a6201e..0000000000 --- a/Code/CryEngine/CryCommon/IStreamEngineDefs.h +++ /dev/null @@ -1,236 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_ISTREAMENGINEDEFS_H -#define CRYINCLUDE_CRYCOMMON_ISTREAMENGINEDEFS_H -#pragma once - - -#if defined(ENABLE_PROFILING_CODE) -#define STREAMENGINE_ENABLE_LISTENER -#define STREAMENGINE_ENABLE_STATS -#endif - -enum : unsigned int -{ - ERROR_UNKNOWN_ERROR = 0xF0000000, - ERROR_UNEXPECTED_DESTRUCTION = 0xF0000001, - ERROR_INVALID_CALL = 0xF0000002, - ERROR_CANT_OPEN_FILE = 0xF0000003, - ERROR_REFSTREAM_ERROR = 0xF0000004, - ERROR_OFFSET_OUT_OF_RANGE = 0xF0000005, - ERROR_REGION_OUT_OF_RANGE = 0xF0000006, - ERROR_SIZE_OUT_OF_RANGE = 0xF0000007, - ERROR_CANT_START_READING = 0xF0000008, - ERROR_OUT_OF_MEMORY = 0xF0000009, - ERROR_ABORTED_ON_SHUTDOWN = 0xF000000A, - ERROR_OUT_OF_MEMORY_QUOTA = 0xF000000B, - ERROR_ZIP_CACHE_FAILURE = 0xF000000C, - ERROR_USER_ABORT = 0xF000000D, - ERROR_MISSCHEDULED = 0xF000000F, - ERROR_VERIFICATION_FAIL = 0xF0000010, - ERROR_PREEMPTED = 0xF0000011, - ERROR_DECOMPRESSION_FAIL = 0xF0000012 -}; - -// Summary: -// Types of streaming tasks -// Affects priority directly -enum EStreamTaskType -{ - eStreamTaskTypeCount = 14, - eStreamTaskTypeGeomCache = 13, - eStreamTaskTypePak = 12, - eStreamTaskTypeFlash = 11, - eStreamTaskTypeVideo = 10, - - eStreamTaskTypeMergedMesh = 9, - eStreamTaskTypeShader = 8, - eStreamTaskTypeSound = 7, - eStreamTaskTypeMusic = 6, - eStreamTaskTypeFSBCache = 5, - eStreamTaskTypeAnimation = 4, - eStreamTaskTypeTerrain = 3, - eStreamTaskTypeGeometry = 2, - eStreamTaskTypeTexture = 1, -}; - -// Summary: -// Priority types of streaming tasks -// Affects priority directly -// Limiting number of priority values allows streaming system to minimize seek time -enum EStreamTaskPriority -{ - estpUrgent = 0, - estpPreempted = 1, //For internal use only - estpAboveNormal = 2, - estpNormal = 3, - estpBelowNormal = 4, - estpIdle = 5, -}; - -enum EStreamSourceMediaType : int32_t -{ - eStreamSourceTypeUnknown = 0, - eStreamSourceTypeHDD, - eStreamSourceTypeDisc, - eStreamSourceTypeMemory, -}; - -#if defined(STREAMENGINE_ENABLE_STATS) -struct SStreamEngineStatistics -{ - struct SMediaTypeInfo - { - SMediaTypeInfo() - { - ResetStats(); - } - void ResetStats() - { - memset(this, 0, sizeof(SMediaTypeInfo)); - } - - float fActiveDuringLastSecond; // Amount of time media device was active during last second - float fAverageActiveTime; // Average time since last reset that the media device was active - - uint32 nBytesRead; // Bytes read during last second. - uint32 nRequestCount; // Amount of requests during last second. - uint64 nTotalBytesRead; // Read bytes total from reset. - uint32 nTotalRequestCount; // Number of request from reset. - - uint64 nSeekOffsetLastSecond; // Average seek offset during the last second - uint64 nAverageSeekOffset; // Average seek offset since last reset - - uint32 nCurrentReadBandwidth; // Bytes/second for last second - uint32 nSessionReadBandwidth; // Bytes/second for last second - - uint32 nActualReadBandwidth; // Bytes/second for last second - only taking actual reading into account - uint32 nAverageActualReadBandwidth; // Average read bandwidth in total from reset - only taking actual read time into account - }; - - SMediaTypeInfo hddInfo; - SMediaTypeInfo memoryInfo; - SMediaTypeInfo discInfo; - - uint32 nTotalSessionReadBandwidth;// Average read bandwidth in total from reset - taking full time into account from reset - uint32 nTotalCurrentReadBandwidth;// Total bytes/sec over all types and systems. - - int nPendingReadBytes; // How many bytes still need to be read - float fAverageCompletionTime; // Time in seconds on average takes to complete file request. - float fAverageRequestCount; // Average requests per second being done to streaming engine - - uint64 nMainStreamingThreadWait; - - uint64 nTotalBytesRead; // Read bytes total from reset. - uint32 nTotalRequestCount; // Number of request from reset to the streaming engine. - uint32 nTotalStreamingRequestCount; // Number of request from reset which actually resulted in streaming data. - - int nCurrentDecompressCount; // Number of requests currently waiting to be decompresses - int nCurrentAsyncCount; // Number of requests currently waiting to be async callback - int nCurrentFinishedCount; // Number of requests currently waiting to be finished by mainthread - - uint32 nDecompressBandwidth; // Bytes/second for last second - uint32 nVerifyBandwidth; // Bytes/second for last second - uint32 nDecompressBandwidthAverage; // Bytes/second in total. - uint32 nVerifyBandwidthAverage; // Bytes/second in total. - - bool bTempMemOutOfBudget; // Was the temporary streaming memory out of budget during the last second - int nMaxTempMemory; // Maximum temporary memory used by the streaming system - int nTempMemory; - - struct SRequestTypeInfo - { - SRequestTypeInfo() - : nPendingReadBytes(0) - { - ResetStats(); - } - void ResetStats() - { - nTmpReadBytes = 0; - nTotalStreamingRequestCount = 0; - nTotalReadBytes = 0; - nTotalRequestDataSize = 0; - nTotalRequestCount = 0; - nCurrentReadBandwidth = 0; - nSessionReadBandwidth = 0; - fTotalCompletionTime = .0f; - fAverageCompletionTime = .0f; - } - - void Merge(const SRequestTypeInfo& _other) - { - nPendingReadBytes += _other.nPendingReadBytes; - nTmpReadBytes += _other.nTmpReadBytes; - nTotalStreamingRequestCount += _other.nTotalStreamingRequestCount; - nTotalReadBytes += _other.nTotalReadBytes; - nTotalRequestDataSize += _other.nTotalRequestDataSize; - nTotalRequestCount += _other.nTotalRequestCount; - fTotalCompletionTime += _other.fTotalCompletionTime; - } - - int nPendingReadBytes; // How many bytes still need to be read from media - - uint64 nTmpReadBytes; // Read bytes since last update to compute current bandwidth - - uint32 nTotalStreamingRequestCount; // Total actual streaming requests of this type - uint64 nTotalReadBytes; // Total actual read bytes (compressed data) - uint64 nTotalRequestDataSize; // Total requested bytes from client (uncompressed data) - uint32 nTotalRequestCount; // Total number of finished requests - - uint32 nCurrentReadBandwidth; // Bytes/second for this type during last second - uint32 nSessionReadBandwidth; // Average read bandwidth in total from reset - taking full time into account from reset - - float fTotalCompletionTime; // Time it took to finish all current requests - float fAverageCompletionTime; // Average time it takes to fully complete a request of this type - float fAverageRequestCount; // Average amount of requests made per second - }; - - SRequestTypeInfo typeInfo[eStreamTaskTypeCount]; - - struct SAsset - { - CryStringLocal m_sName; - int m_nSize; - const bool operator<(const SAsset& a) const { return m_nSize > a.m_nSize; } - SAsset() {} - SAsset(const CryStringLocal& sName, const int nSize) - : m_sName(sName) - , m_nSize(nSize) { } - - friend void swap(SAsset& a, SAsset& b) - { - using std::swap; - - a.m_sName.swap(b.m_sName); - swap(a.m_nSize, b.m_nSize); - } - }; - DynArray vecHeavyAssets; -}; -#endif - -struct SStreamEngineOpenStats -{ - int nOpenRequestCount; - int nOpenRequestCountByType[eStreamTaskTypeCount]; -}; - -class IReadStream; -TYPEDEF_AUTOPTR(IReadStream); - -// typedef IReadStream_AutoPtr auto ptr wrapper -typedef IReadStream_AutoPtr IReadStreamPtr; - -#endif // CRYINCLUDE_CRYCOMMON_ISTREAMENGINEDEFS_H diff --git a/Code/CryEngine/CryCommon/ISystem.h b/Code/CryEngine/CryCommon/ISystem.h index 4c6bd73b61..f863804f3d 100644 --- a/Code/CryEngine/CryCommon/ISystem.h +++ b/Code/CryEngine/CryCommon/ISystem.h @@ -65,12 +65,10 @@ struct IProcess; struct ITimer; struct ICryFont; struct IMovieSystem; -struct IMemoryManager; namespace Audio { struct IAudioSystem; } // namespace Audio -struct IStreamEngine; struct SFileVersion; struct INameTable; struct ILevelSystem; @@ -78,18 +76,11 @@ struct IViewSystem; class ICrySizer; class IXMLBinarySerializer; struct IReadWriteXMLSink; -struct IResourceManager; -struct ITextModeConsole; struct IAVI_Reader; class CPNoise3; struct ILocalizationManager; -struct IZLibCompressor; -struct IZLibDecompressor; -struct ILZ4Decompressor; -class IZStdDecompressor; struct IOutputPrintSink; struct IWindowMessageHandler; -struct IImageHandler; namespace AZ { @@ -528,7 +519,6 @@ struct SSystemInitParams ISystemUserCallback* pUserCallback; const char* sLogFileName; // File name to use for log. bool autoBackupLogs; // if true, logs will be automatically backed up each startup - IValidator* pValidator; // You can specify different validator object to use by System. IOutputPrintSink* pPrintSync; // Print Sync which can be used to catch all output from engine char szSystemCmdLine[2048]; // Command line. @@ -558,7 +548,6 @@ struct SSystemInitParams pUserCallback = NULL; sLogFileName = NULL; autoBackupLogs = true; - pValidator = NULL; pPrintSync = NULL; memset(szSystemCmdLine, 0, sizeof(szSystemCmdLine)); @@ -828,22 +817,10 @@ struct ISystem virtual void DoWorkDuringOcclusionChecks() = 0; virtual bool NeedDoWorkDuringOcclusionChecks() = 0; - // Summary: - // Returns the current used memory. - virtual uint32 GetUsedMemory() = 0; - // Summary: // Retrieve the name of the user currently logged in to the computer. virtual const char* GetUserName() = 0; - // Summary: - // Gets current supported CPU features flags. (CPUF_SSE, CPUF_SSE2, CPUF_3DNOW, CPUF_MMX) - virtual int GetCPUFlags() = 0; - - // Summary: - // Gets number of CPUs - virtual int GetLogicalCPUCount() = 0; - // Summary: // Quits the application. virtual void Quit() = 0; @@ -860,13 +837,6 @@ struct ISystem virtual bool IsRelaunch() const = 0; - // Summary: - // Displays an error message to display info for certain time - // Arguments: - // acMessage - Message to show - // fTime - Amount of seconds to show onscreen - virtual void DisplayErrorMessage(const char* acMessage, float fTime, const float* pfColor = 0, bool bHardError = true) = 0; - // Description: // Displays error message. // Logs it to console and file and error message box then terminates execution. @@ -897,35 +867,21 @@ struct ISystem // return the related subsystem interface // - virtual IZLibCompressor* GetIZLibCompressor() = 0; - virtual IZLibDecompressor* GetIZLibDecompressor() = 0; - virtual ILZ4Decompressor* GetLZ4Decompressor() = 0; - virtual IZStdDecompressor* GetZStdDecompressor() = 0; virtual IViewSystem* GetIViewSystem() = 0; virtual ILevelSystem* GetILevelSystem() = 0; virtual INameTable* GetINameTable() = 0; - virtual IValidator* GetIValidator() = 0; - virtual IStreamEngine* GetStreamEngine() = 0; virtual ICmdLine* GetICmdLine() = 0; virtual ILog* GetILog() = 0; virtual AZ::IO::IArchive* GetIPak() = 0; virtual ICryFont* GetICryFont() = 0; - virtual IMemoryManager* GetIMemoryManager() = 0; virtual IMovieSystem* GetIMovieSystem() = 0; virtual ::IConsole* GetIConsole() = 0; virtual IRemoteConsole* GetIRemoteConsole() = 0; - // Returns: - // Can be NULL, because it only exists when running through the editor, not in pure game mode. - virtual IResourceManager* GetIResourceManager() = 0; virtual IProfilingSystem* GetIProfilingSystem() = 0; virtual ISystemEventDispatcher* GetISystemEventDispatcher() = 0; virtual ITimer* GetITimer() = 0; - virtual void DebugStats(bool checkpoint, bool leaks) = 0; - virtual void DumpWinHeaps() = 0; - virtual int DumpMMStats(bool log) = 0; - // Arguments: // bValue - Set to true when running on a cheat protected server or a client that is connected to it (not used in singleplayer). virtual void SetForceNonDevMode(bool bValue) = 0; @@ -934,7 +890,6 @@ struct ISystem virtual bool GetForceNonDevMode() const = 0; virtual bool WasInDevMode() const = 0; virtual bool IsDevMode() const = 0; - virtual bool IsMODValid(const char* szMODName) const = 0; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// @@ -991,13 +946,6 @@ struct ISystem // Gets build version. virtual const SFileVersion& GetBuildVersion() = 0; - // Summary: - // Data compression - //##@{ - virtual bool CompressDataBlock(const void* input, size_t inputSize, void* output, size_t& outputSize, int level = 3) = 0; - virtual bool DecompressDataBlock(const void* input, size_t inputSize, void* output, size_t& outputSize) = 0; - //##@} - ////////////////////////////////////////////////////////////////////////// // Configuration. ////////////////////////////////////////////////////////////////////////// @@ -1019,21 +967,8 @@ struct ISystem // pCallback - 0 means normal LoadConfigVar behaviour is used virtual void LoadConfiguration(const char* sFilename, ILoadConfigurationEntrySink* pSink = 0, bool warnIfMissing = true) = 0; - // Summary: - // Retrieves current configuration specification for client or server. - // Arguments: - // bClient - If true returns local client config spec, if false returns server config spec. - virtual ESystemConfigSpec GetConfigSpec(bool bClient = true) = 0; - virtual ESystemConfigSpec GetMaxConfigSpec() const = 0; - // Summary: - // Changes current configuration specification for client or server. - // Arguments: - // bClient - If true changes client config spec (sys_spec variable changed), - // if false changes only server config spec (as known on the client). - virtual void SetConfigSpec(ESystemConfigSpec spec, ESystemConfigPlatform platform, bool bClient) = 0; - ////////////////////////////////////////////////////////////////////////// // Summary: @@ -1045,10 +980,6 @@ struct ISystem virtual void SetConfigPlatform(ESystemConfigPlatform platform) = 0; ////////////////////////////////////////////////////////////////////////// - // Summary: - // Detects and set optimal spec. - virtual void AutoDetectSpec(bool detectResolution) = 0; - // Summary: // Query if system is now paused. // Pause flag is set when calling system update with pause mode. @@ -1058,8 +989,6 @@ struct ISystem // Retrieves localized strings manager interface. virtual ILocalizationManager* GetLocalizationManager() = 0; - virtual ITextModeConsole* GetITextModeConsole() = 0; - // Summary: // Retrieves the perlin noise singleton instance. virtual CPNoise3* GetNoiseGen() = 0; @@ -1150,24 +1079,10 @@ struct ISystem virtual ESystemGlobalState GetSystemGlobalState(void) = 0; virtual void SetSystemGlobalState(ESystemGlobalState systemGlobalState) = 0; - // Summary: - // Asynchronous memcpy - // Note sync variable will be incremented (in calling thread) before job starts - // and decremented when job finishes. Multiple async copies can therefore be - // tied to the same sync variable, therefore it's advised to wait for completion with - // while(*sync) (yield()); - virtual void AsyncMemcpy(void* dst, const void* src, size_t size, int nFlags, volatile int* sync) = 0; - // - #if !defined(_RELEASE) virtual bool IsSavingResourceList() const = 0; #endif - // Initializes Steam if needed and returns if it was successful - virtual bool SteamInit() = 0; - - virtual const IImageHandler* GetImageHandler() const = 0; - // Summary: // Gets the root window message handler function // The returned pointer is platform-specific: @@ -1771,44 +1686,6 @@ inline void CryLogAlways(const char* format, ...) #endif // EXCLUDE_NORMAL_LOG -/***************************************************** -ASYNC MEMCPY FUNCTIONS -*****************************************************/ - -// Complex delegation required because it is not really easy to -// export a external standalone symbol like a memcpy function when -// building with modules. Dll pay an extra indirection cost for calling this -// function. -#if !defined(AZ_MONOLITHIC_BUILD) -# define CRY_ASYNC_MEMCPY_DELEGATE_TO_CRYSYSTEM -#endif -#define CRY_ASYNC_MEMCPY_API extern "C" - -// Note sync variable will be incremented (in calling thread) before job starts -// and decremented when job finishes. Multiple async copies can therefore be -// tied to the same sync variable, therefore wait for completion with -// while(*sync) (yield()); -#if defined(CRY_ASYNC_MEMCPY_DELEGATE_TO_CRYSYSTEM) -inline void cryAsyncMemcpy( - void* dst - , const void* src - , size_t size - , int nFlags - , volatile int* sync) -{ - GetISystem()->AsyncMemcpy(dst, src, size, nFlags, sync); -} -# else -CRY_ASYNC_MEMCPY_API void cryAsyncMemcpy( - void* dst - , const void* src - , size_t size - , int nFlags - , volatile int* sync); -#endif - - - ////////////////////////////////////////////////////////////////////////// // Additional headers. ////////////////////////////////////////////////////////////////////////// diff --git a/Code/CryEngine/CryCommon/ITextModeConsole.h b/Code/CryEngine/CryCommon/ITextModeConsole.h deleted file mode 100644 index 026f6d945f..0000000000 --- a/Code/CryEngine/CryCommon/ITextModeConsole.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Allows creation of text mode displays the for dedicated server - - -#ifndef CRYINCLUDE_CRYCOMMON_ITEXTMODECONSOLE_H -#define CRYINCLUDE_CRYCOMMON_ITEXTMODECONSOLE_H -#pragma once - - -struct ITextModeConsole -{ - // - virtual ~ITextModeConsole() {} - virtual Vec2_tpl BeginDraw() = 0; - virtual void PutText(int x, int y, const char* msg) = 0; - virtual void EndDraw() = 0; - virtual void OnShutdown() = 0; - - virtual void SetTitle([[maybe_unused]] const char* title) {} - // -}; - -#endif // CRYINCLUDE_CRYCOMMON_ITEXTMODECONSOLE_H diff --git a/Code/CryEngine/CryCommon/IZLibCompressor.h b/Code/CryEngine/CryCommon/IZLibCompressor.h deleted file mode 100644 index df85992eef..0000000000 --- a/Code/CryEngine/CryCommon/IZLibCompressor.h +++ /dev/null @@ -1,219 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_IZLIBCOMPRESSOR_H -#define CRYINCLUDE_CRYCOMMON_IZLIBCOMPRESSOR_H -#pragma once - - -/* - wrapper interface for the zlib compression / deflate interface - - supports multiple compression streams with an async compatible wrapper - - Gotchas: - the ptr to the input data must remain valid whilst the stream is deflating - the ptr to the output buffer must remain valid whilst the stream is deflating - - **************************************************************************************** - - usage example: - - IZLibCompressor *pComp=GetISystem()->GetIZLibCompressor(); - // see deflateInit2() documentation zlib manual for more info on the parameters here - // this initializes the stream to produce a gzip format block with fairly low memory requirements - IZLibDeflateStream *pStream=pComp->CreateDeflateStream(2,eZMeth_Deflated,24,3,eZStrat_Default,eZFlush_NoFlush); - char *pOutput=new char[512]; // arbitrary size - const char *pInputData="This is an example piece of data that is to be compressed. It can be any arbitrary block of binary data - not just text"; - const int inputBlockSize=16; // to simulate streaming of input, this example provides the input in 16 byte blocks - int totalInput=sizeof(pInputData); - int bytesInput=0; - bool done=false; - FILE *outputFile=fopen("myfile.gz","rb"); - - do - { - EZDeflateState state=pStream->GetState(); - - switch (state) - { - case eZDefState_AwaitingInput: - // 'stream' input data, there is no restriction on the block size you can input, if all the data is available immediately, input all of it at once - { - int inputSize=min(inputBlockSize,totalInput-bytesInput); - - if (inputSize<=0) - { - pStream->EndInput(); - } - else - { - pStream->Input(pInputData+bytesInput,inputSize); - bytesInput+=inputSize; - } - } - break; - - case eZDefState_Deflating: - // do something more interesting... like getting out of this loop and running the rest of your game... - break; - - case eZDefState_ConsumeOutput: - // stream output to a file - { - int bytesToOutput=pStream->GetBytesOutput(); - - if (bytesToOutput>0) - { - fwrite(pOutput,1,bytesToOutput,outputFile); - } - - pStream->SetOutputBuffer(pOutput,sizeof(pOutput)); - } - break; - - case eZDefState_Finished: - case ezDefState_Error: - done=true; - break; - } - - } while (!done); - - fclose(outputFile); - - pStream->Release(); - delete [] pOutput; - -****************************************************************************************/ - -// don't change the order of these zlib wrapping enum values without updating the mapping -// implementation in CZLibCompressorStream -enum EZLibStrategy -{ - eZStrat_Default, // Z_DEFAULT_STRATEGY - eZStrat_Filtered, // Z_FILTERED - eZStrat_HuffmanOnly, // Z_HUFFMAN_ONLY - eZStrat_RLE // Z_RLE -}; -enum EZLibMethod -{ - eZMeth_Deflated // Z_DEFLATED -}; -enum EZLibFlush -{ - eZFlush_NoFlush, // Z_NO_FLUSH - eZFlush_PartialFlush, // Z_PARTIAL_FLUSH - eZFlush_SyncFlush, // Z_SYNC_FLUSH - eZFlush_FullFlush, // Z_FULL_FLUSH -}; - -enum EZDeflateState -{ - eZDefState_AwaitingInput, // caller must call Input() or Finish() to continue - eZDefState_Deflating, // caller must wait - eZDefState_ConsumeOutput, // caller must consume output and then call SetOutputBuffer() to continue - eZDefState_Finished, // stream finished, caller must call Release() to destroy stream - eZDefState_Error // error has occurred and the stream has been closed and will no longer compress -}; - -struct IZLibDeflateStream -{ -protected: - virtual ~IZLibDeflateStream() {}; // use Release() - -public: - struct SStats - { - int bytesInput; - int bytesOutput; - int curMemoryUsed; - int peakMemoryUsed; - }; - - // - // Description: - // Specifies the output buffer for the deflate operation - // Should be set before providing input - // The specified buffer must remain valid (ie do not free) whilst compression is in progress (state == eZDefState_Deflating) - virtual void SetOutputBuffer(char* pInBuffer, int inSize) = 0; - - // Description: - // Returns the number of bytes from the output buffer that are ready to be consumed. After consuming any output, you should call SetOutputBuffer() again to mark the buffer as available - virtual int GetBytesOutput() = 0; - - // Description: - // Begins compressing the source data pInSource of length inSourceSize to a previously specified output buffer - // Only valid to be called if the stream is in state eZDefState_AwaitingInput - // The specified buffer must remain valid (ie do not free) whilst compression is in progress (state == eZDefState_Deflating) - virtual void Input(const char* pInSource, int inSourceSize) = 0; - - // Description: - // Finishes the compression, causing all data to be flushed to the output buffer - // Once called no more data can be input - // After calling the caller must wait until GetState() reutrns eZDefState_Finished - virtual void EndInput() = 0; - - // Description: - // Returns the state of the stream, - virtual EZDeflateState GetState() = 0; - - // Description: - // Gets stats on deflate stream, valid to call at anytime - virtual void GetStats(SStats* pOutStats) = 0; - - // Description: - // Deletes the deflate stream. Will assert if stream is in an invalid state to be released (in state eZDefState_Deflating) - virtual void Release() = 0; - // -}; - -// md5 support structure -struct SMD5Context -{ - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; - -struct IZLibCompressor -{ -protected: - virtual ~IZLibCompressor() {}; // use Release() - -public: - // - // Description: - // Creates a deflate stream to compress data using zlib - // See documentation for zlib deflateInit2() for usage details - // inFlushMethod is passed to calls to zlib deflate(), see zlib docs on deflate() for more details - virtual IZLibDeflateStream* CreateDeflateStream(int inLevel, EZLibMethod inMethod, int inWindowBits, int inMemLevel, EZLibStrategy inStrategy, EZLibFlush inFlushMethod) = 0; - - virtual void Release() = 0; - - // Description: - // Initializes an MD5 context - virtual void MD5Init(SMD5Context* pIOCtx) = 0; - - // Description: - // Digests some data into an existing MD5 context - virtual void MD5Update(SMD5Context* pIOCtx, const char* pInBuff, unsigned int len) = 0; - - // Description: - // Closes the MD5 context and extract the final 16 byte MD5 digest value - virtual void MD5Final(SMD5Context * pIOCtx, char outDigest[16]) = 0; - // -}; - -#endif // CRYINCLUDE_CRYCOMMON_IZLIBCOMPRESSOR_H - diff --git a/Code/CryEngine/CryCommon/IZlibDecompressor.h b/Code/CryEngine/CryCommon/IZlibDecompressor.h deleted file mode 100644 index bd9417c935..0000000000 --- a/Code/CryEngine/CryCommon/IZlibDecompressor.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Provides the interface for the zlib inflate wrapper - - -#ifndef CRYINCLUDE_CRYCOMMON_IZLIBDECOMPRESSOR_H -#define CRYINCLUDE_CRYCOMMON_IZLIBDECOMPRESSOR_H -#pragma once - - -enum EZInflateState -{ - eZInfState_AwaitingInput, // caller must call Input() to continue - eZInfState_Inflating, // caller must wait - eZInfState_ConsumeOutput, // caller must consume output and then call SetOutputBuffer() to continue - eZInfState_Finished, // caller must call Release() - eZInfState_Error // error has occurred and the stream has been closed and will no longer compress -}; - -struct IZLibInflateStream -{ -protected: - virtual ~IZLibInflateStream() {}; // use Release() - -public: - struct SStats - { - int bytesInput; - int bytesOutput; - int curMemoryUsed; - int peakMemoryUsed; - }; - - // Description: - // Specifies the output buffer for the inflate operation - // Should be set before providing input - // The specified buffer must remain valid (ie do not free) whilst compression is in progress (state == eZInfState_Inflating) - virtual void SetOutputBuffer(char* pInBuffer, unsigned int inSize) = 0; - - // Description: - // Returns the number of bytes from the output buffer that are ready to be consumed. After consuming any output, you should call SetOutputBuffer() again to mark the buffer as available - virtual unsigned int GetBytesOutput() = 0; - - // Description: - // Begins decompressing the source data pInSource of length inSourceSize to a previously specified output buffer - // Only valid to be called if the stream is in state eZInfState_AwaitingInput - // The specified buffer must remain valid (ie do not free) whilst compression is in progress (state == eZInfState_Inflating) - virtual void Input(const char* pInSource, unsigned int inSourceSize) = 0; - - // Description: - // Finishes the compression, causing all data to be flushed to the output buffer - // Once called no more data can be input - // After calling the caller must wait until GetState() reuturns eZInfState_Finished - virtual void EndInput() = 0; - - // Description: - // Returns the state of the stream, - virtual EZInflateState GetState() = 0; - - // Description: - // Gets stats on inflate stream, valid to call at anytime - virtual void GetStats(SStats* pOutStats) = 0; - - // Description: - // Deletes the inflate stream. Will assert if stream is in an invalid state to be released (in state eZInfState_Inflating) - virtual void Release() = 0; -}; - -struct IZLibDecompressor -{ -protected: - virtual ~IZLibDecompressor() {}; // use Release() - -public: - // Description: - // Creates a inflate stream to decompress data using zlib - virtual IZLibInflateStream* CreateInflateStream() = 0; - - virtual void Release() = 0; -}; - -#endif // CRYINCLUDE_CRYCOMMON_IZLIBDECOMPRESSOR_H - diff --git a/Code/CryEngine/CryCommon/ImageExtensionHelper.cpp b/Code/CryEngine/CryCommon/ImageExtensionHelper.cpp deleted file mode 100644 index 8cf29bcb2a..0000000000 --- a/Code/CryEngine/CryCommon/ImageExtensionHelper.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include - -namespace CImageExtensionHelper -{ - ColorF GetAverageColor(uint8 const* pMem) - { - pMem = _findChunkStart(pMem, FOURCC_AvgC); - - if (pMem) - { - ColorF ret = ColorF(SwapEndianValue(*(uint32*)pMem)); - //flip red and blue - const float cRed = ret.r; - ret.r = ret.b; - ret.b = cRed; - return ret; - } - - return Col_White; // chunk does not exist - } - - bool IsRangeless(ETEX_Format eTF) - { - return (eTF == eTF_BC6UH || - eTF == eTF_BC6SH || - eTF == eTF_R9G9B9E5 || - eTF == eTF_R16G16B16A16F || - eTF == eTF_R32G32B32A32F || - eTF == eTF_R16F || - eTF == eTF_R32F || - eTF == eTF_R16G16F || - eTF == eTF_R11G11B10F); - } - - bool IsQuantized(ETEX_Format eTF) - { - return (eTF == eTF_B4G4R4A4 || - eTF == eTF_B5G6R5 || - eTF == eTF_B5G5R5 || - eTF == eTF_BC1 || - eTF == eTF_BC2 || - eTF == eTF_BC3 || - eTF == eTF_BC4U || - eTF == eTF_BC4S || - eTF == eTF_BC5U || - eTF == eTF_BC5S || - eTF == eTF_BC6UH || - eTF == eTF_BC6SH || - eTF == eTF_BC7 || - eTF == eTF_R9G9B9E5 || - eTF == eTF_ETC2 || - eTF == eTF_EAC_R11 || - eTF == eTF_ETC2A || - eTF == eTF_EAC_RG11 || - eTF == eTF_PVRTC2 || - eTF == eTF_PVRTC4 || - eTF == eTF_ASTC_4x4 || - eTF == eTF_ASTC_5x4 || - eTF == eTF_ASTC_5x5 || - eTF == eTF_ASTC_6x5 || - eTF == eTF_ASTC_6x6 || - eTF == eTF_ASTC_8x5 || - eTF == eTF_ASTC_8x6 || - eTF == eTF_ASTC_8x8 || - eTF == eTF_ASTC_10x5 || - eTF == eTF_ASTC_10x6 || - eTF == eTF_ASTC_10x8 || - eTF == eTF_ASTC_10x10 || - eTF == eTF_ASTC_12x10 || - eTF == eTF_ASTC_12x12 - ); - } -} diff --git a/Code/CryEngine/CryCommon/ImageExtensionHelper.h b/Code/CryEngine/CryCommon/ImageExtensionHelper.h deleted file mode 100644 index 71e58074c9..0000000000 --- a/Code/CryEngine/CryCommon/ImageExtensionHelper.h +++ /dev/null @@ -1,2155 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - -#include -#include -#include -#include -#include - -#if defined(AZ_RESTRICTED_PLATFORM) || defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#undef AZ_RESTRICTED_SECTION -#define IMAGEEXTENSIONHELPER_H_SECTION_1 1 -#define IMAGEEXTENSIONHELPER_H_SECTION_2 2 -#define IMAGEEXTENSIONHELPER_H_SECTION_CONSTS 3 -#define IMAGEEXTENSIONHELPER_H_SECTION_ISNATIVE 4 -#endif - -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION IMAGEEXTENSIONHELPER_H_SECTION_1 - #include AZ_RESTRICTED_FILE(ImageExtensionHelper_h) -#endif - -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION IMAGEEXTENSIONHELPER_H_SECTION_2 - #include AZ_RESTRICTED_FILE(ImageExtensionHelper_h) -#endif - -#ifndef MAKEFOURCC - #define MAKEFOURCC(ch0, ch1, ch2, ch3) \ - ((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) | \ - ((uint32)(uint8)(ch2) << 16) | ((uint32)(uint8)(ch3) << 24)) -#endif /* defined(MAKEFOURCC) */ - - -// This header defines constants and structures that are useful when parsing -// DDS files. DDS files were originally designed to use several structures -// and constants that are native to DirectDraw and are defined in ddraw.h, -// such as DDSURFACEDESC2 and DDSCAPS2. This file defines similar -// (compatible) constants and structures so that one can use DDS files -// without needing to include ddraw.h. - -// Crytek specific image extensions -// -// usually added to the end of DDS files - -//Needed to write out DDS files on Mac -#if AZ_TRAIT_OS_PLATFORM_APPLE || defined(AZ_PLATFORM_LINUX) -#define DDPF_ALPHAPIXELS 0x00000001 // Texture contains alpha data -#define DDPF_ALPHA 0x00000002 // For alpha channel only uncompressed data -#define DDPF_FOURCC 0x00000004 // Texture contains compressed RGB data -#define DDPF_RGB 0x00000040 // Texture contains uncompressed RGB data -#define DDPF_YUV 0x00000200 // For YUV uncompressed data -#define DDPF_LUMINANCE 0x00020000 // For single channel color uncompressed data - -#define DDSCAPS_COMPLEX 0x00000008 // Must be used on any file that contains more than one surface -#define DDSCAPS_MIPMAP 0x00400000 // Should be used for a mipmap -#define DDSCAPS_TEXTURE 0x00001000 // Required -#endif - -#define DDS_FOURCC 0x00000004 // DDPF_FOURCC -#define DDS_RGB 0x00000040 // DDPF_RGB -#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE -#define DDS_SIGNED 0x00080000 // DDPF_SIGNED -#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS -#define DDS_LUMINANCEA 0x00020001 // DDS_LUMINANCE | DDPF_ALPHAPIXELS -#define DDS_A 0x00000001 // DDPF_ALPHAPIXELS -#define DDS_A_ONLY 0x00000002 // DDPF_ALPHA - -#define DDS_FOURCC_A16B16G16R16 0x00000024 // FOURCC A16B16G16R16 -#define DDS_FOURCC_V16U16 0x00000040 // FOURCC V16U16 -#define DDS_FOURCC_Q16W16V16U16 0x0000006E // FOURCC Q16W16V16U16 -#define DDS_FOURCC_R16F 0x0000006F // FOURCC R16F -#define DDS_FOURCC_G16R16F 0x00000070 // FOURCC G16R16F -#define DDS_FOURCC_A16B16G16R16F 0x00000071 // FOURCC A16B16G16R16F -#define DDS_FOURCC_R32F 0x00000072 // FOURCC R32F -#define DDS_FOURCC_G32R32F 0x00000073 // FOURCC G32R32F -#define DDS_FOURCC_A32B32G32R32F 0x00000074 // FOURCC A32B32G32R32F - -#define DDSD_CAPS 0x00000001l // default -#define DDSD_PIXELFORMAT 0x00001000l -#define DDSD_WIDTH 0x00000004l -#define DDSD_HEIGHT 0x00000002l -#define DDSD_LINEARSIZE 0x00080000l - -#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT -#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT -#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH -#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH -#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE - -#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE -#define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP -#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX - -#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX -#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX -#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY -#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY -#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ -#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ - -#define DDS_CUBEMAP_ALLFACES (DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX | \ - DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY | \ - DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ) - -#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME - -#define DDS_RESF1_NORMALMAP 0x01000000 -#define DDS_RESF1_DSDT 0x02000000 - -#define CRY_DDS_DX10_SUPPORT - -#include - -#if defined(WIN32) && !defined(DXGI_FORMAT_DEFINED) -#include // DX10+ formats -#endif // #if defined(WIN32) && !defined(DXGI_FORMAT_DEFINED) - - -namespace CImageExtensionHelper -{ - struct DDS_PIXELFORMAT - { - DWORD dwSize; - DWORD dwFlags; - DWORD dwFourCC; - DWORD dwRGBBitCount; - DWORD dwRBitMask; - DWORD dwGBitMask; - DWORD dwBBitMask; - DWORD dwABitMask; - - const bool operator == (const DDS_PIXELFORMAT& fmt) const - { - return dwFourCC == fmt.dwFourCC && - dwFlags == fmt.dwFlags && - dwRGBBitCount == fmt.dwRGBBitCount && - dwRBitMask == fmt.dwRBitMask && - dwGBitMask == fmt.dwGBitMask && - dwBBitMask == fmt.dwBBitMask && - dwABitMask == fmt.dwABitMask && - dwSize == fmt.dwSize; - } - - AUTO_STRUCT_INFO - }; - - struct DDS_HEADER_DXT10 - { - // we're unable to use native enums because of TypeInfo(), so we use DWORD instead. - DWORD /*DXGI_FORMAT*/ dxgiFormat; - DWORD /*D3D10_RESOURCE_DIMENSION*/ resourceDimension; - unsigned int miscFlag; - unsigned int arraySize; - unsigned int reserved; - - AUTO_STRUCT_INFO - }; - - struct DDS_HEADER - { - DWORD dwSize; - DWORD dwHeaderFlags; - DWORD dwHeight; - DWORD dwWidth; - DWORD dwPitchOrLinearSize; - DWORD dwDepth; // only if DDS_HEADER_FLAGS_VOLUME is set in dwHeaderFlags - DWORD dwMipMapCount; - DWORD dwAlphaBitDepth; - DWORD dwReserved1; // Crytek image flags - float fAvgBrightness; // Average top mip brightness. Could be f16/half - ColorF cMinColor; - ColorF cMaxColor; - DDS_PIXELFORMAT ddspf; - DWORD dwSurfaceFlags; - DWORD dwCubemapFlags; - BYTE bNumPersistentMips; - BYTE bTileMode; - BYTE bReserved2[6]; - DWORD dwTextureStage; - - AUTO_STRUCT_INFO - - inline const bool IsValid() const { return sizeof(*this) == dwSize; } - inline const bool IsDX10Ext() const { return ddspf.dwFourCC == MAKEFOURCC('D', 'X', '1', '0'); } - inline const uint32 GetMipCount() const { return max(1u, (uint32)dwMipMapCount); } - - inline const size_t GetFullHeaderSize() const - { - if (IsDX10Ext()) - { - return sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10); - } - - return sizeof(DDS_HEADER); - } - }; - - // standard description of file header - struct DDS_FILE_DESC - { - DWORD dwMagic; - DDS_HEADER header; - - AUTO_STRUCT_INFO - - inline const bool IsValid() const { return dwMagic == MAKEFOURCC('D', 'D', 'S', ' ') && header.IsValid(); } - inline const size_t GetFullHeaderSize() const { return sizeof(dwMagic) + header.GetFullHeaderSize(); } - }; - - // chunk identifier - const static uint32 FOURCC_CExt = MAKEFOURCC('C', 'E', 'x', 't'); // Crytek extension start - const static uint32 FOURCC_AvgC = MAKEFOURCC('A', 'v', 'g', 'C'); // average color - const static uint32 FOURCC_CEnd = MAKEFOURCC('C', 'E', 'n', 'd'); // Crytek extension end - const static uint32 FOURCC_AttC = MAKEFOURCC('A', 't', 't', 'C'); // Chunk Attached Channel - - // flags to propagate from the RC to the engine through GetImageFlags() - // 32bit bitmask, numbers should not change as engine relies on them - const static uint32 EIF_Cubemap = 0x1; - const static uint32 EIF_Volumetexture = 0x2; - const static uint32 EIF_Decal = 0x4; // this is usually set through the preset - const static uint32 EIF_Greyscale = 0x8; // hint for the engine (e.g. greyscale light beams can be applied to shadow mask), can be for DXT1 because compression artfacts don't count as color - const static uint32 EIF_SupressEngineReduce = 0x10; // info for the engine: don't reduce texture resolution on this texture - const static uint32 EIF_UNUSED_BIT = 0x40; // Free to use - const static uint32 EIF_AttachedAlpha = 0x400; // info for the engine: it's a texture with attached alpha channel - const static uint32 EIF_SRGBRead = 0x800; // info for the engine: if gamma corrected rendering is on, this texture requires SRGBRead (it's not stored in linear) - const static uint32 EIF_DontResize = 0x8000; // info for the engine: for dds textures that shouldn't be resized with r_TexResolution - const static uint32 EIF_RenormalizedTexture = 0x10000; // info for the engine: for dds textures that have renormalized color range - const static uint32 EIF_CafeNative = 0x20000; // info for the engine: native Cafe texture format - const static uint32 EIF_Tiled = 0x80000; // info for the engine: texture has been tiled for the platform - const static uint32 EIF_Splitted = 0x200000; // info for the engine: this texture is splitted - const static uint32 EIF_Colormodel = 0x7000000; // info for the engine: bitmask: colormodel used in the texture - const static uint32 EIF_Colormodel_RGB = 0x0000000; // info for the engine: colormodel is RGB (default) - const static uint32 EIF_Colormodel_CIE = 0x1000000; // info for the engine: colormodel is CIE (used for terrain) - const static uint32 EIF_Colormodel_YCC = 0x2000000; // info for the engine: colormodel is Y'CbCr (used for reflectance) - const static uint32 EIF_Colormodel_YFF = 0x3000000; // info for the engine: colormodel is Y'FbFr (used for reflectance) - const static uint32 EIF_Colormodel_IRB = 0x4000000; // info for the engine: colormodel is IRB (used for reflectance) - -#if defined(AZ_PLATFORM_JASPER) || defined(TOOLS_SUPPORT_JASPER) - #define AZ_RESTRICTED_SECTION IMAGEEXTENSIONHELPER_H_SECTION_CONSTS - #include AZ_RESTRICTED_FILE_EXPLICIT(ImageExtensionHelper_h, jasper) - #undef AZ_RESTRICTED_SECTION -#endif - -#if defined(AZ_PLATFORM_PROVO) || defined(TOOLS_SUPPORT_PROVO) - #define AZ_RESTRICTED_SECTION IMAGEEXTENSIONHELPER_H_SECTION_CONSTS - #include AZ_RESTRICTED_FILE_EXPLICIT(ImageExtensionHelper_h, provo) - #undef AZ_RESTRICTED_SECTION -#endif - -#if defined(AZ_PLATFORM_SALEM) || defined(TOOLS_SUPPORT_SALEM) - #define AZ_RESTRICTED_SECTION IMAGEEXTENSIONHELPER_H_SECTION_CONSTS - #include AZ_RESTRICTED_FILE_EXPLICIT(ImageExtensionHelper_h, salem) - #undef AZ_RESTRICTED_SECTION -#endif - - enum ETileMode - { - eTM_None = 0, - eTM_LinearPadded, - eTM_Optimal, - }; - - // Arguments: - // pDDSHeader - must not be 0 - // Returns: - // Chunk flags (combined from EIF_Cubemap,EIF_Volumetexture,EIF_Decal,...) - inline uint32 GetImageFlags(DDS_HEADER* pDDSHeader) - { - assert(pDDSHeader); - - // non standardized way to expose some features in the header (same information is in attached chunk but then - // streaming would need to find this spot in the file) - // if this is causing problems we need to change it - if (pDDSHeader->dwSize >= sizeof(DDS_HEADER)) - { - if (pDDSHeader->dwTextureStage == 'CRYF') - { - return pDDSHeader->dwReserved1; - } - } - - return 0; - } - - // Arguments: - // pDDSHeader - must not be 0 - // Returns: - // Chunk flags (combined from EIF_Cubemap,EIF_Volumetexture,EIF_Decal,...) - inline bool SetImageFlags(DDS_HEADER* pDDSHeader, uint32 flags) - { - assert(pDDSHeader); - - // non standardized way to expose some features in the header (same information is in attached chunk but then - // streaming would need to find this spot in the file) - // if this is causing problems we need to change it - if (pDDSHeader->dwSize >= sizeof(DDS_HEADER)) - { - if (pDDSHeader->dwTextureStage == 'CRYF') - { - pDDSHeader->dwReserved1 = flags; - return true; - } - } - - return false; - } - - // Arguments: - // Chunk flags (combined from EIF_Cubemap,EIF_Volumetexture,EIF_Decal,...) - // Returns: - // true, if this texture is ready for this platform - inline const bool IsImageNative(const uint32 nFlags) - { - return (nFlags & (0 -#if defined(AZ_PLATFORM_JASPER) || defined(TOOLS_SUPPORT_JASPER) - #define AZ_RESTRICTED_SECTION IMAGEEXTENSIONHELPER_H_SECTION_ISNATIVE - #include AZ_RESTRICTED_FILE_EXPLICIT(ImageExtensionHelper_h, jasper) -#endif -#if defined(AZ_PLATFORM_PROVO) || defined(TOOLS_SUPPORT_PROVO) - #define AZ_RESTRICTED_SECTION IMAGEEXTENSIONHELPER_H_SECTION_ISNATIVE - #include AZ_RESTRICTED_FILE_EXPLICIT(ImageExtensionHelper_h, provo) -#endif -#if defined(AZ_PLATFORM_SALEM) || defined(TOOLS_SUPPORT_SALEM) - #define AZ_RESTRICTED_SECTION IMAGEEXTENSIONHELPER_H_SECTION_ISNATIVE - #include AZ_RESTRICTED_FILE_EXPLICIT(ImageExtensionHelper_h, salem) -#endif - )) == 0; - } - - // Arguments: - // pMem - usually first byte behind DDS file data, can be 0 (e.g. in case there no more bytes than DDS file data) - // Returns: - // 0 if not existing - inline uint8 const* _findChunkStart(uint8 const* pMem, const uint32 dwChunkName, uint32* dwOutSize = NULL) - { - if (pMem) - { - if (*(uint32*)pMem == SwapEndianValue(FOURCC_CExt)) - { - pMem += 4; // jump over chunk name - while (*(uint32*)pMem != SwapEndianValue(FOURCC_CEnd)) - { - if (*(uint32*)pMem == SwapEndianValue(dwChunkName)) - { - pMem += 4; // jump over chunk name - const uint32 size = SwapEndianValue(*(uint32*)(pMem)); - if (dwOutSize) - { - *dwOutSize = size; - } - pMem += 4; // jump over chunk size - return size > 0 ? pMem : NULL; - } - - pMem += 8 + SwapEndianValue(*(uint32*)(&pMem[4])); // jump over chunk - } - } - } - - return 0; // chunk does not exist - } - - // Arguments: - // pMem - usually first byte behind DDS file data, can be 0 (e.g. in case there no more bytes than DDS file data) - ColorF GetAverageColor(uint8 const* pMem); - - // Arguments: - // pMem - usually first byte behind DDS file data, can be 0 (e.g. in case there no more bytes than DDS file data) - // Returns: - // pointer to the DDS header - inline DDS_HEADER* GetAttachedImage(uint8 const* pMem, uint32* dwOutSize = NULL) - { - pMem = _findChunkStart(pMem, FOURCC_AttC, dwOutSize); - if (pMem) - { - return (DDS_HEADER*)(pMem + 4); - } - - if (dwOutSize) - { - *dwOutSize = 0; - } - return 0; // chunk does not exist - } - - static ILINE Vec2i GetBlockDim(const ETEX_Format eTF) - { - if (eTF == eTF_BC1 || eTF == eTF_BC2 || eTF == eTF_BC3 || eTF == eTF_BC5U || eTF == eTF_BC5S || eTF == eTF_BC4U || eTF == eTF_BC4S || eTF == eTF_CTX1 || eTF == eTF_BC6UH || eTF == eTF_BC6SH || eTF == eTF_BC7 || eTF == eTF_EAC_R11 || eTF == eTF_EAC_RG11 || eTF == eTF_ETC2 || eTF == eTF_ETC2A) - { - return Vec2i(4, 4); - } - // Apple requires the following for the texture: - // Height and width must be a power of 2 - // Height and width must be at least 8 - // Must be square - switch (eTF) - { - case eTF_PVRTC2: - return Vec2i(8, 4); - case eTF_PVRTC4: - return Vec2i(4, 4); - case eTF_ASTC_4x4: - return Vec2i(4, 4); - case eTF_ASTC_5x4: - return Vec2i(5, 4); - case eTF_ASTC_5x5: - return Vec2i(5, 5); - case eTF_ASTC_6x5: - return Vec2i(6, 5); - case eTF_ASTC_6x6: - return Vec2i(6, 6); - case eTF_ASTC_8x5: - return Vec2i(8, 5); - case eTF_ASTC_8x6: - return Vec2i(8, 6); - case eTF_ASTC_8x8: - return Vec2i(8, 8); - case eTF_ASTC_10x5: - return Vec2i(10, 5); - case eTF_ASTC_10x6: - return Vec2i(10, 6); - case eTF_ASTC_10x8: - return Vec2i(10, 8); - case eTF_ASTC_10x10: - return Vec2i(10, 10); - case eTF_ASTC_12x10: - return Vec2i(12, 10); - case eTF_ASTC_12x12: - return Vec2i(12, 12); - } - - return Vec2i(1, 1); - } - - inline int BytesPerBlock(ETEX_Format eTF) - { - switch (eTF) - { - case eTF_R8G8B8A8S: - return 32 / 8; - case eTF_R8G8B8A8: - return 32 / 8; - - case eTF_A8: - return 8 / 8; - case eTF_R8: - return 8 / 8; - case eTF_R8S: - return 8 / 8; - case eTF_R16: - return 16 / 8; - case eTF_R16U: - return 16 / 8; - case eTF_R16G16U: - return 32 / 8; - case eTF_R10G10B10A2UI: - return 32 / 8; - case eTF_R16F: - return 16 / 8; - case eTF_R32F: - return 32 / 8; - case eTF_R8G8: - return 16 / 8; - case eTF_R8G8S: - return 16 / 8; - case eTF_R16G16: - return 32 / 8; - case eTF_R16G16S: - return 32 / 8; - case eTF_R16G16F: - return 32 / 8; - case eTF_R11G11B10F: - return 32 / 8; - case eTF_R10G10B10A2: - return 32 / 8; - case eTF_R16G16B16A16: - return 64 / 8; - case eTF_R16G16B16A16S: - return 64 / 8; - case eTF_R16G16B16A16F: - return 64 / 8; - case eTF_R32G32B32A32F: - return 128 / 8; - - case eTF_R9G9B9E5: - return 32 / 8; - - case eTF_D16: - return 16 / 8; - case eTF_D24S8: - return 32 / 8; - case eTF_D32F: - return 32 / 8; - case eTF_D32FS8: - return 32 / 8; - - case eTF_B5G6R5: - return 16 / 8; - case eTF_B5G5R5: - return 16 / 8; - case eTF_B4G4R4A4: - return 16 / 8; - - case eTF_A8L8: - return 16 / 8; - case eTF_L8: - return 8 / 8; - case eTF_L8V8U8: - return 24 / 8; - case eTF_B8G8R8: - return 24 / 8; - case eTF_L8V8U8X8: - return 32 / 8; - case eTF_B8G8R8X8: - return 32 / 8; - case eTF_B8G8R8A8: - return 32 / 8; - - case eTF_CTX1: - case eTF_BC1: - case eTF_BC4U: - case eTF_BC4S: - case eTF_ETC2: - case eTF_EAC_R11: - return 8; - - case eTF_BC2: - case eTF_BC3: - case eTF_BC5U: - case eTF_BC5S: - case eTF_BC6UH: - case eTF_BC6SH: - case eTF_BC7: - case eTF_ETC2A: - case eTF_EAC_RG11: - return 16; - - case eTF_PVRTC2: - case eTF_PVRTC4: - return 8; - - case eTF_ASTC_4x4: - case eTF_ASTC_5x4: - case eTF_ASTC_5x5: - case eTF_ASTC_6x5: - case eTF_ASTC_6x6: - case eTF_ASTC_8x5: - case eTF_ASTC_8x6: - case eTF_ASTC_8x8: - case eTF_ASTC_10x5: - case eTF_ASTC_10x6: - case eTF_ASTC_10x8: - case eTF_ASTC_10x10: - case eTF_ASTC_12x10: - case eTF_ASTC_12x12: - return 16; - default: - assert(0); - } - return 0; - } - - - inline bool IsBlockCompressed(ETEX_Format eTF) - { - return (eTF == eTF_BC1 || - eTF == eTF_BC2 || - eTF == eTF_BC3 || - eTF == eTF_BC4U || - eTF == eTF_BC4S || - eTF == eTF_BC5S || - eTF == eTF_BC5U || - eTF == eTF_BC6UH || - eTF == eTF_BC6SH || - eTF == eTF_BC7 || - eTF == eTF_CTX1 || - eTF == eTF_ETC2 || - eTF == eTF_EAC_R11 || - eTF == eTF_ETC2A || - eTF == eTF_EAC_RG11 || - eTF == eTF_PVRTC2 || - eTF == eTF_PVRTC4 || - eTF == eTF_ASTC_4x4 || - eTF == eTF_ASTC_5x4 || - eTF == eTF_ASTC_5x5 || - eTF == eTF_ASTC_6x5 || - eTF == eTF_ASTC_6x6 || - eTF == eTF_ASTC_8x5 || - eTF == eTF_ASTC_8x6 || - eTF == eTF_ASTC_8x8 || - eTF == eTF_ASTC_10x5 || - eTF == eTF_ASTC_10x6 || - eTF == eTF_ASTC_10x8 || - eTF == eTF_ASTC_10x10 || - eTF == eTF_ASTC_12x10 || - eTF == eTF_ASTC_12x12 - ); - } - - bool IsRangeless(ETEX_Format eTF); - - bool IsQuantized(ETEX_Format eTF); - - // Added this code from Image, as it has less dependencies here. - // Warning: duplicate code. - inline const char* NameForTextureFormat(ETEX_Format ETF) - { - switch (ETF) - { - case eTF_Unknown: - return "Unknown"; - - case eTF_R8G8B8A8S: - return "R8G8B8A8S"; - case eTF_R8G8B8A8: - return "R8G8B8A8"; - - case eTF_A8: - return "A8"; - case eTF_R8: - return "R8"; - case eTF_R8S: - return "R8S"; - case eTF_R16: - return "R16"; - case eTF_R16F: - return "R16F"; - case eTF_R32F: - return "R32F"; - case eTF_R8G8: - return "R8G8"; - case eTF_R8G8S: - return "R8G8S"; - case eTF_R16G16: - return "R16G16"; - case eTF_R16G16S: - return "R16G16S"; - case eTF_R16G16F: - return "R16G16F"; - case eTF_R11G11B10F: - return "R11G11B10F"; - case eTF_R10G10B10A2: - return "R10G10B10A2"; - case eTF_R16G16B16A16: - return "R16G16B16A16"; - case eTF_R16G16B16A16S: - return "R16G16B16A16S"; - case eTF_R16G16B16A16F: - return "R16G16B16A16F"; - case eTF_R32G32B32A32F: - return "R32G32B32A32F"; - - case eTF_CTX1: - return "CTX1"; - case eTF_BC1: - return "BC1"; - case eTF_BC2: - return "BC2"; - case eTF_BC3: - return "BC3"; - case eTF_BC4U: - return "BC4"; - case eTF_BC4S: - return "BC4S"; - case eTF_BC5U: - return "BC5"; - case eTF_BC5S: - return "BC5S"; - case eTF_BC6UH: - return "BC6UH"; - case eTF_BC6SH: - return "BC6SH"; - case eTF_BC7: - return "BC7"; - case eTF_R9G9B9E5: - return "R9G9B9E5"; - - case eTF_D16: - return "D16"; - case eTF_D24S8: - return "D24S8"; - case eTF_D32F: - return "D32F"; - case eTF_D32FS8: - return "D32FS8"; - - case eTF_B5G6R5: - return "R5G5B5"; - case eTF_B5G5R5: - return "R5G6B5"; - case eTF_B4G4R4A4: - return "B4G4R4A4"; - - case eTF_EAC_R11: - return "EAC_R11"; - case eTF_EAC_RG11: - return "EAC_RG11"; - case eTF_ETC2: - return "ETC2"; - case eTF_ETC2A: - return "ETC2A"; - - case eTF_PVRTC2: - return "PVRTC2"; - case eTF_PVRTC4: - return "PVRTC4"; - - case eTF_ASTC_4x4: - return "ASTC_4x4"; - case eTF_ASTC_5x4: - return "ASTC_5x4"; - case eTF_ASTC_5x5: - return "ASTC_5x5"; - case eTF_ASTC_6x5: - return "ASTC_6x5"; - case eTF_ASTC_6x6: - return "ASTC_6x6"; - case eTF_ASTC_8x5: - return "ASTC_8x5"; - case eTF_ASTC_8x6: - return "ASTC_8x6"; - case eTF_ASTC_8x8: - return "ASTC_8x8"; - case eTF_ASTC_10x5: - return "ASTC_10x5"; - case eTF_ASTC_10x6: - return "ASTC_10x6"; - case eTF_ASTC_10x8: - return "ASTC_10x8"; - case eTF_ASTC_10x10: - return "ASTC_10x10"; - case eTF_ASTC_12x10: - return "ASTC_12x10"; - case eTF_ASTC_12x12: - return "ASTC_12x12"; - - case eTF_A8L8: - return "A8L8"; - case eTF_L8: - return "L8"; - case eTF_L8V8U8: - return "L8V8U8"; - case eTF_B8G8R8: - return "B8G8R8"; - case eTF_L8V8U8X8: - return "L8V8U8X8"; - case eTF_B8G8R8X8: - return "B8G8R8X8"; - case eTF_B8G8R8A8: - return "B8G8R8A8"; - - default: - assert(0); // pass through for better behaviour in non debug - } - - return "Unknown"; - } - - // Added this code from Image, as it has less dependencies here. - // Warning: duplicate code. - inline ETEX_Format TextureFormatForName(const char* sETF) - { - if (!azstricmp(sETF, "Unknown")) - { - return eTF_Unknown; - } - - if (!azstricmp(sETF, "R8G8B8A8S")) - { - return eTF_R8G8B8A8S; - } - if (!azstricmp(sETF, "R8G8B8A8")) - { - return eTF_R8G8B8A8; - } - - if (!azstricmp(sETF, "A8")) - { - return eTF_A8; - } - if (!azstricmp(sETF, "R8")) - { - return eTF_R8; - } - if (!azstricmp(sETF, "R8S")) - { - return eTF_R8S; - } - if (!azstricmp(sETF, "R16")) - { - return eTF_R16; - } - if (!azstricmp(sETF, "R16F")) - { - return eTF_R16F; - } - if (!azstricmp(sETF, "R32F")) - { - return eTF_R32F; - } - if (!azstricmp(sETF, "R8G8")) - { - return eTF_R8G8; - } - if (!azstricmp(sETF, "R8G8S")) - { - return eTF_R8G8S; - } - if (!azstricmp(sETF, "R16G16")) - { - return eTF_R16G16; - } - if (!azstricmp(sETF, "R16G16S")) - { - return eTF_R16G16S; - } - if (!azstricmp(sETF, "R16G16F")) - { - return eTF_R16G16F; - } - if (!azstricmp(sETF, "R11G11B10F")) - { - return eTF_R11G11B10F; - } - if (!azstricmp(sETF, "R10G10B10A2")) - { - return eTF_R10G10B10A2; - } - if (!azstricmp(sETF, "R16G16B16A16")) - { - return eTF_R16G16B16A16; - } - if (!azstricmp(sETF, "R16G16B16A16S")) - { - return eTF_R16G16B16A16S; - } - if (!azstricmp(sETF, "R16G16B16A16F")) - { - return eTF_R16G16B16A16F; - } - if (!azstricmp(sETF, "R32G32B32A32F")) - { - return eTF_R32G32B32A32F; - } - - if (!azstricmp(sETF, "CTX1")) - { - return eTF_CTX1; - } - if (!azstricmp(sETF, "BC1")) - { - return eTF_BC1; - } - if (!azstricmp(sETF, "BC2")) - { - return eTF_BC2; - } - if (!azstricmp(sETF, "BC3")) - { - return eTF_BC3; - } - if (!azstricmp(sETF, "BC4")) - { - return eTF_BC4U; - } - if (!azstricmp(sETF, "BC4S")) - { - return eTF_BC4S; - } - if (!azstricmp(sETF, "BC5")) - { - return eTF_BC5U; - } - if (!azstricmp(sETF, "BC5S")) - { - return eTF_BC5S; - } - if (!azstricmp(sETF, "BC6UH")) - { - return eTF_BC6UH; - } - if (!azstricmp(sETF, "BC6SH")) - { - return eTF_BC6SH; - } - if (!azstricmp(sETF, "BC7")) - { - return eTF_BC7; - } - if (!azstricmp(sETF, "R9G9B9E5")) - { - return eTF_R9G9B9E5; - } - - if (!azstricmp(sETF, "D16")) - { - return eTF_D16; - } - if (!azstricmp(sETF, "D24S8")) - { - return eTF_D24S8; - } - if (!azstricmp(sETF, "D32F")) - { - return eTF_D32F; - } - if (!azstricmp(sETF, "D32FS8")) - { - return eTF_D32FS8; - } - - if (!azstricmp(sETF, "R5G5B5")) - { - return eTF_B5G6R5; - } - if (!azstricmp(sETF, "R5G6B5")) - { - return eTF_B5G5R5; - } - if (!azstricmp(sETF, "B4G4R4A4")) - { - return eTF_B4G4R4A4; - } - - if (!azstricmp(sETF, "EAC_R11")) - { - return eTF_EAC_R11; - } - if (!azstricmp(sETF, "EAC_RG11")) - { - return eTF_EAC_RG11; - } - if (!azstricmp(sETF, "ETC2")) - { - return eTF_ETC2; - } - if (!azstricmp(sETF, "ETC2A")) - { - return eTF_ETC2A; - } - - if (!azstricmp(sETF, "PVRTC2")) - { - return eTF_PVRTC2; - } - if (!azstricmp(sETF, "PVRTC4")) - { - return eTF_PVRTC4; - } - - if (!azstricmp(sETF, "ASTC_4x4")) - { - return eTF_ASTC_4x4; - } - if (!azstricmp(sETF, "ASTC_5x4")) - { - return eTF_ASTC_5x4; - } - if (!azstricmp(sETF, "ASTC_5x5")) - { - return eTF_ASTC_5x5; - } - if (!azstricmp(sETF, "ASTC_6x5")) - { - return eTF_ASTC_6x5; - } - if (!azstricmp(sETF, "ASTC_6x6")) - { - return eTF_ASTC_6x6; - } - if (!azstricmp(sETF, "ASTC_8x5")) - { - return eTF_ASTC_8x5; - } - if (!azstricmp(sETF, "ASTC_8x6")) - { - return eTF_ASTC_8x6; - } - if (!azstricmp(sETF, "ASTC_8x8")) - { - return eTF_ASTC_8x8; - } - if (!azstricmp(sETF, "ASTC_10x5")) - { - return eTF_ASTC_10x5; - } - if (!azstricmp(sETF, "ASTC_10x6")) - { - return eTF_ASTC_10x6; - } - if (!azstricmp(sETF, "ASTC_10x8")) - { - return eTF_ASTC_10x8; - } - if (!azstricmp(sETF, "ASTC_10x10")) - { - return eTF_ASTC_10x10; - } - if (!azstricmp(sETF, "ASTC_12x10")) - { - return eTF_ASTC_12x10; - } - if (!azstricmp(sETF, "ASTC_12x12")) - { - return eTF_ASTC_12x12; - } - - if (!azstricmp(sETF, "A8L8")) - { - return eTF_A8L8; - } - if (!azstricmp(sETF, "L8")) - { - return eTF_L8; - } - if (!azstricmp(sETF, "L8V8U8")) - { - return eTF_L8V8U8; - } - if (!azstricmp(sETF, "B8G8R8")) - { - return eTF_B8G8R8; - } - if (!azstricmp(sETF, "L8V8U8X8")) - { - return eTF_L8V8U8X8; - } - if (!azstricmp(sETF, "B8G8R8X8")) - { - return eTF_B8G8R8X8; - } - if (!azstricmp(sETF, "B8G8R8A8")) - { - return eTF_B8G8R8A8; - } - - if (!azstricmp(sETF, "V8U8")) - { - return eTF_R8G8S; - } - if (!azstricmp(sETF, "V16U16")) - { - return eTF_R16G16S; - } - - if (!azstricmp(sETF, "DXT1")) - { - return eTF_BC1; - } - if (!azstricmp(sETF, "DXT3")) - { - return eTF_BC2; - } - if (!azstricmp(sETF, "DXT5")) - { - return eTF_BC3; - } - if (!azstricmp(sETF, "ATI1")) - { - return eTF_BC4U; - } - if (!azstricmp(sETF, "ATI2")) - { - return eTF_BC5U; - } - if (!azstricmp(sETF, "3DCp")) - { - return eTF_BC4U; - } - if (!azstricmp(sETF, "3DC")) - { - return eTF_BC5U; - } - if (!azstricmp(sETF, "RGBE")) - { - return eTF_R9G9B9E5; - } - - assert (0); - return eTF_Unknown; - } - - // Added this code from Image, as it has less dependencies here. - // Warning: duplicate code. - inline const char* NameForTextureType(ETEX_Type eTT) - { - const char* sETT; - switch (eTT) - { - case eTT_1D: - sETT = "1D"; - break; - case eTT_2D: - sETT = "2D"; - break; - case eTT_2DArray: - sETT = "2D array"; - break; - case eTT_2DMS: - sETT = "2D multi-sampled"; - break; - case eTT_3D: - sETT = "3D"; - break; - case eTT_Cube: - sETT = "Cube"; - break; - case eTT_CubeArray: - sETT = "CubeArray"; - break; - case eTT_Auto2D: - sETT = "Auto2D"; - break; - case eTT_Dyn2D: - sETT = "Dyn2D"; - break; - default: - assert(0); - sETT = "Unknown"; // for better behaviour in non debug - break; - } - return sETT; - } - - inline ETEX_Type TextureTypeForName(const char* sETT) - { - if (!azstricmp(sETT, "1D")) - { - return eTT_1D; - } - if (!azstricmp(sETT, "2D")) - { - return eTT_2D; - } - if (!azstricmp(sETT, "3D")) - { - return eTT_3D; - } - if (!azstricmp(sETT, "Cube")) - { - return eTT_Cube; - } - if (!azstricmp(sETT, "Auto2D")) - { - return eTT_Auto2D; - } - if (!azstricmp(sETT, "Dyn2D")) - { - return eTT_Dyn2D; - } - if (!azstricmp(sETT, "User")) - { - return eTT_User; - } - assert(0); - return eTT_2D; - } - - inline bool HasAlphaForName(const char* sETF) - { - if (!azstricmp(sETF, "R8G8B8A8S")) - { - return true; - } - if (!azstricmp(sETF, "R8G8B8A8")) - { - return true; - } - if (!azstricmp(sETF, "A8")) - { - if (!azstricmp(sETF, "A8L8")) - { - if (!azstricmp(sETF, "BC1") || !azstricmp(sETF, "DXT1")) - { - if (!azstricmp(sETF, "BC2") || !azstricmp(sETF, "DXT3")) - { - if (!azstricmp(sETF, "BC3") || !azstricmp(sETF, "DXT5")) - { - if (!azstricmp(sETF, "BC7")) - { - if (!azstricmp(sETF, "A8")) - { - return true; - } - } - } - } - } - } - } - if (!azstricmp(sETF, "R10G10B10A2")) - { - return true; - } - if (!azstricmp(sETF, "R16G16B16A16")) - { - return true; - } - if (!azstricmp(sETF, "R16G16B16A16S")) - { - return true; - } - if (!azstricmp(sETF, "R16G16B16A16F")) - { - return true; - } - if (!azstricmp(sETF, "R32G32B32A32F")) - { - return true; - } - - if (!azstricmp(sETF, "BC2")) - { - return true; - } - if (!azstricmp(sETF, "BC3")) - { - return true; - } - if (!azstricmp(sETF, "BC7")) - { - return true; - } - - if (!azstricmp(sETF, "B4G4R4A4")) - { - return true; - } - - if (!azstricmp(sETF, "ETC2A")) - { - return true; - } - - if (!azstricmp(sETF, "A8L8")) - { - return true; - } - if (!azstricmp(sETF, "B8G8R8A8")) - { - return true; - } - - if (!azstricmp(sETF, "DXT3")) - { - return true; - } - if (!azstricmp(sETF, "DXT5")) - { - return true; - } - - return false; - } - - inline bool HasAlphaForTextureFormat(ETEX_Format ETF) - { - if (ETF == eTF_R8G8B8A8S) - { - return true; - } - if (ETF == eTF_R8G8B8A8) - { - return true; - } - - if (ETF == eTF_A8) - { - return true; - } - if (ETF == eTF_R10G10B10A2) - { - return true; - } - if (ETF == eTF_R16G16B16A16) - { - return true; - } - if (ETF == eTF_R16G16B16A16S) - { - return true; - } - if (ETF == eTF_R16G16B16A16F) - { - return true; - } - if (ETF == eTF_R32G32B32A32F) - { - return true; - } - - if (ETF == eTF_BC2) - { - return true; - } - if (ETF == eTF_BC3) - { - return true; - } - if (ETF == eTF_BC7) - { - return true; - } - - if (ETF == eTF_B4G4R4A4) - { - return true; - } - - if (ETF == eTF_ETC2A) - { - return true; - } - - if (ETF == eTF_A8L8) - { - return true; - } - if (ETF == eTF_B8G8R8A8) - { - return true; - } - - return false; - } - - inline const char* NameForDesc(const DDS_PIXELFORMAT& ddspf, DWORD /*DXGI_FORMAT*/ dxgif); -}; - -namespace DDSFormats -{ - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_DX10 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_DXT1 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_DXT2 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_DXT3 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_DXT4 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_DXT5 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_CTX1 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('C', 'T', 'X', '1'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_3DC = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_3DCP = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_EAC_R11 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('E', 'A', 'R', ' '), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_EAC_RG11 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('E', 'A', 'R', 'G'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ETC2 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('E', 'T', '2', ' '), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ETC2A = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('E', 'T', '2', 'A'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_PVRTC2 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('P', 'V', 'R', '2'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_PVRTC4 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('P', 'V', 'R', '4'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_4x4 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', '4', '4'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_5x4 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', '5', '4'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_5x5 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', '5', '5'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_6x5 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', '6', '5'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_6x6 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', '6', '6'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_8x5 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', '8', '5'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_8x6 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', '8', '6'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_10x5 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', 'A', '5'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_10x6 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', 'A', '6'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_8x8 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', '8', '8'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_10x8 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', 'A', '8'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_10x10 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', 'A', 'A'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_12x10 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', 'C', 'A'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_ASTC_12x12 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('A', 'S', 'C', 'C'), 0, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_R32F = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, DDS_FOURCC_R32F, 32, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_G32R32F = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, DDS_FOURCC_G32R32F, 64, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_A32B32G32R32F = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, DDS_FOURCC_A32B32G32R32F, 128, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_R16F = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, DDS_FOURCC_R16F, 16, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_G16R16F = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, DDS_FOURCC_G16R16F, 32, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_A16B16G16R16F = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, DDS_FOURCC_A16B16G16R16F, 64, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_U16 = // unofficial - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_SIGNED, 0, 16, 0x0000ffff, 0x00000000, 0x00000000, 0x00000000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_V16U16 = // unofficial - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_SIGNED, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_Q16W16V16U16 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, DDS_FOURCC_Q16W16V16U16, 64, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_R16 = // unofficial - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0000ffff, 0x00000000, 0x00000000, 0x00000000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_G16R16 = // unofficial - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_A16B16G16R16 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_FOURCC, DDS_FOURCC_A16B16G16R16, 64, 0, 0, 0, 0 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_A8B8G8R8 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_A8R8G8B8 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_A1R5G5B5 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_A4R4G4B4 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_R8G8B8 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_X8R8G8B8 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_R5G6B5 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_A8 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_A, 0, 8, 0x00000000, 0x00000000, 0x00000000, 0x000000ff }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_L8 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0x000000ff, 0x000000ff, 0x000000ff, 0x00000000 }; - - const CImageExtensionHelper::DDS_PIXELFORMAT DDSPF_A8L8 = - { sizeof(CImageExtensionHelper::DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff }; - - inline ETEX_Format GetFormatByDesc(const CImageExtensionHelper::DDS_PIXELFORMAT& ddspf) - { - if (ddspf.dwFourCC == DDSPF_DXT1.dwFourCC) - { - return eTF_BC1; - } - else if (ddspf.dwFourCC == DDSPF_DXT3.dwFourCC) - { - return eTF_BC2; - } - else if (ddspf.dwFourCC == DDSPF_DXT5.dwFourCC) - { - return eTF_BC3; - } - else if (ddspf.dwFourCC == DDSPF_3DCP.dwFourCC) - { - return eTF_BC4U; - } - else if (ddspf.dwFourCC == DDSPF_3DC.dwFourCC) - { - return eTF_BC5U; - } - else if (ddspf.dwFourCC == DDSPF_CTX1.dwFourCC) - { - return eTF_CTX1; - } - else if (ddspf.dwFourCC == DDSPF_R32F.dwFourCC) - { - return eTF_R32F; - } - // else if( ddspf.dwFourCC == DDSPF_G32R32F.dwFourCC) - // return eTF_R32G32F; // TODO: add to engine - else if (ddspf.dwFourCC == DDSPF_A32B32G32R32F.dwFourCC) - { - return eTF_R32G32B32A32F; - } - else if (ddspf.dwFourCC == DDSPF_R16F.dwFourCC) - { - return eTF_R16F; - } - else if (ddspf.dwFourCC == DDSPF_G16R16F.dwFourCC) - { - return eTF_R16G16F; - } - else if (ddspf.dwFourCC == DDSPF_A16B16G16R16F.dwFourCC) - { - return eTF_R16G16B16A16F; - } - // else if( ddspf == DDSPF_U16) - // return eTF_R16S; // TODO: add to engine - else if (ddspf == DDSPF_V16U16) - { - return eTF_R16G16S; - } - else if (ddspf.dwFourCC == DDSPF_Q16W16V16U16.dwFourCC) - { - return eTF_R16G16B16A16S; - } - else if (ddspf == DDSPF_R16) - { - return eTF_R16; - } - else if (ddspf == DDSPF_G16R16) - { - return eTF_R16G16; - } - else if (ddspf.dwFourCC == DDSPF_A16B16G16R16.dwFourCC) - { - return eTF_R16G16B16A16; - } - else if (ddspf.dwFourCC == DDSPF_EAC_R11.dwFourCC) - { - return eTF_EAC_R11; - } - else if (ddspf.dwFourCC == DDSPF_EAC_RG11.dwFourCC) - { - return eTF_EAC_RG11; - } - else if (ddspf.dwFourCC == DDSPF_ETC2.dwFourCC) - { - return eTF_ETC2; - } - else if (ddspf.dwFourCC == DDSPF_ETC2A.dwFourCC) - { - return eTF_ETC2A; - } - else if (ddspf.dwFlags == DDS_RGBA && ddspf.dwRGBBitCount == 32 && ddspf.dwRBitMask == 0x000000ff && ddspf.dwABitMask == 0xff000000) - { - return eTF_R8G8B8A8; - } - else if (ddspf.dwFlags == DDS_RGBA && ddspf.dwRGBBitCount == 32 && ddspf.dwRBitMask == 0x00ff0000 && ddspf.dwABitMask == 0xff000000) - { - return eTF_B8G8R8A8; - } - else if (ddspf.dwFlags == DDS_RGB && ddspf.dwRGBBitCount == 32 && ddspf.dwRBitMask == 0x00ff0000) - { - return eTF_B8G8R8X8; - } - else if (ddspf.dwFlags == DDS_RGBA && ddspf.dwRGBBitCount == 16) - { - return eTF_B4G4R4A4; - } - else if (ddspf.dwFlags == DDS_RGB && ddspf.dwRGBBitCount == 24) - { - return eTF_B8G8R8; - } - else if (ddspf.dwFlags == DDS_LUMINANCEA && ddspf.dwRGBBitCount == 8) - { - return eTF_A8L8; - } - else if (ddspf.dwFlags == DDS_LUMINANCE && ddspf.dwRGBBitCount == 8) - { - return eTF_L8; - } - else if ((ddspf.dwFlags == DDS_A || ddspf.dwFlags == DDS_A_ONLY || ddspf.dwFlags == (DDS_A | DDS_A_ONLY)) && ddspf.dwRGBBitCount == 8) - { - return eTF_A8; - } - else if (ddspf.dwFourCC == DDSPF_PVRTC2.dwFourCC) - { - return eTF_PVRTC2; - } - else if (ddspf.dwFourCC == DDSPF_PVRTC4.dwFourCC) - { - return eTF_PVRTC4; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_4x4.dwFourCC) - { - return eTF_ASTC_4x4; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_5x4.dwFourCC) - { - return eTF_ASTC_5x4; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_5x5.dwFourCC) - { - return eTF_ASTC_5x5; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_6x5.dwFourCC) - { - return eTF_ASTC_6x5; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_6x6.dwFourCC) - { - return eTF_ASTC_6x6; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_8x5.dwFourCC) - { - return eTF_ASTC_8x5; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_8x6.dwFourCC) - { - return eTF_ASTC_8x6; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_8x8.dwFourCC) - { - return eTF_ASTC_8x8; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_10x5.dwFourCC) - { - return eTF_ASTC_10x5; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_10x6.dwFourCC) - { - return eTF_ASTC_10x6; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_10x8.dwFourCC) - { - return eTF_ASTC_10x8; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_10x10.dwFourCC) - { - return eTF_ASTC_10x10; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_12x10.dwFourCC) - { - return eTF_ASTC_12x10; - } - else if (ddspf.dwFourCC == DDSPF_ASTC_12x12.dwFourCC) - { - return eTF_ASTC_12x12; - } - - assert(0); - return eTF_Unknown; - } - - inline ETEX_Format GetFormatByDesc(const CImageExtensionHelper::DDS_PIXELFORMAT& ddspf, const DWORD /*DXGI_FORMAT*/ dxgif) - { - // 'DX10' indicates the format is not in the FourCC, but in the extended header - if (ddspf.dwFourCC == DDSPF_DX10.dwFourCC) - { -#if defined(CRY_DDS_DX10_SUPPORT) - switch (dxgif) - { - case DXGI_FORMAT_R8G8B8A8_TYPELESS: - return eTF_R8G8B8A8; - case DXGI_FORMAT_R8G8B8A8_UNORM: - return eTF_R8G8B8A8; - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - return eTF_R8G8B8A8; - case DXGI_FORMAT_R8G8B8A8_SNORM: - return eTF_R8G8B8A8S; - - case DXGI_FORMAT_A8_UNORM: - return eTF_A8; - case DXGI_FORMAT_R8_UNORM: - return eTF_R8; - case DXGI_FORMAT_R8_SNORM: - return eTF_R8S; - case DXGI_FORMAT_R16_UNORM: - return eTF_R16; - // case DXGI_FORMAT_R16_SNORM: return eTF_R16S; - case DXGI_FORMAT_R16_FLOAT: - return eTF_R16F; - case DXGI_FORMAT_R16_TYPELESS: - return eTF_R16F; // arbitrary choice for F - case DXGI_FORMAT_R32_FLOAT: - return eTF_R32F; - case DXGI_FORMAT_R32_TYPELESS: - return eTF_R32F; - case DXGI_FORMAT_R8G8_UNORM: - return eTF_R8G8; - case DXGI_FORMAT_R8G8_SNORM: - return eTF_R8G8S; - case DXGI_FORMAT_R16G16_UNORM: - return eTF_R16G16; - case DXGI_FORMAT_R16G16_SNORM: - return eTF_R16G16S; - case DXGI_FORMAT_R16G16_FLOAT: - return eTF_R16G16F; - // case DXGI_FORMAT_R32G32_FLOAT: return eTF_R32G32F; - case DXGI_FORMAT_R11G11B10_FLOAT: - return eTF_R11G11B10F; - case DXGI_FORMAT_R10G10B10A2_UNORM: - return eTF_R10G10B10A2; - case DXGI_FORMAT_R16G16B16A16_UNORM: - return eTF_R16G16B16A16; - case DXGI_FORMAT_R16G16B16A16_SNORM: - return eTF_R16G16B16A16S; - case DXGI_FORMAT_R16G16B16A16_FLOAT: - return eTF_R16G16B16A16F; - case DXGI_FORMAT_R32G32B32A32_FLOAT: - return eTF_R32G32B32A32F; - - case DXGI_FORMAT_BC1_TYPELESS: - return eTF_BC1; - case DXGI_FORMAT_BC1_UNORM: - return eTF_BC1; - case DXGI_FORMAT_BC1_UNORM_SRGB: - return eTF_BC1; - case DXGI_FORMAT_BC2_TYPELESS: - return eTF_BC2; - case DXGI_FORMAT_BC2_UNORM: - return eTF_BC2; - case DXGI_FORMAT_BC2_UNORM_SRGB: - return eTF_BC2; - case DXGI_FORMAT_BC3_TYPELESS: - return eTF_BC3; - case DXGI_FORMAT_BC3_UNORM: - return eTF_BC3; - case DXGI_FORMAT_BC3_UNORM_SRGB: - return eTF_BC3; - case DXGI_FORMAT_BC4_TYPELESS: - return eTF_BC4U; - case DXGI_FORMAT_BC4_UNORM: - return eTF_BC4U; - case DXGI_FORMAT_BC4_SNORM: - return eTF_BC4S; - case DXGI_FORMAT_BC5_TYPELESS: - return eTF_BC5U; - case DXGI_FORMAT_BC5_UNORM: - return eTF_BC5U; - case DXGI_FORMAT_BC5_SNORM: - return eTF_BC5S; - case DXGI_FORMAT_BC6H_UF16: - return eTF_BC6UH; - case DXGI_FORMAT_BC6H_SF16: - return eTF_BC6SH; - case DXGI_FORMAT_BC7_TYPELESS: - return eTF_BC7; - case DXGI_FORMAT_BC7_UNORM: - return eTF_BC7; - case DXGI_FORMAT_BC7_UNORM_SRGB: - return eTF_BC7; - case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: - return eTF_R9G9B9E5; - - // only available as hardware format under DX11.1 with DXGI 1.2 - case DXGI_FORMAT_B5G6R5_UNORM: - return eTF_B5G6R5; - case DXGI_FORMAT_B5G5R5A1_UNORM: - return eTF_B5G5R5; - // case DXGI_FORMAT_B4G4R4A4_UNORM: return eTF_B4G4R4A4; - -#if defined(OPENGL) || defined(CRY_USE_METAL) - // only available as hardware format under OpenGL - case DXGI_FORMAT_EAC_R11_TYPELESS: - return eTF_EAC_R11; - case DXGI_FORMAT_EAC_R11_UNORM: - return eTF_EAC_R11; - case DXGI_FORMAT_EAC_R11_SNORM: - return eTF_EAC_R11; - case DXGI_FORMAT_EAC_RG11_TYPELESS: - return eTF_EAC_RG11; - case DXGI_FORMAT_EAC_RG11_UNORM: - return eTF_EAC_RG11; - case DXGI_FORMAT_EAC_RG11_SNORM: - return eTF_EAC_RG11; - case DXGI_FORMAT_ETC2_TYPELESS: - return eTF_ETC2; - case DXGI_FORMAT_ETC2_UNORM: - return eTF_ETC2; - case DXGI_FORMAT_ETC2_UNORM_SRGB: - return eTF_ETC2; - case DXGI_FORMAT_ETC2A_TYPELESS: - return eTF_ETC2A; - case DXGI_FORMAT_ETC2A_UNORM: - return eTF_ETC2A; - case DXGI_FORMAT_ETC2A_UNORM_SRGB: - return eTF_ETC2A; -#endif //defined(OPENGL) - -#ifdef CRY_USE_METAL - case DXGI_FORMAT_PVRTC2_TYPELESS: - return eTF_PVRTC2; - case DXGI_FORMAT_PVRTC2_UNORM: - return eTF_PVRTC2; - case DXGI_FORMAT_PVRTC2_UNORM_SRGB: - return eTF_PVRTC2; - case DXGI_FORMAT_PVRTC4_TYPELESS: - return eTF_PVRTC4; - case DXGI_FORMAT_PVRTC4_UNORM: - return eTF_PVRTC4; - case DXGI_FORMAT_PVRTC4_UNORM_SRGB: - return eTF_PVRTC4; -#endif -#if defined(ANDROID) //|| defined(CRY_USE_METAL) - case DXGI_FORMAT_ASTC_4x4_TYPELESS: - return eTF_ASTC_4x4; - case DXGI_FORMAT_ASTC_4x4_UNORM: - return eTF_ASTC_4x4; - case DXGI_FORMAT_ASTC_4x4_UNORM_SRGB: - return eTF_ASTC_4x4; - case DXGI_FORMAT_ASTC_5x4_TYPELESS: - return eTF_ASTC_5x4; - case DXGI_FORMAT_ASTC_5x4_UNORM: - return eTF_ASTC_5x4; - case DXGI_FORMAT_ASTC_5x4_UNORM_SRGB: - return eTF_ASTC_5x4; - case DXGI_FORMAT_ASTC_5x5_TYPELESS: - return eTF_ASTC_5x5; - case DXGI_FORMAT_ASTC_5x5_UNORM: - return eTF_ASTC_5x5; - case DXGI_FORMAT_ASTC_5x5_UNORM_SRGB: - return eTF_ASTC_5x5; - case DXGI_FORMAT_ASTC_6x5_TYPELESS: - return eTF_ASTC_6x5; - case DXGI_FORMAT_ASTC_6x5_UNORM: - return eTF_ASTC_6x5; - case DXGI_FORMAT_ASTC_6x5_UNORM_SRGB: - return eTF_ASTC_6x5; - case DXGI_FORMAT_ASTC_6x6_TYPELESS: - return eTF_ASTC_6x6; - case DXGI_FORMAT_ASTC_6x6_UNORM: - return eTF_ASTC_6x6; - case DXGI_FORMAT_ASTC_6x6_UNORM_SRGB: - return eTF_ASTC_6x6; - case DXGI_FORMAT_ASTC_8x5_TYPELESS: - return eTF_ASTC_8x5; - case DXGI_FORMAT_ASTC_8x5_UNORM: - return eTF_ASTC_8x5; - case DXGI_FORMAT_ASTC_8x5_UNORM_SRGB: - return eTF_ASTC_8x5; - case DXGI_FORMAT_ASTC_8x6_TYPELESS: - return eTF_ASTC_8x6; - case DXGI_FORMAT_ASTC_8x6_UNORM: - return eTF_ASTC_8x6; - case DXGI_FORMAT_ASTC_8x6_UNORM_SRGB: - return eTF_ASTC_8x6; - case DXGI_FORMAT_ASTC_8x8_TYPELESS: - return eTF_ASTC_8x8; - case DXGI_FORMAT_ASTC_8x8_UNORM: - return eTF_ASTC_8x8; - case DXGI_FORMAT_ASTC_8x8_UNORM_SRGB: - return eTF_ASTC_8x8; - case DXGI_FORMAT_ASTC_10x5_TYPELESS: - return eTF_ASTC_10x5; - case DXGI_FORMAT_ASTC_10x5_UNORM: - return eTF_ASTC_10x5; - case DXGI_FORMAT_ASTC_10x5_UNORM_SRGB: - return eTF_ASTC_10x5; - case DXGI_FORMAT_ASTC_10x6_TYPELESS: - return eTF_ASTC_10x6; - case DXGI_FORMAT_ASTC_10x6_UNORM: - return eTF_ASTC_10x6; - case DXGI_FORMAT_ASTC_10x6_UNORM_SRGB: - return eTF_ASTC_10x6; - case DXGI_FORMAT_ASTC_10x8_TYPELESS: - return eTF_ASTC_10x8; - case DXGI_FORMAT_ASTC_10x8_UNORM: - return eTF_ASTC_10x8; - case DXGI_FORMAT_ASTC_10x8_UNORM_SRGB: - return eTF_ASTC_10x8; - case DXGI_FORMAT_ASTC_10x10_TYPELESS: - return eTF_ASTC_10x10; - case DXGI_FORMAT_ASTC_10x10_UNORM: - return eTF_ASTC_10x10; - case DXGI_FORMAT_ASTC_10x10_UNORM_SRGB: - return eTF_ASTC_10x10; - case DXGI_FORMAT_ASTC_12x10_TYPELESS: - return eTF_ASTC_12x10; - case DXGI_FORMAT_ASTC_12x10_UNORM: - return eTF_ASTC_12x10; - case DXGI_FORMAT_ASTC_12x10_UNORM_SRGB: - return eTF_ASTC_12x10; - case DXGI_FORMAT_ASTC_12x12_TYPELESS: - return eTF_ASTC_12x12; - case DXGI_FORMAT_ASTC_12x12_UNORM: - return eTF_ASTC_12x12; - case DXGI_FORMAT_ASTC_12x12_UNORM_SRGB: - return eTF_ASTC_12x12; -#endif - // only available as hardware format under DX9 - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - return eTF_B8G8R8A8; - case DXGI_FORMAT_B8G8R8A8_UNORM: - return eTF_B8G8R8A8; - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - return eTF_B8G8R8A8; - case DXGI_FORMAT_B8G8R8X8_TYPELESS: - return eTF_B8G8R8X8; - case DXGI_FORMAT_B8G8R8X8_UNORM: - return eTF_B8G8R8X8; - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - return eTF_B8G8R8X8; - } -#endif - return eTF_Unknown; - } - else - { - return GetFormatByDesc(ddspf); - } - } - - inline const bool IsNormalMap(const ETEX_Format eTF) - { - if (eTF == eTF_BC5U || eTF == eTF_BC5S || eTF == eTF_CTX1 || eTF == eTF_EAC_RG11) - { - return true; - } - return false; - } - - inline const bool IsSigned(const ETEX_Format eTF) - { - if (eTF == eTF_BC4S || eTF == eTF_BC5S || eTF == eTF_BC6SH || eTF == eTF_R8S || eTF == eTF_R8G8S || eTF == eTF_R16G16S || eTF == eTF_R8G8B8A8S || eTF == eTF_R16G16B16A16S) - { - return true; - } - return false; - } - - // Added this code from Image, as it has less dependencies here. - // Warning: duplicate code. - inline const CImageExtensionHelper::DDS_PIXELFORMAT& GetDescByFormat(const ETEX_Format eTF) - { - switch (eTF) - { - case eTF_BC1: - return DDSPF_DXT1; - case eTF_BC2: - return DDSPF_DXT3; - case eTF_BC3: - return DDSPF_DXT5; - case eTF_BC4U: - return DDSPF_3DCP; - case eTF_BC5U: - return DDSPF_3DC; - case eTF_CTX1: - return DDSPF_CTX1; - case eTF_R32F: - return DDSPF_R32F; - // case eTF_R32G32F: - // return DDSPF_G32R32F; - case eTF_R32G32B32A32F: - return DDSPF_A32B32G32R32F; - case eTF_R16F: - return DDSPF_R16F; - case eTF_R16G16F: - return DDSPF_G16R16F; - case eTF_R16G16B16A16F: - return DDSPF_A16B16G16R16F; - case eTF_R16: - return DDSPF_R16; - case eTF_R16G16: - return DDSPF_G16R16; - case eTF_R16G16B16A16: - return DDSPF_A16B16G16R16; - // case eTF_R16S: - // return DDSPF_U16; - case eTF_R16G16S: - return DDSPF_V16U16; - case eTF_R16G16B16A16S: - return DDSPF_Q16W16V16U16; - case eTF_B8G8R8: - case eTF_L8V8U8: - return DDSPF_R8G8B8; - case eTF_R8G8B8A8: - return DDSPF_A8B8G8R8; - case eTF_B8G8R8X8: - case eTF_L8V8U8X8: - return DDSPF_X8R8G8B8; - case eTF_B8G8R8A8: - return DDSPF_A8R8G8B8; - case eTF_B5G6R5: - return DDSPF_R5G6B5; - case eTF_A8: - return DDSPF_A8; - case eTF_L8: - return DDSPF_L8; - case eTF_A8L8: - return DDSPF_A8L8; - case eTF_EAC_R11: - return DDSPF_EAC_R11; - case eTF_EAC_RG11: - return DDSPF_EAC_RG11; - case eTF_ETC2: - return DDSPF_ETC2; - case eTF_ETC2A: - return DDSPF_ETC2A; - case eTF_PVRTC2: - return DDSPF_PVRTC2; - case eTF_PVRTC4: - return DDSPF_PVRTC4; - - case eTF_ASTC_4x4: - return DDSPF_ASTC_4x4; - case eTF_ASTC_5x4: - return DDSPF_ASTC_5x4; - case eTF_ASTC_5x5: - return DDSPF_ASTC_5x5; - case eTF_ASTC_6x5: - return DDSPF_ASTC_6x5; - case eTF_ASTC_6x6: - return DDSPF_ASTC_6x6; - case eTF_ASTC_8x5: - return DDSPF_ASTC_8x5; - case eTF_ASTC_8x6: - return DDSPF_ASTC_8x6; - case eTF_ASTC_8x8: - return DDSPF_ASTC_8x8; - case eTF_ASTC_10x5: - return DDSPF_ASTC_10x5; - case eTF_ASTC_10x6: - return DDSPF_ASTC_10x6; - case eTF_ASTC_10x8: - return DDSPF_ASTC_10x8; - case eTF_ASTC_10x10: - return DDSPF_ASTC_10x10; - case eTF_ASTC_12x10: - return DDSPF_ASTC_12x10; - case eTF_ASTC_12x12: - return DDSPF_ASTC_12x12; - default: - assert(0); - return DDSPF_A8B8G8R8; - } - } - - inline const CImageExtensionHelper::DDS_PIXELFORMAT& GetDescByFormat(DWORD& dxgifOut, const ETEX_Format eTF) - { - dxgifOut = 0; - - switch (eTF) - { -#if defined(CRY_DDS_DX10_SUPPORT) - case eTF_R8: - dxgifOut = DXGI_FORMAT_R8_UNORM; - return DDSPF_DX10; - case eTF_R8S: - dxgifOut = DXGI_FORMAT_R8_SNORM; - return DDSPF_DX10; - case eTF_R16: - dxgifOut = DXGI_FORMAT_R16_UNORM; - return DDSPF_DX10; - case eTF_R16F: - dxgifOut = DXGI_FORMAT_R16_FLOAT; - return DDSPF_DX10; - case eTF_R8G8: - dxgifOut = DXGI_FORMAT_R8G8_UNORM; - return DDSPF_DX10; - case eTF_R8G8S: - dxgifOut = DXGI_FORMAT_R8G8_SNORM; - return DDSPF_DX10; - case eTF_R16G16: - dxgifOut = DXGI_FORMAT_R16G16_UNORM; - return DDSPF_DX10; - case eTF_R11G11B10F: - dxgifOut = DXGI_FORMAT_R11G11B10_FLOAT; - return DDSPF_DX10; - case eTF_R10G10B10A2: - dxgifOut = DXGI_FORMAT_R10G10B10A2_UNORM; - return DDSPF_DX10; - case eTF_R16G16B16A16: - dxgifOut = DXGI_FORMAT_R16G16B16A16_UNORM; - return DDSPF_DX10; - case eTF_R16G16B16A16S: - dxgifOut = DXGI_FORMAT_R16G16B16A16_SNORM; - return DDSPF_DX10; - case eTF_R32G32B32A32F: - dxgifOut = DXGI_FORMAT_R32G32B32A32_FLOAT; - return DDSPF_DX10; - case eTF_R8G8B8A8S: - dxgifOut = DXGI_FORMAT_R8G8B8A8_SNORM; - return DDSPF_DX10; - - case eTF_BC4S: - dxgifOut = DXGI_FORMAT_BC4_SNORM; - return DDSPF_DX10; - case eTF_BC5S: - dxgifOut = DXGI_FORMAT_BC5_SNORM; - return DDSPF_DX10; - case eTF_BC6SH: - dxgifOut = DXGI_FORMAT_BC6H_SF16; - return DDSPF_DX10; - case eTF_BC6UH: - dxgifOut = DXGI_FORMAT_BC6H_UF16; - return DDSPF_DX10; - case eTF_BC7: - dxgifOut = DXGI_FORMAT_BC7_UNORM; - return DDSPF_DX10; - case eTF_R9G9B9E5: - dxgifOut = DXGI_FORMAT_R9G9B9E5_SHAREDEXP; - return DDSPF_DX10; -#endif - - default: - return GetDescByFormat(eTF); - } - } -}; - -namespace CImageExtensionHelper -{ - inline const char* NameForDesc(const DDS_PIXELFORMAT& ddspf) - { - ETEX_Format nFormat = DDSFormats::GetFormatByDesc(ddspf); - return NameForTextureFormat(nFormat); - } - - inline const char* NameForDesc(const DDS_PIXELFORMAT& ddspf, DWORD /*DXGI_FORMAT*/ dxgif) - { - ETEX_Format nFormat = DDSFormats::GetFormatByDesc(ddspf, dxgif); - return NameForTextureFormat(nFormat); - } -}; diff --git a/Code/CryEngine/CryCommon/ImageExtensionHelper_info.h b/Code/CryEngine/CryCommon/ImageExtensionHelper_info.h deleted file mode 100644 index dae6f9cb2d..0000000000 --- a/Code/CryEngine/CryCommon/ImageExtensionHelper_info.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_IMAGEEXTENSIONHELPER_INFO_H -#define CRYINCLUDE_CRYCOMMON_IMAGEEXTENSIONHELPER_INFO_H -#pragma once - -#include "CryString.h" -#include "TypeInfo_decl.h" -#include "ImageExtensionHelper.h" - -// Crytek specific image extensions -// -// usually added to the end of DDS files - - -STRUCT_INFO_BEGIN(CImageExtensionHelper::DDS_PIXELFORMAT) -STRUCT_VAR_INFO(dwSize, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwFlags, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwFourCC, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwRGBBitCount, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwRBitMask, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwGBitMask, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwBBitMask, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwABitMask, TYPE_INFO(DWORD)) -STRUCT_INFO_END(CImageExtensionHelper::DDS_PIXELFORMAT) - -STRUCT_INFO_BEGIN(CImageExtensionHelper::DDS_HEADER_DXT10) -STRUCT_VAR_INFO(dxgiFormat, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(resourceDimension, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(miscFlag, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(arraySize, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(reserved, TYPE_INFO(DWORD)) -STRUCT_INFO_END(CImageExtensionHelper::DDS_HEADER_DXT10) - -STRUCT_INFO_BEGIN(CImageExtensionHelper::DDS_HEADER) -STRUCT_VAR_INFO(dwSize, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwHeaderFlags, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwHeight, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwWidth, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwPitchOrLinearSize, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwDepth, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwMipMapCount, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwAlphaBitDepth, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwReserved1, TYPE_ARRAY(10, TYPE_INFO(DWORD))) -STRUCT_VAR_INFO(ddspf, TYPE_INFO(CImageExtensionHelper::DDS_PIXELFORMAT)) -STRUCT_VAR_INFO(dwSurfaceFlags, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(dwCubemapFlags, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(bNumPersistentMips, TYPE_INFO(BYTE)) -STRUCT_VAR_INFO(bReserved2, TYPE_ARRAY(7, TYPE_INFO(BYTE))) -STRUCT_VAR_INFO(dwTextureStage, TYPE_INFO(DWORD)) -STRUCT_INFO_END(CImageExtensionHelper::DDS_HEADER) - -STRUCT_INFO_BEGIN(CImageExtensionHelper::DDS_FILE_DESC) -STRUCT_VAR_INFO(dwMagic, TYPE_INFO(DWORD)) -STRUCT_VAR_INFO(header, TYPE_INFO(CImageExtensionHelper::DDS_HEADER)) -STRUCT_INFO_END(CImageExtensionHelper::DDS_FILE_DESC) - -#endif // CRYINCLUDE_CRYCOMMON_IMAGEEXTENSIONHELPER_INFO_H diff --git a/Code/CryEngine/CryCommon/LyShine/ISprite.h b/Code/CryEngine/CryCommon/LyShine/ISprite.h index d2e9a6e039..b9adda6901 100644 --- a/Code/CryEngine/CryCommon/LyShine/ISprite.h +++ b/Code/CryEngine/CryCommon/LyShine/ISprite.h @@ -16,9 +16,6 @@ #include #include -// forward declarations -class ITexture; - //////////////////////////////////////////////////////////////////////////////////////////////////// //! A sprite is a texture with extra information about how it behaves for 2D drawing //! Currently a sprite exists on disk as a side car file next to the texture file. @@ -80,9 +77,6 @@ public: // member functions //! Set the borders of a given cell within the sprite-sheet. virtual void SetCellBorders(int cellIndex, Borders borders) = 0; - //! Get the texture for this sprite - virtual ITexture* GetTexture() = 0; - //! Serialize this object for save/load virtual void Serialize(TSerialize ser) = 0; diff --git a/Code/CryEngine/CryCommon/Mocks/IRendererMock.h b/Code/CryEngine/CryCommon/Mocks/IRendererMock.h index 74d072c48c..a3fae96310 100644 --- a/Code/CryEngine/CryCommon/Mocks/IRendererMock.h +++ b/Code/CryEngine/CryCommon/Mocks/IRendererMock.h @@ -330,8 +330,6 @@ public: ITexture * (const char* nameTex)); MOCK_METHOD1(EF_LoadLightmap, int(const char* name)); - MOCK_METHOD3(EF_RenderEnvironmentCubeHDR, - bool(int size, Vec3 & Pos, TArray&vecData)); MOCK_METHOD1(EF_StartEf, void(const SRenderingPassInfo& passInfo)); MOCK_METHOD3(EF_GetObjData, @@ -360,8 +358,6 @@ public: uint32(eDeferredLightType)); MOCK_METHOD0(EF_ClearDeferredLightsList, void()); - MOCK_METHOD2(EF_GetDeferredLights, - TArray*(const SRenderingPassInfo&, const eDeferredLightType)); MOCK_METHOD1(EF_AddDeferredClipVolume, uint8(const IClipVolume * pClipVolume)); MOCK_METHOD2(EF_SetDeferredClipVolumeBlendData, diff --git a/Code/CryEngine/CryCommon/Mocks/ISystemMock.h b/Code/CryEngine/CryCommon/Mocks/ISystemMock.h index cfe150c1df..8c9c98b3ee 100644 --- a/Code/CryEngine/CryCommon/Mocks/ISystemMock.h +++ b/Code/CryEngine/CryCommon/Mocks/ISystemMock.h @@ -37,14 +37,8 @@ public: bool()); MOCK_METHOD0(RenderStatistics, void()); - MOCK_METHOD0(GetUsedMemory, - uint32()); MOCK_METHOD0(GetUserName, const char*()); - MOCK_METHOD0(GetCPUFlags, - int()); - MOCK_METHOD0(GetLogicalCPUCount, - int()); MOCK_METHOD0(Quit, void()); MOCK_METHOD1(Relaunch, @@ -57,8 +51,6 @@ public: int()); MOCK_CONST_METHOD0(IsRelaunch, bool()); - MOCK_METHOD4(DisplayErrorMessage, - void(const char*, float, const float*, bool)); void FatalError([[maybe_unused]] const char* sFormat, ...) override {} void ReportBug([[maybe_unused]] const char* sFormat, ...) override {} @@ -72,24 +64,12 @@ public: int(const char* text, const char* caption, unsigned int uType)); MOCK_METHOD1(CheckLogVerbosity, bool(int verbosity)); - MOCK_METHOD0(GetIZLibCompressor, - IZLibCompressor * ()); - MOCK_METHOD0(GetIZLibDecompressor, - IZLibDecompressor * ()); - MOCK_METHOD0(GetLZ4Decompressor, - ILZ4Decompressor * ()); - MOCK_METHOD0(GetZStdDecompressor, - IZStdDecompressor * ()); MOCK_METHOD0(GetIViewSystem, IViewSystem * ()); MOCK_METHOD0(GetILevelSystem, ILevelSystem * ()); MOCK_METHOD0(GetINameTable, INameTable * ()); - MOCK_METHOD0(GetIValidator, - IValidator * ()); - MOCK_METHOD0(GetStreamEngine, - IStreamEngine * ()); MOCK_METHOD0(GetICmdLine, ICmdLine * ()); MOCK_METHOD0(GetILog, @@ -98,8 +78,6 @@ public: AZ::IO::IArchive * ()); MOCK_METHOD0(GetICryFont, ICryFont * ()); - MOCK_METHOD0(GetIMemoryManager, - IMemoryManager * ()); MOCK_METHOD0(GetIMovieSystem, IMovieSystem * ()); MOCK_METHOD0(GetIAudioSystem, @@ -108,20 +86,12 @@ public: ::IConsole * ()); MOCK_METHOD0(GetIRemoteConsole, IRemoteConsole * ()); - MOCK_METHOD0(GetIResourceManager, - IResourceManager * ()); MOCK_METHOD0(GetIProfilingSystem, IProfilingSystem * ()); MOCK_METHOD0(GetISystemEventDispatcher, ISystemEventDispatcher * ()); MOCK_METHOD0(GetITimer, ITimer * ()); - MOCK_METHOD2(DebugStats, - void(bool checkpoint, bool leaks)); - MOCK_METHOD0(DumpWinHeaps, - void()); - MOCK_METHOD1(DumpMMStats, - int(bool log)); MOCK_METHOD1(SetForceNonDevMode, void(bool bValue)); MOCK_CONST_METHOD0(GetForceNonDevMode, @@ -130,8 +100,6 @@ public: bool()); MOCK_CONST_METHOD0(IsDevMode, bool()); - MOCK_CONST_METHOD1(IsMODValid, - bool(const char* szMODName)); MOCK_METHOD3(CreateXmlNode, XmlNodeRef(const char*, bool, bool)); MOCK_METHOD4(LoadXmlFromBuffer, @@ -161,11 +129,6 @@ public: MOCK_METHOD0(GetBuildVersion, const SFileVersion&()); - MOCK_METHOD5(CompressDataBlock, - bool(const void*, size_t, void*, size_t &, int)); - - MOCK_METHOD4(DecompressDataBlock, - bool(const void* input, size_t inputSize, void* output, size_t & outputSize)); MOCK_METHOD1(AddCVarGroupDirectory, void(const string&)); MOCK_METHOD0(SaveConfiguration, @@ -173,24 +136,16 @@ public: MOCK_METHOD3(LoadConfiguration, void(const char*, ILoadConfigurationEntrySink*, bool)); - MOCK_METHOD1(GetConfigSpec, - ESystemConfigSpec(bool)); MOCK_CONST_METHOD0(GetMaxConfigSpec, ESystemConfigSpec()); - MOCK_METHOD3(SetConfigSpec, - void(ESystemConfigSpec spec, ESystemConfigPlatform platform, bool bClient)); MOCK_CONST_METHOD0(GetConfigPlatform, ESystemConfigPlatform()); MOCK_METHOD1(SetConfigPlatform, void(ESystemConfigPlatform platform)); - MOCK_METHOD1(AutoDetectSpec, - void(bool detectResolution)); MOCK_CONST_METHOD0(IsPaused, bool()); MOCK_METHOD0(GetLocalizationManager, ILocalizationManager * ()); - MOCK_METHOD0(GetITextModeConsole, - ITextModeConsole * ()); MOCK_METHOD0(GetNoiseGen, CPNoise3 * ()); MOCK_METHOD0(GetUpdateCounter, @@ -227,18 +182,12 @@ public: ESystemGlobalState(void)); MOCK_METHOD1(SetSystemGlobalState, void(ESystemGlobalState systemGlobalState)); - MOCK_METHOD5(AsyncMemcpy, - void(void* dst, const void* src, size_t size, int nFlags, volatile int* sync)); #if !defined(_RELEASE) MOCK_CONST_METHOD0(IsSavingResourceList, bool()); #endif - MOCK_METHOD0(SteamInit, - bool()); - MOCK_CONST_METHOD0(GetImageHandler, - const IImageHandler * ()); MOCK_METHOD0(GetRootWindowMessageHandler, void*()); MOCK_METHOD1(RegisterWindowMessageHandler, diff --git a/Code/CryEngine/CryCommon/PoolAllocator.h b/Code/CryEngine/CryCommon/PoolAllocator.h index d6037289a7..110d25153e 100644 --- a/Code/CryEngine/CryCommon/PoolAllocator.h +++ b/Code/CryEngine/CryCommon/PoolAllocator.h @@ -36,9 +36,6 @@ // require a pointer to the bucket be stored, whereas now no memory is used // while the block is allocated. // -// This allocator is suitable for use with STL lists - see STLPoolAllocator -// for an STL-compatible interface. -// // The class can optionally support multi-threading, using the second // template parameter. By default it is multithread-safe. // See Synchronization.h. diff --git a/Code/CryEngine/CryCommon/ProjectDefines.h b/Code/CryEngine/CryCommon/ProjectDefines.h index 67ae58a324..1f151caf2e 100644 --- a/Code/CryEngine/CryCommon/ProjectDefines.h +++ b/Code/CryEngine/CryCommon/ProjectDefines.h @@ -40,8 +40,6 @@ #endif #endif -#define USE_STEAM 0 // Enable this to start using Steam - // The following definitions are used by Sandbox and RC to determine which platform support is needed #define TOOLS_SUPPORT_POWERVR #define TOOLS_SUPPORT_ETC2COMP diff --git a/Code/CryEngine/CryCommon/RenderBus.h b/Code/CryEngine/CryCommon/RenderBus.h index efd004219a..21c56f607c 100644 --- a/Code/CryEngine/CryCommon/RenderBus.h +++ b/Code/CryEngine/CryCommon/RenderBus.h @@ -33,14 +33,6 @@ namespace AZ static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; ////////////////////////////////////////////////////////////////////////// - /** - * This event gets posted at the end of CD3D9Renderer's EF_Scene3D method. - * CSystem (in SystemRenderer.cpp) uses this to render the console, aux geom and UI - * in a manner that will make sure the render calls end up as part of the scene's render. - * This is important or else those render calls won't show up properly in VR. - */ - virtual void OnScene3DEnd() {}; - /** * This event gets posted at the beginning of CD3D9Renderer's FreeResources method, before the resources have been freed. */ diff --git a/Code/CryEngine/CryCommon/STLGlobalAllocator.h b/Code/CryEngine/CryCommon/STLGlobalAllocator.h deleted file mode 100644 index 2067c9b2e9..0000000000 --- a/Code/CryEngine/CryCommon/STLGlobalAllocator.h +++ /dev/null @@ -1,185 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_STLGLOBALALLOCATOR_H -#define CRYINCLUDE_CRYCOMMON_STLGLOBALALLOCATOR_H -#pragma once - - -//--------------------------------------------------------------------------- -// STL-compatible interface for an std::allocator using the global heap. -//--------------------------------------------------------------------------- - -#include -#include - -#include "CryMemoryManager.h" - -#include -#include -#include - -struct CryLegacySTLAllocatorDescriptor - : public AZ::HphaSchema::Descriptor -{ - CryLegacySTLAllocatorDescriptor() - { - m_systemChunkSize = 4 * 1024 * 1024; // Ask the OS for 4MB at a time - } -}; - -class CryLegacySTLAllocator - : public AZ::SimpleSchemaAllocator -{ -public: - AZ_TYPE_INFO(CryLegacySTLAllocator, "{87EE21F1-8215-4979-B493-AF13D8D91DAD}"); - using Descriptor = CryLegacySTLAllocatorDescriptor; - using Base = AZ::SimpleSchemaAllocator; - CryLegacySTLAllocator() - : Base("CryLegacySTLAllocator", "Allocator used to dodge limits on static init time allocations") - { - } -}; - -// Specialize for the CryLegacySTLAllocator to provide one per module that does not use the -// environment for its storage, since this thing is designed to get around the lack -// of static allocators -namespace AZ -{ - template <> - class AllocatorInstance : public Internal::AllocatorInstanceBase> - { - }; -} - - -class ICrySizer; -namespace stl -{ - template - class STLGlobalAllocator - { - public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - template - struct rebind - { - typedef STLGlobalAllocator other; - }; - - STLGlobalAllocator() throw() - { - } - - STLGlobalAllocator(const STLGlobalAllocator&) throw() - { - } - - template - STLGlobalAllocator(const STLGlobalAllocator&) throw() - { - } - - ~STLGlobalAllocator() throw() - { - } - - pointer address(reference x) const - { - return &x; - } - - const_pointer address(const_reference x) const - { - return &x; - } - - pointer allocate(size_type n = 1, const void* hint = 0) - { - (void)hint; - pointer ret = static_cast(AZ::AllocatorInstance::Get().Allocate(n * sizeof(T), 0)); - return ret; - } - - void deallocate(pointer p, [[maybe_unused]] size_type n = 1) - { - AZ::AllocatorInstance::Get().DeAllocate(p); - } - - size_type max_size() const throw() - { - return INT_MAX; - } -#if !defined(_LIBCPP_VERSION) - void construct(pointer p, const T& val) - { - new(static_cast(p))T(val); - } - - void construct(pointer p) - { - new(static_cast(p))T(); - } -#endif // !_LIBCPP_VERSION - void destroy(pointer p) - { - p->~T(); - } - - pointer new_pointer() - { - return new(allocate())T(); - } - - pointer new_pointer(const T& val) - { - return new(allocate())T(val); - } - - void delete_pointer(pointer p) - { - p->~T(); - deallocate(p); - } - - bool operator==(const STLGlobalAllocator&) const { return true; } - bool operator!=(const STLGlobalAllocator&) const { return false; } - - static void GetMemoryUsage(ICrySizer* pSizer) - { - } - }; - - template <> - class STLGlobalAllocator - { - public: - typedef void* pointer; - typedef const void* const_pointer; - typedef void value_type; - template - struct rebind - { - typedef STLGlobalAllocator other; - }; - }; -} - -#endif // CRYINCLUDE_CRYCOMMON_STLGLOBALALLOCATOR_H diff --git a/Code/CryEngine/CryCommon/STLPoolAllocator.h b/Code/CryEngine/CryCommon/STLPoolAllocator.h deleted file mode 100644 index 564720bc02..0000000000 --- a/Code/CryEngine/CryCommon/STLPoolAllocator.h +++ /dev/null @@ -1,208 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_STLPOOLALLOCATOR_H -#define CRYINCLUDE_CRYCOMMON_STLPOOLALLOCATOR_H -#pragma once - - -//--------------------------------------------------------------------------- -// STL-compatible interface for the pool allocator (see PoolAllocator.h). -// -// This class is suitable for use as an allocator for STL lists. Note it will -// not work with vectors, since it allocates fixed-size blocks, while vectors -// allocate elements in variable-sized contiguous chunks. -// -// To create a list of type UserDataType using this allocator, use the -// following syntax: -// -// std::list > myList; -//--------------------------------------------------------------------------- - -#include "PoolAllocator.h" -#include "MetaUtils.h" -#include -#include - -namespace stl -{ - namespace STLPoolAllocatorHelper - { - inline void destruct(char*) {} - inline void destruct(wchar_t*) {} - template - inline void destruct(T* t) {t->~T(); } - } - - template - struct STLPoolAllocatorStatic - { - // Non-freeing stl pool allocators should just go on the global heap - only if they've been explicitly - // set to cleanup should they go on the default heap. - typedef SizePoolAllocator< - HeapAllocator< - L, - typename metautils::select::type> - > AllocatorType; - - static AllocatorType* GetOrCreateAllocator() - { - if (allocator) - { - return allocator; - } - - allocator = new AllocatorType(S, A, FHeap().FreeWhenEmpty(FreeWhenEmpty)); - return allocator; - } - - static AllocatorType* allocator; - }; - - template - struct STLPoolAllocatorKungFu - : public STLPoolAllocatorStatic - { - }; - - template - class STLPoolAllocator - { - public: - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef T value_type; - - template - struct rebind - { - typedef STLPoolAllocator other; - }; - - STLPoolAllocator() throw() - { - } - - STLPoolAllocator(const STLPoolAllocator&) throw() - { - } - - template - STLPoolAllocator(const STLPoolAllocator&) throw() - { - } - - ~STLPoolAllocator() throw() - { - } - - pointer address(reference x) const - { - return &x; - } - - const_pointer address(const_reference x) const - { - return &x; - } - - pointer allocate([[maybe_unused]] size_type n = 1, [[maybe_unused]] const void* hint = 0) - { - assert(n == 1); - typename STLPoolAllocatorKungFu::AllocatorType * allocator = STLPoolAllocatorKungFu::GetOrCreateAllocator(); - return static_cast(allocator->Allocate()); - } - - void deallocate(pointer p, [[maybe_unused]] size_type n = 1) - { - assert(n == 1); - typename STLPoolAllocatorKungFu::AllocatorType * allocator = STLPoolAllocatorKungFu::allocator; - allocator->Deallocate(p); - } - - size_type max_size() const throw() - { - return INT_MAX; - } -#ifndef _LIBCPP_VERSION - void construct(pointer p, const T& val) - { - new(static_cast(p))T(val); - } - - void construct(pointer p) - { - new(static_cast(p))T(); - } -#endif // !(_LIBCPP_VERSION) - void destroy(pointer p) - { - STLPoolAllocatorHelper::destruct(p); - } - - pointer new_pointer() - { - return new(allocate())T(); - } - - pointer new_pointer(const T& val) - { - return new(allocate())T(val); - } - - void delete_pointer(pointer p) - { - p->~T(); - deallocate(p); - } - - bool operator==(const STLPoolAllocator&) {return true; } - bool operator!=(const STLPoolAllocator&) {return false; } - - static void GetMemoryUsage(ICrySizer* pSizer) - { - pSizer->AddObject(STLPoolAllocatorKungFu::allocator); - } - }; - - template - class STLPoolAllocatorNoMT - : public STLPoolAllocator - { - }; - - template <> - class STLPoolAllocator - { - public: - typedef void* pointer; - typedef const void* const_pointer; - typedef void value_type; - template - struct rebind - { - typedef STLPoolAllocator other; - }; - }; - - template - typename STLPoolAllocatorStatic::AllocatorType * STLPoolAllocatorStatic::allocator; -} - - - -#endif // CRYINCLUDE_CRYCOMMON_STLPOOLALLOCATOR_H diff --git a/Code/CryEngine/CryCommon/STLPoolAllocator_ManyElems.h b/Code/CryEngine/CryCommon/STLPoolAllocator_ManyElems.h deleted file mode 100644 index 28fff38917..0000000000 --- a/Code/CryEngine/CryCommon/STLPoolAllocator_ManyElems.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYCOMMON_STLPOOLALLOCATOR_MANYELEMS_H -#define CRYINCLUDE_CRYCOMMON_STLPOOLALLOCATOR_MANYELEMS_H -#pragma once - - -//--------------------------------------------------------------------------- -// STL-compatible interface for the pool allocator (see PoolAllocator.h). -// -// this class acts like STLPoolAllocator, but it is also usable for vectors -// which means that it can be used as a more efficient allocator for many -// implementations of hash_map (typically this uses internally a vector and -// a list with the same allocator) -//--------------------------------------------------------------------------- - -#include "STLPoolAllocator.h" - -namespace stl -{ - template - struct STLPoolAllocator_ManyElemsStatic - { - static PoolAllocator* allocator; - }; - - template - class STLPoolAllocator_ManyElems - : public STLPoolAllocator - { - typedef STLPoolAllocator Super; - typedef PoolAllocator LargeAllocator; - - public: - typedef typename Super::pointer pointer; - typedef typename Super::pointer pointer_type; - typedef typename Super::size_type size_type; - typedef AZStd::false_type allow_memory_leaks; - - template - struct rebind - { - typedef STLPoolAllocator_ManyElems other; - }; - - STLPoolAllocator_ManyElems() throw() - { - } - - template - STLPoolAllocator_ManyElems(const STLPoolAllocator_ManyElems&) throw() - { - } - - pointer allocate(size_type n = 1, const void* hint = 0) - { - if (n == 1) - { - return Super::allocate(n, hint); - } - else if (n * sizeof(T) <= LargeAllocationSizeThreshold) - { - if (!STLPoolAllocator_ManyElemsStatic::allocator) - { - STLPoolAllocator_ManyElemsStatic::allocator = new LargeAllocator(); - } - return static_cast(STLPoolAllocator_ManyElemsStatic::allocator->Allocate()); - } - else - { - return static_cast(CryModuleMalloc(n * sizeof(T))); - } - } - - void deallocate(pointer p, size_type n = 1) - { - if (n == 1) - { - Super::deallocate(p); - } - else if (n * sizeof(T) <= LargeAllocationSizeThreshold) - { - STLPoolAllocator_ManyElemsStatic::allocator->Deallocate(p); - } - else - { - CryModuleFree(p); - } - } - }; - - template - PoolAllocator* STLPoolAllocator_ManyElemsStatic::allocator; -} - -#endif // CRYINCLUDE_CRYCOMMON_STLPOOLALLOCATOR_MANYELEMS_H diff --git a/Code/CryEngine/CryCommon/StlUtils.h b/Code/CryEngine/CryCommon/StlUtils.h index df88a14196..9d6090502f 100644 --- a/Code/CryEngine/CryCommon/StlUtils.h +++ b/Code/CryEngine/CryCommon/StlUtils.h @@ -27,7 +27,6 @@ #endif #define STATIC_ASSERT(condition, errMessage) static_assert(condition, errMessage) -#include "STLGlobalAllocator.h" #include #include diff --git a/Code/CryEngine/CryCommon/StringUtils.h b/Code/CryEngine/CryCommon/StringUtils.h index 6c38315b40..4e3bed3b26 100644 --- a/Code/CryEngine/CryCommon/StringUtils.h +++ b/Code/CryEngine/CryCommon/StringUtils.h @@ -168,7 +168,6 @@ namespace CryStringUtils_Internal // Can be used for ASCII and Unicode (UTF-8/UTF-16/UTF-32), but not for ANSI. // ? will match exactly one code-point. // * will match zero or more code-points. - // Note: function moved here from CryCommonTools. template class CharComparator, class CharType> inline bool MatchesWildcards_Tpl(const CharType* pStr, const CharType* pWild) { diff --git a/Code/CryEngine/CryCommon/Tarray.h b/Code/CryEngine/CryCommon/Tarray.h index 035a4b3e0e..32bb249f7c 100644 --- a/Code/CryEngine/CryCommon/Tarray.h +++ b/Code/CryEngine/CryCommon/Tarray.h @@ -19,7 +19,6 @@ #include #include #include -#include #ifndef CLAMP #define CLAMP(X, mn, mx) ((X) < (mn) ? (mn) : ((X) < (mx) ? (X) : (mx))) @@ -58,400 +57,4 @@ } #endif - -// General array class. -// Can refer to a general (unowned) region of memory (m_nAllocatedCount = 0). -// Can allocate, grow, and shrink an array. -// Does not deep copy. - -template -class TArray -{ -protected: - T* m_pElements; - unsigned int m_nCount; - unsigned int m_nAllocatedCount; - -public: - typedef T value_type; - - // Empty array. - TArray() - { - ClearArr(); - } - - // Create a new array, delete it on destruction. - TArray(int Count) - { - m_nCount = Count; - m_nAllocatedCount = Count; - m_pElements = NULL; - Realloc(0); - } - TArray(int Use, int Max) - { - m_nCount = Use; - m_nAllocatedCount = Max; - m_pElements = NULL; - Realloc(0); - } - - // Reference pre-existing memory. Does not delete it. - TArray(T* Elems, int Count) - { - m_pElements = Elems; - m_nCount = Count; - m_nAllocatedCount = 0; - } - ~TArray() - { - Free(); - } - - void Free() - { - m_nCount = 0; - if (m_nAllocatedCount && AZ::AllocatorInstance::IsReady()) - { - AZ::AllocatorInstance::Get().DeAllocate(m_pElements); - } - m_nAllocatedCount = 0; - m_pElements = NULL; - } - - void Create (int Count) - { - m_pElements = NULL; - m_nCount = Count; - m_nAllocatedCount = Count; - Realloc(0); - Clear(); - } - void Copy (const TArray& src) - { - m_pElements = NULL; - m_nCount = m_nAllocatedCount = src.Num(); - Realloc(0); - PREFAST_ASSUME(m_pElements); // realloc asserts if it fails - so this is safe - memcpy(m_pElements, src.m_pElements, src.Num() * sizeof(T)); - } - void Copy (const T* src, unsigned int numElems) - { - int nOffs = m_nCount; - Grow(numElems); - memcpy(&m_pElements[nOffs], src, numElems * sizeof(T)); - } - void Align4Copy (const T* src, unsigned int& numElems) - { - int nOffs = m_nCount; - Grow((numElems + 3) & ~3); - memcpy(&m_pElements[nOffs], src, numElems * sizeof(T)); - if (numElems & 3) - { - int nSet = 4 - (numElems & 3); - memset(&m_pElements[nOffs + numElems], 0, nSet); - numElems += nSet; - } - } - - void Realloc([[maybe_unused]] int nOldAllocatedCount) - { - if (!m_nAllocatedCount) - { - m_pElements = NULL; - } - else - { - m_pElements = static_cast(AZ::AllocatorInstance::Get().ReAllocate(m_pElements, m_nAllocatedCount * sizeof(T), alignof(T))); - assert (m_pElements); - } - } - - void Remove(unsigned int Index, unsigned int Count = 1) - { - if (Count) - { - memmove(m_pElements + Index, m_pElements + (Index + Count), sizeof(T) * (m_nCount - Index - Count)); - m_nCount -= Count; - } - } - - void Shrink() - { - if (m_nCount == 0 || m_nAllocatedCount == 0) - { - return; - } - assert(m_nAllocatedCount >= m_nCount); - if (m_nAllocatedCount != m_nCount) - { - int nOldAllocatedCount = m_nAllocatedCount; - m_nAllocatedCount = m_nCount; - Realloc(nOldAllocatedCount); - } - } - - void _Remove(unsigned int Index, unsigned int Count) - { - assert (Index >= 0); - assert (Index <= m_nCount); - assert ((Index + Count) <= m_nCount); - - Remove(Index, Count); - } - - unsigned int Num(void) const { return m_nCount; } - unsigned int Capacity(void) const { return m_nAllocatedCount; } - unsigned int MemSize(void) const { return m_nCount * sizeof(T); } - void SetNum(unsigned int n) { m_nCount = m_nAllocatedCount = n; } - void SetUse(unsigned int n) { m_nCount = n; } - void Alloc(unsigned int n) { int nOldAllocatedCount = m_nAllocatedCount; m_nAllocatedCount = n; Realloc(nOldAllocatedCount); } - void Reserve(unsigned int n) { int nOldAllocatedCount = m_nAllocatedCount; SetNum(n); Realloc(nOldAllocatedCount); Clear(); } - void ReserveNoClear(unsigned int n) { int nOldAllocatedCount = m_nAllocatedCount; SetNum(n); Realloc(nOldAllocatedCount); } - void Expand(unsigned int n) - { - if (n > m_nAllocatedCount) - { - ReserveNew(n); - } - } - void ReserveNew(unsigned int n) - { - int num = m_nCount; - if (n > m_nAllocatedCount) - { - int nOldAllocatedCount = m_nAllocatedCount; - m_nAllocatedCount = n * 2; - Realloc(nOldAllocatedCount); - } - m_nCount = n; - memset(&m_pElements[num], 0, sizeof(T) * (m_nCount - num)); - } - T* Grow(unsigned int n) - { - int nStart = m_nCount; - m_nCount += n; - if (m_nCount > m_nAllocatedCount) - { - int nOldAllocatedCount = m_nAllocatedCount; - m_nAllocatedCount = m_nCount * 2; - Realloc(nOldAllocatedCount); - } - return &m_pElements[nStart]; - } - T* GrowReset(unsigned int n) - { - int num = m_nAllocatedCount; - T* Obj = AddIndex(n); - if (num != m_nAllocatedCount) - { - memset(&m_pElements[num], 0, sizeof(T) * (m_nAllocatedCount - num)); - } - return Obj; - } - - unsigned int* GetNumAddr(void) { return &m_nCount; } - T** GetDataAddr(void) { return &m_pElements; } - - T* Data(void) const { return m_pElements; } - T& Get(unsigned int id) const { return m_pElements[id]; } - - - void Assign(TArray& fa) - { - m_pElements = fa.m_pElements; - m_nCount = fa.m_nCount; - m_nAllocatedCount = fa.m_nAllocatedCount; - } - - - /*const TArray operator=(TArray fa) const - { - TArray t = TArray(fa.m_nCount,fa.m_nAllocatedCount); - for ( int i=0; i 0); return *m_pElements; } - - TArray operator()(unsigned int Start) - { - assert(Start < m_nCount); - return TArray(m_pElements + Start, m_nCount - Start); - } - TArray operator()(unsigned int Start, unsigned int Count) - { - assert(Start < m_nCount); - assert(Start + Count <= m_nCount); - return TArray(m_pElements + Start, Count); - } - - // For simple types only - TArray(const TArray& cTA) - { - m_pElements = NULL; - m_nCount = m_nAllocatedCount = cTA.Num(); - Realloc(0); - if (m_pElements) - { - memcpy(m_pElements, &cTA[0], m_nCount * sizeof(T)); - } - /*for (unsigned int i=0; i m_nAllocatedCount) - { - int nOldAllocatedCount = m_nAllocatedCount; - m_nAllocatedCount = nNewCount + (nNewCount >> 1) + 10; - Realloc(nOldAllocatedCount); - } - - m_nCount = nNewCount; - return &m_pElements[nIndex]; - } - - T& Insert(unsigned int nIndex, unsigned int inc = 1) - { - m_nCount += inc; - if (m_nCount > m_nAllocatedCount) - { - int nOldAllocatedCount = m_nAllocatedCount; - m_nAllocatedCount = m_nCount + (m_nCount >> 1) + 32; - Realloc(nOldAllocatedCount); - } - memmove(&m_pElements[nIndex + inc], &m_pElements[nIndex], (m_nCount - inc - nIndex) * sizeof(T)); - - return m_pElements[nIndex]; - } - - void AddIndexNoCache(unsigned int inc) - { - m_nCount += inc; - if (m_nCount > m_nAllocatedCount) - { - int nOldAllocatedCount = m_nAllocatedCount; - m_nAllocatedCount = m_nCount; - Realloc(nOldAllocatedCount); - } - } - - void Add(const T& elem){AddElem(elem); } - void AddElem(const T& elem) - { - unsigned int m = m_nCount; - AddIndex(1); - m_pElements[m] = elem; - } - void AddElemNoCache(const T& elem) - { - unsigned int m = m_nCount; - AddIndexNoCache(1); - m_pElements[m] = elem; - } - - int Find(const T& p) - { - for (unsigned int i = 0; i < m_nCount; i++) - { - if (p == (*this)[i]) - { - return i; - } - } - return -1; - } - - void Delete(unsigned int n){DelElem(n); } - void DelElem(unsigned int n) - { - // memset(&m_pElements[n],0,sizeof(T)); - _Remove(n, 1); - } - - // Standard compliance interface - // - // This is for those who don't want to learn the non standard and - // thus not very convenient interface of TArray, but are unlucky - // enough not to be able to avoid using it. - void clear(){Free(); } - void resize(unsigned int nSize) { reserve(nSize); m_nCount = nSize; } - void reserve(unsigned int nSize) - { - if (nSize > m_nAllocatedCount) - { - Alloc(nSize); - } - } - unsigned size() const {return m_nCount; } - unsigned capacity() const {return m_nAllocatedCount; } - bool empty() const {return size() == 0; } - void push_back (const T& rSample) {Add(rSample); } - void pop_back () {m_nCount--; } - void erase (T* pElem) - { - int n = int(pElem - m_pElements); - assert(n >= 0 && n < m_nCount); - _Remove(n, 1); - } - T* begin() {return m_pElements; } - T* end() {return m_pElements + m_nCount; } - T last() {return m_pElements[m_nCount - 1]; } - const T* begin() const {return m_pElements; } - const T* end() const {return m_pElements + m_nCount; } - - int GetMemoryUsage() const { return (int)(m_nAllocatedCount * sizeof(T)); } -}; - -template -inline void Exchange(T& X, T& Y) -{ - const T Tmp = X; - X = Y; - Y = Tmp; -} - #endif // CRYINCLUDE_CRYCOMMON_TARRAY_H diff --git a/Code/CryEngine/CryCommon/crycommon_files.cmake b/Code/CryEngine/CryCommon/crycommon_files.cmake index dff4ca66e7..3c1d1605e7 100644 --- a/Code/CryEngine/CryCommon/crycommon_files.cmake +++ b/Code/CryEngine/CryCommon/crycommon_files.cmake @@ -12,7 +12,6 @@ set(FILES QTangent.h CryCommon.cpp - Allocator.h FinalizingSpline.h IAudioInterfacesCommonData.h IAudioSystem.h @@ -26,10 +25,8 @@ set(FILES IFunctorBase.h IFuncVariable.h IGem.h - IGeneralMemoryHeap.h IGeomCache.h IImage.h - IImageHandler.h IIndexedMesh.h IIndexedMesh_info.cpp ILevelSystem.h @@ -37,9 +34,7 @@ set(FILES LocalizationManagerBus.h LocalizationManagerBus.inl ILog.h - ILZ4Decompressor.h IMaterial.h - IMemory.h IMeshBaking.h IMiniLog.h IMovieSystem.h @@ -51,8 +46,6 @@ set(FILES IRenderAuxGeom.h IRenderer.h IRenderMesh.h - IResourceCollector.h - IResourceManager.h ISerialize.h IShader.h IShader_info.h @@ -60,11 +53,8 @@ set(FILES IStatObj.h StatObjBus.h IStereoRenderer.h - IStreamEngine.h - IStreamEngineDefs.h ISurfaceType.h ISystem.h - ITextModeConsole.h ITexture.h ITimer.h IValidator.h @@ -72,9 +62,6 @@ set(FILES IViewSystem.h IWindowMessageHandler.h IXml.h - IZLibCompressor.h - IZlibDecompressor.h - IZStdDecompressor.h IProximityTriggerSystem.h MicrophoneBus.h physinterface.h @@ -85,10 +72,8 @@ set(FILES IObjManager.h INavigationSystem.h IMNM.h - AzDXGIFormat.h SFunctor.h FunctorBaseFunction.h - CustomMemoryHeap.h FunctorBaseMember.h stridedptr.h Options.h @@ -102,31 +87,21 @@ set(FILES CryTypeInfo.cpp BaseTypes.h CompileTimeAssert.h - CryThreadSafeWorkerContainer.h - CryThreadSafeRendererContainer.h intrusive_list.hpp MemoryAccess.h - Algorithm.h AnimKey.h BitFiddling.h - CGFContent.h - CGFContent_info.cpp Common_TypeInfo.cpp - CountedValue.h - CrtDebugStats.h CryArray.h CryArray2d.h CryAssert.h CryCrc32.h CryCustomTypes.h CryFile.h - CryFixedArray.h CryFixedString.h CryHeaders.h CryHeaders_info.cpp CryListenerSet.h - CryMemoryAllocator.h - CryMemoryManager.h CryLegacyAllocator.h CryName.h CryPath.h @@ -145,9 +120,6 @@ set(FILES HashGrid.h HeapAllocator.h HeapContainer.h - ImageExtensionHelper.cpp - ImageExtensionHelper.h - ImageExtensionHelper_info.h InplaceFactory.h LegacyAllocator.h MetaUtils.h @@ -172,8 +144,6 @@ set(FILES SmartPointersHelpers.h smartptr.h StackContainer.h - STLGlobalAllocator.h - STLPoolAllocator.h StlUtils.h StringUtils.h Synchronization.h @@ -203,7 +173,6 @@ set(FILES Cry_Matrix44.h Cry_MatrixDiag.h Cry_Vector4.h - AABBSV.h Cry_Camera.h Cry_Color.h Cry_Geo.h @@ -224,7 +193,6 @@ set(FILES Cry_HWVector3.h AndroidSpecific.h AppleSpecific.h - Console_std.h CryAssert_Android.h CryAssert_impl.h CryAssert_iOS.h @@ -232,7 +200,6 @@ set(FILES CryAssert_Mac.h CryLibrary.cpp CryLibrary.h - CryMemoryManager_impl.h CryThread_dummy.h CryThread_pthreads.h CryThread_windows.h diff --git a/Code/CryEngine/CryCommon/platform.h b/Code/CryEngine/CryCommon/platform.h index f7361db11d..df8fb125b2 100644 --- a/Code/CryEngine/CryCommon/platform.h +++ b/Code/CryEngine/CryCommon/platform.h @@ -479,15 +479,7 @@ ILINE DestinationType alias_cast(SourceType pPtr) return conv_union.pDst; } -////////////////////////////////////////////////////////////////////////// - -#include "CryMemoryManager.h" - -// Memory manager breaks strdup -// Use something higher level, like CryString - #undef strdup - #define strdup dont_use_strdup - +#include "CryLegacyAllocator.h" ////////////////////////////////////////////////////////////////////////// #ifndef DEPRECATED diff --git a/Code/CryEngine/CryCommon/platform_impl.cpp b/Code/CryEngine/CryCommon/platform_impl.cpp index 885ea2984d..1d784ed8a0 100644 --- a/Code/CryEngine/CryCommon/platform_impl.cpp +++ b/Code/CryEngine/CryCommon/platform_impl.cpp @@ -20,6 +20,7 @@ #include #include +#include #include // Section dictionary @@ -194,11 +195,6 @@ void __stl_debug_message(const char* format_str, ...) #include #endif -// If we use cry memory manager this should be also included in every module. -#if defined(USING_CRY_MEMORY_MANAGER) -#include -#endif - #if defined(APPLE) || defined(LINUX) #include "CryAssert_impl.h" #endif diff --git a/Code/CryEngine/CrySystem/AndroidConsole.cpp b/Code/CryEngine/CrySystem/AndroidConsole.cpp deleted file mode 100644 index 2716df3a22..0000000000 --- a/Code/CryEngine/CrySystem/AndroidConsole.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Console implementation for Android, reports back to the main interface. - - -#include "CrySystem_precompiled.h" -#if defined(ANDROID) -#include "AndroidConsole.h" - -#include "android/log.h" -CAndroidConsole::CAndroidConsole() - : m_isInitialized(false) -{ -} - -CAndroidConsole::~CAndroidConsole() -{ -} - -// Interface IOutputPrintSink ///////////////////////////////////////////// -void CAndroidConsole::Print(const char* line) -{ - __android_log_print(ANDROID_LOG_VERBOSE, "CryEngine", "MSG: %s\n", line); -} -// Interface ISystemUserCallback ////////////////////////////////////////// -bool CAndroidConsole::OnError(const char* errorString) -{ - __android_log_print(ANDROID_LOG_ERROR, "CryEngine", "ERR: %s\n", errorString); - return true; -} - -void CAndroidConsole::OnInitProgress(const char* sProgressMsg) -{ - (void) sProgressMsg; - // Do Nothing -} -void CAndroidConsole::OnInit(ISystem* pSystem) -{ - if (!m_isInitialized) - { - IConsole* pConsole = pSystem->GetIConsole(); - if (pConsole != 0) - { - pConsole->AddOutputPrintSink(this); - } - m_isInitialized = true; - } -} -void CAndroidConsole::OnShutdown() -{ - if (m_isInitialized) - { - // remove outputprintsink - m_isInitialized = false; - } -} -void CAndroidConsole::OnUpdate() -{ - // Do Nothing -} -void CAndroidConsole::GetMemoryUsage(ICrySizer* pSizer) -{ - size_t size = sizeof(*this); - - - - pSizer->AddObject(this, size); -} - -// Interface ITextModeConsole ///////////////////////////////////////////// -Vec2_tpl CAndroidConsole::BeginDraw() -{ - return Vec2_tpl(0, 0); -} -void CAndroidConsole::PutText(int x, int y, const char* msg) -{ - __android_log_print(ANDROID_LOG_VERBOSE, "CryEngine", "PUT: %s\n", msg); -} -void CAndroidConsole::EndDraw() -{ - // Do Nothing -} -#endif // ANDROID diff --git a/Code/CryEngine/CrySystem/AndroidConsole.h b/Code/CryEngine/CrySystem/AndroidConsole.h deleted file mode 100644 index af45a68d5e..0000000000 --- a/Code/CryEngine/CrySystem/AndroidConsole.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Console implementation for Android, reports back to the main interface. - - -#ifndef CRYINCLUDE_CRYSYSTEM_ANDROIDCONSOLE_H -#define CRYINCLUDE_CRYSYSTEM_ANDROIDCONSOLE_H -#pragma once - - -#include -#include - - - -class CAndroidConsole - : public ISystemUserCallback - , public IOutputPrintSink - , public ITextModeConsole -{ - CAndroidConsole(const CAndroidConsole&); - CAndroidConsole& operator = (const CAndroidConsole&); - - bool m_isInitialized; -public: - static CryCriticalSectionNonRecursive s_lock; -public: - CAndroidConsole(); - ~CAndroidConsole(); - - // Interface IOutputPrintSink ///////////////////////////////////////////// - DLL_EXPORT virtual void Print(const char* line); - - // Interface ISystemUserCallback ////////////////////////////////////////// - virtual bool OnError(const char* errorString); - virtual bool OnSaveDocument() { return false; } - virtual void OnProcessSwitch() { } - virtual void OnInitProgress(const char* sProgressMsg); - virtual void OnInit(ISystem*); - virtual void OnShutdown(); - virtual void OnUpdate(); - virtual void GetMemoryUsage(ICrySizer* pSizer); - void SetRequireDedicatedServer(bool) {} - void SetHeader(const char*) {} - // Interface ITextModeConsole ///////////////////////////////////////////// - virtual Vec2_tpl BeginDraw(); - virtual void PutText(int x, int y, const char* msg); - virtual void EndDraw(); -}; - -#endif // CRYINCLUDE_CRYSYSTEM_ANDROIDCONSOLE_H diff --git a/Code/CryEngine/CrySystem/AsyncPakManager.cpp b/Code/CryEngine/CrySystem/AsyncPakManager.cpp deleted file mode 100644 index 40928715d8..0000000000 --- a/Code/CryEngine/CrySystem/AsyncPakManager.cpp +++ /dev/null @@ -1,516 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Manage async pak files - - -#include "CrySystem_precompiled.h" -#include "AsyncPakManager.h" -#include "System.h" -#include "IStreamEngine.h" -#include -#include -#include "ResourceManager.h" - -#define MEGA_BYTE 1024* 1024 - -////////////////////////////////////////////////////////////////////////// - -string& CAsyncPakManager::SAsyncPak::GetStatus(string& status) const -{ - switch (eState) - { - case STATE_UNLOADED: - status = "Unloaded"; - break; - case STATE_REQUESTED: - status = "Requested"; - break; - case STATE_REQUESTUNLOAD: - status = "RequestUnload"; - break; - case STATE_LOADED: - status = "Loaded"; - break; - default: - status = "Unknown"; - break; - } - - return status; -} - -////////////////////////////////////////////////////////////////////////// - -CAsyncPakManager::CAsyncPakManager() -{ - m_nTotalOpenLayerPakSize = 0; - m_bRequestLayerUpdate = false; -} - -CAsyncPakManager::~CAsyncPakManager() -{ - Clear(); -} - -////////////////////////////////////////////////////////////////////////// - -void CAsyncPakManager::Clear() -{ - //float startTime = gEnv->pTimer->GetAsyncCurTime(); - - for (TPakMap::iterator it = m_paks.begin(); - it != m_paks.end(); ++it) - { - SAsyncPak& layerPak = it->second; - if (layerPak.bStreaming) - { - // wait until finished - layerPak.pReadStream->Abort(); - } - - ReleaseData(&layerPak); - } - m_paks.clear(); - m_bRequestLayerUpdate = false; - - assert(m_nTotalOpenLayerPakSize == 0); - m_nTotalOpenLayerPakSize = 0; - - //printf("CAsyncPakManager::Clear() %0.4f secs\n", gEnv->pTimer->GetAsyncCurTime() - startTime); -} - -void CAsyncPakManager::UnloadLevelLoadPaks() -{ - for (TPakMap::iterator it = m_paks.begin(); - it != m_paks.end(); ++it) - { - SAsyncPak& layerPak = it->second; - - if (layerPak.eLifeTime == SAsyncPak::LIFETIME_LOAD_ONLY) - { - if (layerPak.bStreaming) - { - // wait until finished - layerPak.pReadStream->Abort(); - } - - ReleaseData(&layerPak); - } - } -} - -////////////////////////////////////////////////////////////////////////// - -void CAsyncPakManager::ParseLayerPaks(const string& levelCachePath) -{ - string layerPath = levelCachePath + "/"; // "/layers/"; - string search = layerPath + "*"; - auto pPak = gEnv->pCryPak; - - - // allow this find first to actually touch the file system - AZ::IO::ArchiveFileIterator fileIterator= pPak->FindFirst(search.c_str(), 0, true); - - if (fileIterator) - { - do - { - if ((fileIterator.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) == AZ::IO::FileDesc::Attribute::Subdirectory || fileIterator.m_filename == "." || fileIterator.m_filename == "..") - { - continue; - } - - string pakName(fileIterator.m_filename.data(), fileIterator.m_filename.size()); - size_t findPos = pakName.find_last_of('.'); - if (findPos == string::npos) - { - continue; - } - - string extension = pakName.substr(findPos + 1, pakName.size()); - if (extension != "pak") - { - continue; - } - - SAsyncPak layerPak; - layerPak.layername = pakName.substr(0, findPos); - layerPak.filename = layerPath + pakName; - layerPak.nSize = pPak->FGetSize(layerPak.filename.c_str(), true); // allow to go to disc for this access - layerPak.bClosePakOnRelease = true; - - m_paks[layerPak.layername] = layerPak; - } while (fileIterator = pPak->FindNext(fileIterator)); - - pPak->FindClose(fileIterator); - } -} - -////////////////////////////////////////////////////////////////////////// - -void CAsyncPakManager::StartStreaming(SAsyncPak* pLayerPak) -{ - StreamReadParams params; - params.dwUserData = (DWORD_PTR) pLayerPak; - params.nSize = 0; - params.pBuffer = NULL; - params.nFlags = IStreamEngine::FLAGS_FILE_ON_DISK; - params.ePriority = estpIdle; - - pLayerPak->pReadStream = gEnv->pSystem->GetStreamEngine()->StartRead(eStreamTaskTypePak, pLayerPak->filename.c_str(), this, ¶ms); - - if (pLayerPak->pReadStream) - { - pLayerPak->bStreaming = true; - } - else - { - pLayerPak->eState = SAsyncPak::STATE_UNLOADED; - pLayerPak->pData.reset(); - } -} - -void CAsyncPakManager::ReleaseData(SAsyncPak* pLayerPak) -{ - if (pLayerPak->eState == SAsyncPak::STATE_LOADED) - { - if (pLayerPak->bClosePakOnRelease) - { - gEnv->pCryPak->ClosePack(pLayerPak->filename.c_str(), 0); - //printf("Unload pak from mem: %s\n", pLayerPak->filename.c_str()); - } - else - { - gEnv->pCryPak->LoadPakToMemory(pLayerPak->filename.c_str(), AZ::IO::IArchive::eInMemoryPakLocale_Unload); - //printf("Close pak: %s\n", pLayerPak->filename.c_str()); - } - - m_nTotalOpenLayerPakSize -= pLayerPak->nSize; - } - - if (pLayerPak->pData) - { - assert(pLayerPak->pData->use_count() == 1); - } - - assert((!pLayerPak->pData) || (pLayerPak->pData && pLayerPak->pData->use_count() == 1)); - pLayerPak->pData.reset(); - pLayerPak->eState = SAsyncPak::STATE_UNLOADED; - - m_bRequestLayerUpdate = true; -} - -////////////////////////////////////////////////////////////////////////// - -bool CAsyncPakManager::LoadLayerPak(const char* sLayerName) -{ - // only load layer paks from valid files - TPakMap::iterator findResult = m_paks.find(sLayerName); - if (findResult != m_paks.end()) - { - return LoadPak(findResult->second); - } - - return false; -} - - -bool CAsyncPakManager::LoadPakToMemAsync(const char* pPath, bool bLevelLoadOnly) -{ - //check if pak reference exists - TPakMap::iterator findResult = m_paks.find(pPath); - if (findResult != m_paks.end()) - { - return LoadPak(findResult->second); - } - else - { - char szFullPathBuf[AZ::IO::IArchive::MaxPath]; - const char* szFullPath = gEnv->pCryPak->AdjustFileName(pPath, szFullPathBuf, AZ_ARRAY_SIZE(szFullPathBuf), AZ::IO::IArchive::FOPEN_HINT_QUIET | AZ::IO::IArchive::FLAGS_PATH_REAL); - - // Check if the pak file actually exists before trying to load - if (!gEnv->pCryPak->IsFileExist(szFullPath, AZ::IO::IArchive::eFileLocation_Any)) - { - // Cached file does not exist - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Level cache pak file %s does not exist", szFullPath); - return false; - } - - SAsyncPak layerPak; - layerPak.layername = pPath; - layerPak.filename = szFullPathBuf; - layerPak.nSize = 0; - layerPak.eLifeTime = bLevelLoadOnly ? SAsyncPak::LIFETIME_LOAD_ONLY : SAsyncPak::LIFETIME_LEVEL_COMPLETE; - - m_paks[layerPak.layername] = layerPak; - - return LoadPak(m_paks[layerPak.layername]); - } - return false; -} - -bool CAsyncPakManager::LoadPak(SAsyncPak& layerPak) -{ - layerPak.nRequestCount++; - if (layerPak.eState == SAsyncPak::STATE_LOADED || layerPak.bStreaming || - layerPak.eState == SAsyncPak::STATE_REQUESTED) - { - return true; - } - - layerPak.eState = SAsyncPak::STATE_REQUESTED; - - //printf("Streaming level pak: %s\n", layerPak.layername.c_str()); - - StartStreaming(&layerPak); - - return false; -} - -////////////////////////////////////////////////////////////////////////// - -void CAsyncPakManager::UnloadLayerPak(const char* sLayerName) -{ - TPakMap::iterator findResult = m_paks.find(sLayerName); - if (findResult == m_paks.end()) - { - return; - } - - SAsyncPak& layerPak = findResult->second; - layerPak.nRequestCount--; - assert(layerPak.nRequestCount >= 0); - if (layerPak.nRequestCount > 0) - { - return; - } - - if (layerPak.bStreaming) - { - if (layerPak.pReadStream) - { - layerPak.pReadStream->Abort(); - } - layerPak.eState = SAsyncPak::STATE_REQUESTUNLOAD; - return; - } - - if (layerPak.eState == SAsyncPak::STATE_LOADED) - { - ReleaseData(&layerPak); - m_bRequestLayerUpdate = true; - } - - if (layerPak.eState == SAsyncPak::STATE_REQUESTED) - { - layerPak.eState = SAsyncPak::STATE_UNLOADED; - } -} - -////////////////////////////////////////////////////////////////////////// - -void CAsyncPakManager::GetLayerPakStats( - SLayerPakStats& stats, bool bCollectAllStats) const -{ - stats.m_MaxSize = (g_cvars.archiveVars.nTotalInMemoryPakSizeLimit * MEGA_BYTE); - stats.m_UsedSize = m_nTotalOpenLayerPakSize; - - for (TPakMap::const_iterator it = m_paks.begin(); it != m_paks.end(); ++it) - { - const SAsyncPak& layerPak = it->second; - if (bCollectAllStats || layerPak.eState != SAsyncPak::STATE_UNLOADED) - { - SLayerPakStats::SEntry entry; - entry.name = it->first; - entry.nSize = layerPak.nSize; - entry.bStreaming = layerPak.bStreaming; - layerPak.GetStatus(entry.status); - - stats.m_entries.push_back(entry); - } - } -} - -////////////////////////////////////////////////////////////////////////// - -void CAsyncPakManager::StreamAsyncOnComplete( - IReadStream* pStream, unsigned nError) -{ - if (nError != 0) - { - return; - } - - SAsyncPak* pLayerPak = (SAsyncPak*) pStream->GetUserData(); - - //Check is pak is already open, if so, just assign mem - if (gEnv->pCryPak->LoadPakToMemory(pLayerPak->filename.c_str(), AZ::IO::IArchive::eInMemoryPakLocale_GPU, pLayerPak->pData)) - { - pLayerPak->bPakAlreadyOpen = true; - } - else - { - bool usePrefabSystemForLevels = false; - AzFramework::ApplicationRequests::Bus::BroadcastResult( - usePrefabSystemForLevels, - &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled); - - if (usePrefabSystemForLevels) - { - gEnv->pCryPak->OpenPack( - "@assets@", {pLayerPak->filename.c_str(), pLayerPak->filename.size()}, AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32, NULL); - } - else - { - // - // ugly hack - depending on the pak file pak may need special root info / open flags - // - if (pLayerPak->layername.find("level.pak") != string::npos) - { - gEnv->pCryPak->OpenPack( - {pLayerPak->filename.c_str(), pLayerPak->filename.size()}, AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32, NULL); - } - else if (pLayerPak->layername.find("levelshadercache.pak") != string::npos) - { - gEnv->pCryPak->OpenPack( - "@assets@", {pLayerPak->filename.c_str(), pLayerPak->filename.size()}, AZ::IO::IArchive::FLAGS_PATH_REAL, NULL); - } - else - { - gEnv->pCryPak->OpenPack( - "@assets@", {pLayerPak->filename.c_str(), pLayerPak->filename.size()}, AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32, - NULL); - } - } - gEnv->pCryPak->LoadPakToMemory(pLayerPak->filename.c_str(), AZ::IO::IArchive::eInMemoryPakLocale_GPU, pLayerPak->pData); - } - - pLayerPak->eState = SAsyncPak::STATE_LOADED; - - //printf("Finished streaming level pak: %s\n", pLayerPak->layername.c_str()); -} - -////////////////////////////////////////////////////////////////////////// - -void CAsyncPakManager::StreamOnComplete( - IReadStream* pStream, unsigned nError) -{ - SAsyncPak* pLayerPak = (SAsyncPak*) pStream->GetUserData(); - - if (nError != 0) - { - ReleaseData(pLayerPak); - } - - pLayerPak->bStreaming = false; - pLayerPak->pReadStream = NULL; - - m_bRequestLayerUpdate = true; -} - -void* CAsyncPakManager::StreamOnNeedStorage(IReadStream* pStream, unsigned nSize, bool& bAbortOnFailToAlloc) -{ - SAsyncPak* pAsyncPak = (SAsyncPak*)pStream->GetUserData(); - - pAsyncPak->nSize = nSize; - - if ((m_nTotalOpenLayerPakSize + nSize) > (size_t)(g_cvars.archiveVars.nTotalInMemoryPakSizeLimit * MEGA_BYTE)) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Not enough space to load in memory layer pak %s (Current: %" PRISIZE_T " Required: %d)", - pAsyncPak->filename.c_str(), m_nTotalOpenLayerPakSize, nSize); - - //printf("Not enough space to load in memory layer pak %s (Current: %d Required: %d)\n", pAsyncPak->filename.c_str(), m_nTotalOpenLayerPakSize, nSize); - - pAsyncPak->eState = SAsyncPak::STATE_UNLOADED; - pAsyncPak->bStreaming = false; - pAsyncPak->pReadStream = NULL; - - bAbortOnFailToAlloc = true; - - return NULL; - } - - if (nSize) - { - auto pCryPak = static_cast(gEnv->pCryPak); - - // allocate the data - const char* szUsage = "In Memory Zip File"; - pAsyncPak->pData = pCryPak->PoolAllocMemoryBlock(nSize, szUsage, alignof(uint8_t)); - - m_nTotalOpenLayerPakSize += nSize; - - return pAsyncPak->pData->m_address.get(); - } - return NULL; -} - -////////////////////////////////////////////////////////////////////////// - -void CAsyncPakManager::Update() -{ - if (!m_bRequestLayerUpdate) - { - return; - } - - m_bRequestLayerUpdate = false; - - for (TPakMap::iterator it = m_paks.begin(); - it != m_paks.end(); ++it) - { - SAsyncPak& layerPak = it->second; - if (!layerPak.bStreaming) - { - if (layerPak.eState == SAsyncPak::STATE_REQUESTUNLOAD) - { - // done streaming and not interested in it anymore, then release it again - ReleaseData(&layerPak); - } - else if (layerPak.eState == SAsyncPak::STATE_REQUESTED && - (m_nTotalOpenLayerPakSize + layerPak.nSize <= ((size_t)g_cvars.archiveVars.nTotalInMemoryPakSizeLimit * MEGA_BYTE))) - { - // do we have enough memory now to start streaming the pak - StartStreaming(&layerPak); - } - } - } -} - -// Abort streaming jobs and prevent any more requests -// Paks which are loaded remain, they will be cleaned up as usual -void CAsyncPakManager::CancelPendingJobs() -{ - for (TPakMap::iterator it = m_paks.begin(); it != m_paks.end(); ++it) - { - SAsyncPak& layerPak = it->second; - - if (layerPak.bStreaming) - { - layerPak.pReadStream->Abort(); - ReleaseData(&layerPak); - - //printf("Pak %s Aborted\n", layerPak.filename.c_str()); - } - else if (layerPak.eState == SAsyncPak::STATE_REQUESTED) - { - layerPak.eState = SAsyncPak::STATE_UNLOADED; - ReleaseData(&layerPak); - - //printf("Pak %s Cancelled\n", layerPak.filename.c_str()); - } - } -} - -////////////////////////////////////////////////////////////////////////// diff --git a/Code/CryEngine/CrySystem/AsyncPakManager.h b/Code/CryEngine/CrySystem/AsyncPakManager.h deleted file mode 100644 index 92a319c73c..0000000000 --- a/Code/CryEngine/CrySystem/AsyncPakManager.h +++ /dev/null @@ -1,116 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Manage async pak files - -#ifndef CRYINCLUDE_CRYSYSTEM_ASYNCPAKMANAGER_H -#define CRYINCLUDE_CRYSYSTEM_ASYNCPAKMANAGER_H -#pragma once - -#include -#include -#include - -namespace AZ::IO -{ - struct MemoryBlock; -} - -class CAsyncPakManager - : public IStreamCallback -{ -protected: - - struct SAsyncPak - { - enum EState - { - STATE_UNLOADED, - STATE_REQUESTED, - STATE_REQUESTUNLOAD, - STATE_LOADED, - }; - - enum ELifeTime - { - LIFETIME_LOAD_ONLY, - LIFETIME_LEVEL_COMPLETE, - LIFETIME_PERMANENT - }; - - SAsyncPak() - : nRequestCount(0) - , eState(STATE_UNLOADED) - , eLifeTime(LIFETIME_LOAD_ONLY) - , nSize(0) - , pData(0) - , bStreaming(false) - , bPakAlreadyOpen(false) - , bClosePakOnRelease(false) - , pReadStream(0) {} - - string& GetStatus(string&) const; - - string layername; - string filename; - size_t nSize; - AZStd::intrusive_ptr pData; - EState eState; - ELifeTime eLifeTime; - bool bStreaming; - bool bPakAlreadyOpen; - bool bClosePakOnRelease; - int nRequestCount; - IReadStreamPtr pReadStream; - }; - typedef std::map TPakMap; - -public: - - CAsyncPakManager(); - ~CAsyncPakManager(); - - void ParseLayerPaks(const string& levelCachePath); - - bool LoadPakToMemAsync(const char* pPath, bool bLevelLoadOnly); - void UnloadLevelLoadPaks(); - bool LoadLayerPak(const char* sLayerName); - void UnloadLayerPak(const char* sLayerName); - void CancelPendingJobs(); - - void GetLayerPakStats(SLayerPakStats& stats, bool bCollectAllStats) const; - - void Clear(); - void Update(); - -protected: - - bool LoadPak(SAsyncPak& layerPak); - - void StartStreaming(SAsyncPak* pLayerPak); - void ReleaseData(SAsyncPak* pLayerPak); - - ////////////////////////////////////////////////////////////////////////// - // IStreamCallback interface implementation. - ////////////////////////////////////////////////////////////////////////// - virtual void StreamAsyncOnComplete (IReadStream* pStream, unsigned nError); - virtual void StreamOnComplete (IReadStream* pStream, unsigned nError); - virtual void* StreamOnNeedStorage(IReadStream* pStream, unsigned nSize, bool& bAbortOnFailToAlloc); - ////////////////////////////////////////////////////////////////////////// - - TPakMap m_paks; - size_t m_nTotalOpenLayerPakSize; - bool m_bRequestLayerUpdate; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_ASYNCPAKMANAGER_H diff --git a/Code/CryEngine/CrySystem/AutoDetectSpec.cpp b/Code/CryEngine/CrySystem/AutoDetectSpec.cpp deleted file mode 100644 index aa344684e3..0000000000 --- a/Code/CryEngine/CrySystem/AutoDetectSpec.cpp +++ /dev/null @@ -1,1097 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" - -#if defined(WIN32) || defined(WIN64) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "System.h" -#include "AutoDetectSpec.h" - -// both function live in CPUDetect.cpp -bool IsAMD(); -bool IsIntel(); - - -static void TrimExcessiveWhiteSpaces(char* pStr) -{ - size_t len(strlen(pStr)); - bool remove(true); - for (size_t i(0); i < len; ++i) - { - if (pStr[i] == ' ' && remove) - { - size_t newlen(len - 1); - - size_t j(i + 1); - for (; j < len && pStr[j] == ' '; ++j) - { - --newlen; - } - - size_t ii(i); - for (; j < len + 1; ++j, ++ii) - { - pStr[ii] = pStr[j]; - } - - assert(newlen == strlen(pStr)); - len = newlen; - remove = false; - } - else - { - remove = pStr[i] == ' '; - } - } - - if (len > 0 && pStr[len - 1] == ' ') - { - pStr[len - 1] = '\0'; - } -} - - -static void GetCPUName(char* pName, size_t bufferSize) -{ - if (!pName || !bufferSize) - { - return; - } - - char name[12 * 4 + 1]; - - int CPUInfo[4]; - __cpuid(CPUInfo, 0x80000000); - if (CPUInfo[0] >= 0x80000004) - { - __cpuid(CPUInfo, 0x80000002); - ((int*)name)[0] = CPUInfo[0]; - ((int*)name)[1] = CPUInfo[1]; - ((int*)name)[2] = CPUInfo[2]; - ((int*)name)[3] = CPUInfo[3]; - - __cpuid(CPUInfo, 0x80000003); - ((int*)name)[4] = CPUInfo[0]; - ((int*)name)[5] = CPUInfo[1]; - ((int*)name)[6] = CPUInfo[2]; - ((int*)name)[7] = CPUInfo[3]; - - __cpuid(CPUInfo, 0x80000004); - ((int*)name)[8] = CPUInfo[0]; - ((int*)name)[9] = CPUInfo[1]; - ((int*)name)[10] = CPUInfo[2]; - ((int*)name)[11] = CPUInfo[3]; - - name[48] = '\0'; - } - else - { - name[0] = '\0'; - } - - int ret(azsnprintf(pName, bufferSize, name)); - if (ret >= bufferSize || ret < 0) - { - pName[bufferSize - 1] = '\0'; - } -} - - -void Win32SysInspect::GetOS(SPlatformInfo::EWinVersion& ver, bool& is64Bit, char* pName, size_t bufferSize) -{ - ver = SPlatformInfo::WinUndetected; - is64Bit = false; - - if (pName && bufferSize) - { - pName[0] = '\0'; - } - - //GetVersionEx was changed to work based on how the application is manifest - //meaning we have to specifically state that this application supports - //Windows 10, Windows 8.1 etc if we want GetVersionEx to return those version numbers. - //RtlGetVersion does not require a manifest. - auto RtlGetVersion = reinterpret_cast(GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion")); - AZ_Assert(RtlGetVersion, "Failed to get address to RtlGetVersion from ntdll.dll"); - - RTL_OSVERSIONINFOEXW sysInfo; - sysInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); - - if (RtlGetVersion(&sysInfo) == 0) - { - if (sysInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - if (sysInfo.dwMajorVersion == 5) - { - if (sysInfo.dwMinorVersion == 0) - { - ver = SPlatformInfo::Win2000; - } - else if (sysInfo.dwMinorVersion == 1) - { - ver = SPlatformInfo::WinXP; - } - else if (sysInfo.dwMinorVersion == 2) - { - if (sysInfo.wProductType == VER_NT_WORKSTATION) - { - ver = SPlatformInfo::WinXP; // 64 bit windows actually but this will be detected later anyway - } - else if (sysInfo.wProductType == VER_NT_SERVER || sysInfo.wProductType == VER_NT_DOMAIN_CONTROLLER) - { - ver = SPlatformInfo::WinSrv2003; - } - } - } - else if (sysInfo.dwMajorVersion == 6) - { - if (sysInfo.dwMinorVersion == 0) - { - ver = SPlatformInfo::WinVista; - } - else if (sysInfo.dwMinorVersion == 1) - { - ver = SPlatformInfo::Win7; - } - else if (sysInfo.dwMinorVersion == 2) - { - ver = SPlatformInfo::Win8; - } - else if (sysInfo.dwMinorVersion == 3) - { - ver = SPlatformInfo::Win81; - } - } - else if (sysInfo.dwMajorVersion == 10) - { - ver = SPlatformInfo::Win10; - } - } - - typedef BOOL (WINAPI * FP_GetSystemWow64Directory)(LPSTR, UINT); - FP_GetSystemWow64Directory pgsw64d((FP_GetSystemWow64Directory) GetProcAddress(GetModuleHandle("kernel32"), "GetSystemWow64DirectoryA")); - if (pgsw64d) - { - char str[MAX_PATH]; - if (!pgsw64d(str, sizeof(str))) - { - is64Bit = GetLastError() != ERROR_CALL_NOT_IMPLEMENTED; - } - else - { - is64Bit = true; - } - } - - if (pName && bufferSize) - { - const char* windowsVersionText(0); - switch (ver) - { - case SPlatformInfo::Win2000: - windowsVersionText = "Windows 2000"; - break; - case SPlatformInfo::WinXP: - windowsVersionText = "Windows XP"; - break; - case SPlatformInfo::WinSrv2003: - windowsVersionText = "Windows Server 2003"; - break; - case SPlatformInfo::WinVista: - windowsVersionText = "Windows Vista"; - break; - case SPlatformInfo::Win7: - windowsVersionText = "Windows 7"; - break; - case SPlatformInfo::Win8: - windowsVersionText = "Windows 8"; - break; - case SPlatformInfo::Win81: - windowsVersionText = "Windows 8.1"; - break; - case SPlatformInfo::Win10: - windowsVersionText = "Windows 10"; - break; - default: - windowsVersionText = "Windows"; - break; - } - - char sptext[32]; - sptext[0] = '\0'; - if (sysInfo.wServicePackMajor > 0) - { - azsnprintf(sptext, sizeof(sptext), "SP %d ", sysInfo.wServicePackMajor); - } - - int ret(azsnprintf(pName, bufferSize, "%s %s %s(build %d.%d.%d)", windowsVersionText, is64Bit ? "64 bit" : "32 bit", - sptext, sysInfo.dwMajorVersion, sysInfo.dwMinorVersion, sysInfo.dwBuildNumber)); - if (ret >= bufferSize || ret < 0) - { - pName[bufferSize - 1] = '\0'; - } - } - } -} - -bool Win32SysInspect::IsVistaKB940105Required() -{ -#if defined(WIN32) && !defined(WIN64) - OSVERSIONINFO osv; - memset(&osv, 0, sizeof(osv)); - osv.dwOSVersionInfoSize = sizeof(osv); - GetVersionEx(&osv); - - if (osv.dwMajorVersion != 6 || osv.dwMinorVersion != 0 || (osv.dwBuildNumber > 6000)) - { - // This QFE only ever applies to Windows Vista RTM. Windows Vista SP1 already has this fix, - // and earlier versions of Windows do not implement WDDM - return false; - } - - //MEMORYSTATUSEX mex; - //memset(&mex, 0, sizeof(mex)); - //mex.dwLength = sizeof(mex); - //GlobalMemoryStatusEx(&mex); - - //if (mex.ullTotalVirtual >= 4294836224) - //{ - // // If there is 4 GB of VA space total for this process, then we are a - // // 32-bit Large Address Aware application running on a Windows 64-bit OS. - - // // We could be a 32-bit Large Address Aware application running on a - // // Windows 32-bit OS and get up to 3 GB, but that has stability implications. - // // Therefore, we recommend the QFE for all 32-bit versions of the OS. - - // // No need for the fix unless the game is pushing 4 GB of VA - // return false; - //} - - const char* sysFile = "dxgkrnl.sys"; - - // Ensure we are checking the system copy of the file - char sysPath[MAX_PATH]; - GetSystemDirectory(sysPath, sizeof(sysPath)); - - cry_strcat(sysPath, "\\drivers\\"); - cry_strcat(sysPath, sysFile); - - char buf[2048]; - if (!GetFileVersionInfo(sysPath, 0, sizeof(buf), buf)) - { - // This should never happen, but we'll assume it's a newer .sys file since we've - // narrowed the test to a Windows Vista RTM OS. - return false; - } - - VS_FIXEDFILEINFO* ver; - UINT size; - if (!VerQueryValue(buf, "\\", (void**) &ver, &size) || size != sizeof(VS_FIXEDFILEINFO) || ver->dwSignature != 0xFEEF04BD) - { - // This should never happen, but we'll assume it's a newer .sys file since we've - // narrowed the test to a Windows Vista RTM OS. - return false; - } - - // File major.minor.build.qfe version comparison - // WORD major = HIWORD( ver->dwFileVersionMS ); WORD minor = LOWORD( ver->dwFileVersionMS ); - // WORD build = HIWORD( ver->dwFileVersionLS ); WORD qfe = LOWORD( ver->dwFileVersionLS ); - - if (ver->dwFileVersionMS > MAKELONG(0, 6) || (ver->dwFileVersionMS == MAKELONG(0, 6) && ver->dwFileVersionLS >= MAKELONG(20648, 6000))) - { - // QFE fix version of dxgkrnl.sys is 6.0.6000.20648 - return false; - } - - return true; -#else - return false; // The QFE is not required for a 64-bit native application as it has 8 TB of VA -#endif -} - - -static void GetSystemMemory(uint64& totSysMem) -{ - typedef BOOL (WINAPI * FP_GlobalMemoryStatusEx)(LPMEMORYSTATUSEX); - FP_GlobalMemoryStatusEx pgmsex((FP_GlobalMemoryStatusEx) GetProcAddress(GetModuleHandle("kernel32"), "GlobalMemoryStatusEx")); - if (pgmsex) - { - MEMORYSTATUSEX memStats; - memStats.dwLength = sizeof(memStats); - if (pgmsex(&memStats)) - { - totSysMem = memStats.ullTotalPhys; - } - else - { - totSysMem = 0; - } - } - else - { - MEMORYSTATUS memStats; - memStats.dwLength = sizeof(memStats); - GlobalMemoryStatus(&memStats); - totSysMem = memStats.dwTotalPhys; - } -} - - -static bool IsVistaOrAbove() -{ - typedef BOOL (WINAPI * FP_VerifyVersionInfo)(LPOSVERSIONINFOEX, DWORD, DWORDLONG); - FP_VerifyVersionInfo pvvi((FP_VerifyVersionInfo) GetProcAddress(GetModuleHandle("kernel32"), "VerifyVersionInfoA")); - - if (pvvi) - { - typedef ULONGLONG (WINAPI * FP_VerSetConditionMask)(ULONGLONG, DWORD, BYTE); - FP_VerSetConditionMask pvscm((FP_VerSetConditionMask) GetProcAddress(GetModuleHandle("kernel32"), "VerSetConditionMask")); - assert(pvscm); - - OSVERSIONINFOEX osvi; - memset(&osvi, 0, sizeof(osvi)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - osvi.dwMajorVersion = 6; - osvi.dwMinorVersion = 0; - osvi.wServicePackMajor = 0; - osvi.wServicePackMinor = 0; - - ULONGLONG mask(0); - mask = pvscm(mask, VER_MAJORVERSION, VER_GREATER_EQUAL); - mask = pvscm(mask, VER_MINORVERSION, VER_GREATER_EQUAL); - mask = pvscm(mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - mask = pvscm(mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); - - if (pvvi(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, mask)) - { - return true; - } - } - - return false; -} - - -// Preferred solution to determine the number of available CPU cores, works reliably only on WinVista/Win7 32/64 and above -// See http://msdn2.microsoft.com/en-us/library/ms686694.aspx for reasons -static void GetNumCPUCoresGlpi(unsigned int& totAvailToSystem, unsigned int& totAvailToProcess) -{ - typedef BOOL (WINAPI * FP_GetLogicalProcessorInformation)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); - FP_GetLogicalProcessorInformation pglpi((FP_GetLogicalProcessorInformation) GetProcAddress(GetModuleHandle("kernel32"), "GetLogicalProcessorInformation")); - if (pglpi && IsVistaOrAbove()) - { - unsigned long bufferSize(0); - pglpi(0, &bufferSize); - - void* pBuffer(alloca(bufferSize)); - - SYSTEM_LOGICAL_PROCESSOR_INFORMATION* pLogProcInfo((SYSTEM_LOGICAL_PROCESSOR_INFORMATION*) pBuffer); - if (pLogProcInfo && pglpi(pLogProcInfo, &bufferSize)) - { - DWORD_PTR processAffinity, systemAffinity; - GetProcessAffinityMask(GetCurrentProcess(), &processAffinity, &systemAffinity); - - unsigned long numEntries(bufferSize / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); - for (unsigned long i(0); i < numEntries; ++i) - { - switch (pLogProcInfo[i].Relationship) - { - case RelationProcessorCore: - { - ++totAvailToSystem; - if (pLogProcInfo[i].ProcessorMask & processAffinity) - { - ++totAvailToProcess; - } - } - break; - - default: - break; - } - } - } - } -} - - -class CApicExtractor -{ -public: - CApicExtractor(unsigned int logProcsPerPkg = 1, unsigned int coresPerPkg = 1) - { - SetPackageTopology(logProcsPerPkg, coresPerPkg); - } - - unsigned char SmtId(unsigned char apicId) const - { - return apicId & m_smtIdMask.mask; - } - - unsigned char CoreId(unsigned char apicId) const - { - return (apicId & m_coreIdMask.mask) >> m_smtIdMask.width; - } - - unsigned char PackageId(unsigned char apicId) const - { - return (apicId & m_pkgIdMask.mask) >> (m_smtIdMask.width + m_coreIdMask.width); - } - - unsigned char PackageCoreId(unsigned char apicId) const - { - return (apicId & (m_pkgIdMask.mask | m_coreIdMask.mask)) >> m_smtIdMask.width; - } - - unsigned int GetLogProcsPerPkg() const - { - return m_logProcsPerPkg; - } - - unsigned int GetCoresPerPkg() const - { - return m_coresPerPkg; - } - - void SetPackageTopology(unsigned int logProcsPerPkg, unsigned int coresPerPkg) - { - m_logProcsPerPkg = (unsigned char) logProcsPerPkg; - m_coresPerPkg = (unsigned char) coresPerPkg; - - m_smtIdMask.width = GetMaskWidth(m_logProcsPerPkg / m_coresPerPkg); - m_coreIdMask.width = GetMaskWidth(m_coresPerPkg); - m_pkgIdMask.width = 8 - (m_smtIdMask.width + m_coreIdMask.width); - - m_pkgIdMask.mask = (unsigned char) (0xFF << (m_smtIdMask.width + m_coreIdMask.width)); - m_coreIdMask.mask = (unsigned char) ((0xFF << m_smtIdMask.width) ^ m_pkgIdMask.mask); - m_smtIdMask.mask = (unsigned char) ~(0xFF << m_smtIdMask.width); - } - -private: - unsigned char GetMaskWidth(unsigned char maxIds) const - { - --maxIds; - unsigned char msbIdx(8); - unsigned char msbMask(0x80); - while (msbMask && !(msbMask & maxIds)) - { - --msbIdx; - msbMask >>= 1; - } - return msbIdx; - } - - struct IdMask - { - unsigned char width; - unsigned char mask; - }; - - unsigned char m_logProcsPerPkg; - unsigned char m_coresPerPkg; - IdMask m_smtIdMask; - IdMask m_coreIdMask; - IdMask m_pkgIdMask; -}; - - -// Fallback solution for WinXP 32/64 -static void GetNumCPUCoresApic(unsigned int& totAvailToSystem, unsigned int& totAvailToProcess) -{ - unsigned int numLogicalPerPhysical(1); - unsigned int numCoresPerPhysical(1); - - int CPUInfo[4]; - __cpuid(CPUInfo, 0x00000001); - if ((CPUInfo[3] & 0x10000000) != 0) // Hyperthreading / Multicore bit set - { - numLogicalPerPhysical = (CPUInfo[1] & 0x00FF0000) >> 16; - - if (IsIntel()) - { - __cpuid(CPUInfo, 0x00000000); - if (CPUInfo[0] >= 0x00000004) - { - __cpuidex(CPUInfo, 4, 0); - numCoresPerPhysical = ((CPUInfo[0] & 0xFC000000) >> 26) + 1; - } - } - else if (IsAMD()) - { - __cpuid(CPUInfo, 0x80000000); - if (CPUInfo[0] >= 0x80000008) - { - __cpuid(CPUInfo, 0x80000008); - if (CPUInfo[2] & 0x0000F000) - { - numCoresPerPhysical = 1 << ((CPUInfo[2] & 0x0000F000) >> 12); - } - else - { - numCoresPerPhysical = (CPUInfo[2] & 0xFF) + 1; - } - } - } - } - - HANDLE hCurProcess(GetCurrentProcess()); - HANDLE hCurThread(GetCurrentThread()); - - const int c_maxLogicalProcessors(sizeof(DWORD_PTR) * 8); - unsigned char apicIds[c_maxLogicalProcessors] = { 0 }; - unsigned char items(0); - - DWORD_PTR processAffinity, systemAffinity; - GetProcessAffinityMask(hCurProcess, &processAffinity, &systemAffinity); - - if (systemAffinity == 1) - { - assert(numLogicalPerPhysical == 1); - apicIds[items++] = 0; - } - else - { - if (processAffinity != systemAffinity) - { - SetProcessAffinityMask(hCurProcess, systemAffinity); - } - - DWORD_PTR prevThreadAffinity(0); - for (DWORD_PTR threadAffinity = 1; threadAffinity && threadAffinity <= systemAffinity; threadAffinity <<= 1) - { - if (systemAffinity & threadAffinity) - { - if (!prevThreadAffinity) - { - assert(!items); - prevThreadAffinity = SetThreadAffinityMask(hCurThread, threadAffinity); - } - else - { - assert(items > 0); - SetThreadAffinityMask(hCurThread, threadAffinity); - } - - Sleep(0); - - int CPUInfo2[4]; - __cpuid(CPUInfo2, 0x00000001); - apicIds[items++] = (unsigned char) ((CPUInfo2[1] & 0xFF000000) >> 24); - } - } - - SetProcessAffinityMask(hCurProcess, processAffinity); - SetThreadAffinityMask(hCurThread, prevThreadAffinity); - Sleep(0); - } - - CApicExtractor apicExtractor(numLogicalPerPhysical, numCoresPerPhysical); - - totAvailToSystem = 0; - { - unsigned char pkgCoreIds[c_maxLogicalProcessors] = { 0 }; - for (unsigned int i(0); i < items; ++i) - { - unsigned int j(0); - for (; j < totAvailToSystem; ++j) - { - if (pkgCoreIds[j] == apicExtractor.PackageCoreId(apicIds[i])) - { - break; - } - } - if (j == totAvailToSystem) - { - pkgCoreIds[j] = apicExtractor.PackageCoreId(apicIds[i]); - ++totAvailToSystem; - } - } - } - - totAvailToProcess = 0; - { - unsigned char pkgCoreIds[c_maxLogicalProcessors] = { 0 }; - for (unsigned int i(0); i < items; ++i) - { - if (processAffinity & ((DWORD_PTR) 1 << i)) - { - unsigned int j(0); - for (; j < totAvailToProcess; ++j) - { - if (pkgCoreIds[j] == apicExtractor.PackageCoreId(apicIds[i])) - { - break; - } - } - if (j == totAvailToProcess) - { - pkgCoreIds[j] = apicExtractor.PackageCoreId(apicIds[i]); - ++totAvailToProcess; - } - } - } - } -} - -const char* Win32SysInspect::GetFeatureLevelAsString(Win32SysInspect::DXFeatureLevel featureLevel) -{ - switch (featureLevel) - { - case Win32SysInspect::DXFL_Undefined: - return "unknown"; - case Win32SysInspect::DXFL_9_1: - return "DX9 (SM 2.0)"; - case Win32SysInspect::DXFL_9_2: - return "DX9 (SM 2.0)"; - case Win32SysInspect::DXFL_9_3: - return "DX9 (SM 2.x)"; - case Win32SysInspect::DXFL_10_0: - return "DX10 (SM 4.0)"; - case Win32SysInspect::DXFL_10_1: - return "DX10.1 (SM 4.x)"; - case Win32SysInspect::DXFL_11_0: - default: - return "DX11 (SM 5.0)"; - } -} - -void Win32SysInspect::GetNumCPUCores(unsigned int& totAvailToSystem, unsigned int& totAvailToProcess) -{ - totAvailToSystem = 0; - totAvailToProcess = 0; - - GetNumCPUCoresGlpi(totAvailToSystem, totAvailToProcess); - - if (!totAvailToSystem) - { - GetNumCPUCoresApic(totAvailToSystem, totAvailToProcess); - } -} - - -static Win32SysInspect::DXFeatureLevel GetFeatureLevel(D3D_FEATURE_LEVEL featureLevel) -{ - switch (featureLevel) - { - case D3D_FEATURE_LEVEL_9_1: - return Win32SysInspect::DXFL_9_1; - case D3D_FEATURE_LEVEL_9_2: - return Win32SysInspect::DXFL_9_2; - case D3D_FEATURE_LEVEL_9_3: - return Win32SysInspect::DXFL_9_3; - case D3D_FEATURE_LEVEL_10_0: - return Win32SysInspect::DXFL_10_0; - case D3D_FEATURE_LEVEL_10_1: - return Win32SysInspect::DXFL_10_1; - case D3D_FEATURE_LEVEL_11_0: - default: - return Win32SysInspect::DXFL_11_0; - } -} - -static bool FindGPU(DXGI_ADAPTER_DESC1& adapterDesc, Win32SysInspect::DXFeatureLevel& featureLevel) -{ - memset(&adapterDesc, 0, sizeof(adapterDesc)); - featureLevel = Win32SysInspect::DXFL_Undefined; - - if (!IsVistaOrAbove()) - { - return false; - } - - typedef HRESULT (WINAPI * FP_CreateDXGIFactory1)(REFIID, void**); - FP_CreateDXGIFactory1 pCDXGIF = (FP_CreateDXGIFactory1) GetProcAddress(LoadLibraryA("dxgi.dll"), "CreateDXGIFactory1"); - - IDXGIFactory1* pFactory = 0; - if (pCDXGIF && SUCCEEDED(pCDXGIF(__uuidof(IDXGIFactory1), (void**) &pFactory)) && pFactory) - { - typedef HRESULT (WINAPI * FP_D3D11CreateDevice)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**); - FP_D3D11CreateDevice pD3D11CD = (FP_D3D11CreateDevice) GetProcAddress(LoadLibraryA("d3d11.dll"), "D3D11CreateDevice"); - - if (pD3D11CD) - { - unsigned int nAdapter = 0; - IDXGIAdapter1* pAdapter = 0; - while (pFactory->EnumAdapters1(nAdapter, &pAdapter) != DXGI_ERROR_NOT_FOUND) - { - if (pAdapter) - { - ID3D11Device* pDevice = 0; - D3D_FEATURE_LEVEL levels[] = {D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1}; - D3D_FEATURE_LEVEL deviceFeatureLevel = D3D_FEATURE_LEVEL_9_1; - HRESULT hr = pD3D11CD(pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, levels, sizeof(levels) / sizeof(levels[0]), D3D11_SDK_VERSION, &pDevice, &deviceFeatureLevel, NULL); - if (SUCCEEDED(hr) && pDevice) - { - IDXGIOutput* pOutput = 0; - const bool displaysConnected = SUCCEEDED(pAdapter->EnumOutputs(0, &pOutput)) && pOutput; - SAFE_RELEASE(pOutput); - - DXGI_ADAPTER_DESC1 ad; - pAdapter->GetDesc1(&ad); - - const Win32SysInspect::DXFeatureLevel fl = GetFeatureLevel(deviceFeatureLevel); - - if (featureLevel < fl && displaysConnected) - { - adapterDesc = ad; - featureLevel = fl; - } - } - - SAFE_RELEASE(pDevice); - SAFE_RELEASE(pAdapter); - } - ++nAdapter; - } - } - } - SAFE_RELEASE(pFactory); - return featureLevel != Win32SysInspect::DXFL_Undefined; -} - - -bool Win32SysInspect::IsDX11Supported() -{ - DXGI_ADAPTER_DESC1 adapterDesc = {}; - DXFeatureLevel featureLevel = Win32SysInspect::DXFL_Undefined; - return FindGPU(adapterDesc, featureLevel) && featureLevel >= DXFL_11_0; -} - - -bool Win32SysInspect::GetGPUInfo(char* pName, size_t bufferSize, unsigned int& vendorID, unsigned int& deviceID, unsigned int& totLocalVidMem, DXFeatureLevel& featureLevel) -{ - if (pName && bufferSize) - { - pName[0] = '\0'; - } - - vendorID = 0; - deviceID = 0; - totLocalVidMem = 0; - featureLevel = Win32SysInspect::DXFL_Undefined; - - DXGI_ADAPTER_DESC1 adapterDesc = {}; - const bool gpuFound = FindGPU(adapterDesc, featureLevel); - if (gpuFound) - { - vendorID = adapterDesc.VendorId; - deviceID = adapterDesc.DeviceId; - - if (pName && bufferSize) - { - sprintf_s(pName, bufferSize, "%s", CryStringUtils::WStrToUTF8(adapterDesc.Description).c_str()); - } - - totLocalVidMem = adapterDesc.DedicatedVideoMemory; - } - - return gpuFound; -} - - -class CGPURating -{ -public: - CGPURating(); - ~CGPURating(); - - int GetRating(unsigned int vendorId, unsigned int deviceId) const; - -private: - struct SGPUID - { - SGPUID(unsigned int vendorId, unsigned int deviceId) - : vendor(vendorId) - , device(deviceId) - { - } - - bool operator < (const SGPUID& rhs) const - { - if (vendor == rhs.vendor) - { - return device < rhs.device; - } - else - { - return vendor < rhs.vendor; - } - } - - unsigned int vendor; - unsigned int device; - }; - - typedef std::map GPURatingMap; - -private: - GPURatingMap m_gpuRatingMap; -}; - - -static size_t SafeReadLine(AZ::IO::IArchive* pPak, AZ::IO::HandleType fileHandle, char* buffer, size_t bufferSize) -{ - assert(buffer && bufferSize); - - memset(buffer, 0, bufferSize); - - size_t bytesRead = pPak->FRead(buffer, bufferSize - 1, fileHandle); - if (!bytesRead) - { - return 0; - } - - char* currentPosition = buffer; - size_t len = 0; - - bool done = false; - int slashRPosition = -1; - do - { - if (*currentPosition != '\r' && *currentPosition != '\n' && len < bufferSize - 1) - { - len++; - currentPosition++; - } - else - { - done = true; - if (*currentPosition == '\r') - { - slashRPosition = len; - } - } - } while (!done); - - // null terminate string - buffer[len] = '\0'; - - ////////////////////////////////////////// - //seek back to the end of the string - int seekback = bytesRead - len - 1; - - // handle CR/LF for file coming from different platforms - if (slashRPosition > -1 && bytesRead > slashRPosition && buffer[slashRPosition + 1] == '\n') - { - seekback--; - } - pPak->FSeek(fileHandle, -seekback, SEEK_CUR); - /////////////////////////////////////////// - - return len; -} - - -#define BUILDPATH_GPURATING(x) "config/gpu/" x - -CGPURating::CGPURating() -{ - auto pPak(gEnv->pCryPak); - - AZ::IO::ArchiveFileIterator h(pPak->FindFirst(BUILDPATH_GPURATING("*.txt"))); - if (h) - { - do - { - char filename[128]; - azsnprintf(filename, sizeof(filename), BUILDPATH_GPURATING("%.*s"), aznumeric_cast(h.m_filename.size()), h.m_filename.data()); - - AZ::IO::HandleType fileHandle = pPak->FOpen(filename, "rb"); - if (fileHandle != AZ::IO::InvalidHandle) - { - size_t lineNr(0); - while (!pPak->FEof(fileHandle)) - { - char line[1024]; - line[0] = '\0'; - size_t len(SafeReadLine(pPak, fileHandle, line, sizeof(line))); - ++lineNr; - - if (len > 2 && line[0] != '/' && line[1] != '/') - { - unsigned int vendorId(0), deviceId(0); - int rating(0); - if (_snscanf_s(line, sizeof(line), "%x,%x,%d", &vendorId, &deviceId, &rating) == 3) - { - GPURatingMap::iterator it(m_gpuRatingMap.find(SGPUID(vendorId, deviceId))); - if (it == m_gpuRatingMap.end()) - { - m_gpuRatingMap.insert(GPURatingMap::value_type(SGPUID(vendorId, deviceId), rating)); - } - else - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, - "%s line %d contains a multiple defined GPU rating!", filename, lineNr); - } - } - else - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, - "%s line %d contains incomplete GPU rating!", filename, lineNr); - } - } - } - - pPak->FClose(fileHandle); - } - } while (h = pPak->FindNext(h)); - - pPak->FindClose(h); - } -} - - -CGPURating::~CGPURating() -{ -} - - -int CGPURating::GetRating(unsigned int vendorId, unsigned int deviceId) const -{ - GPURatingMap::const_iterator it(m_gpuRatingMap.find(SGPUID(vendorId, deviceId))); - if (it != m_gpuRatingMap.end()) - { - return (*it).second; - } - else - { - return 0; - } -} - - -int Win32SysInspect::GetGPURating([[maybe_unused]] unsigned int vendorId, [[maybe_unused]] unsigned int deviceId) -{ - return 0; // All GPUs unrated as the database is out of date - - //CGPURating gpuRatingDb; - //return gpuRatingDb.GetRating(vendorId, deviceId); -} - - -static int GetFinalSpecValue(int cpuRating, unsigned int totSysMemMB, int gpuRating, unsigned int totVidMemMB, ESystemConfigSpec maxConfigSpec) -{ - int sysMemRating = 1; - if (totSysMemMB >= Win32SysInspect::SafeMemoryThreshold(12228)) - { - sysMemRating = 3; - } - else if (totSysMemMB >= Win32SysInspect::SafeMemoryThreshold(8192)) - { - sysMemRating = 2; - } - - cpuRating = sysMemRating < cpuRating ? sysMemRating : cpuRating; - - // just a sanity check, GPU should reflect overall GPU perf including memory (higher rated GPUs usually come with enough memory) - if (totVidMemMB < Win32SysInspect::SafeMemoryThreshold(1024)) - { - gpuRating = 1; - } - - int finalRating = cpuRating < gpuRating ? cpuRating : gpuRating; - - return min(finalRating, (int) maxConfigSpec); -} - - -void CSystem::AutoDetectSpec(const bool detectResolution) -{ - CryLogAlways("Running machine spec auto detect (%d bit)...", sizeof(void*) << 3); - - char tempBuf[512]; - - // get OS - SPlatformInfo::EWinVersion winVer(SPlatformInfo::WinUndetected); - bool is64bit(false); - Win32SysInspect::GetOS(winVer, is64bit, tempBuf, sizeof(tempBuf)); - CryLogAlways("- %s", tempBuf); - - // get system memory - uint64 totSysMem(0); - GetSystemMemory(totSysMem); - CryLogAlways("- System memory"); - CryLogAlways("--- %d MB", totSysMem >> 20); - - // get CPU name - GetCPUName(tempBuf, sizeof(tempBuf)); - TrimExcessiveWhiteSpaces(tempBuf); - CryLogAlways("- %s", tempBuf); - - // get number of CPU cores - unsigned int numSysCores(1), numProcCores(1); - Win32SysInspect::GetNumCPUCores(numSysCores, numProcCores); - CryLogAlways("--- Number of available cores: %d (out of %d)", numProcCores, numSysCores); - - // get CPU rating - const int cpuRating = numProcCores >= 4 ? 3 : (numProcCores >= 3 ? 2 : 1); - - // get GPU info - unsigned int gpuVendorId(0), gpuDeviceId(0), totVidMem(0); - Win32SysInspect::DXFeatureLevel featureLevel(Win32SysInspect::DXFL_Undefined); - Win32SysInspect::GetGPUInfo(tempBuf, sizeof(tempBuf), gpuVendorId, gpuDeviceId, totVidMem, featureLevel); - - CryLogAlways("- %s (vendor = 0x%.4x, device = 0x%.4x)", tempBuf, gpuVendorId, gpuDeviceId); - CryLogAlways("--- Dedicated video memory: %d MB", totVidMem >> 20); - CryLogAlways("--- Feature level: %s", GetFeatureLevelAsString(featureLevel)); - - // get GPU rating - const int gpuRating = (totVidMem >> 20) >= Win32SysInspect::SafeMemoryThreshold(4096) ? 3 : ((totVidMem >> 20) >= Win32SysInspect::SafeMemoryThreshold(2048) ? 2 : 1); - - // get final rating - int finalSpecValue(GetFinalSpecValue(cpuRating, totSysMem >> 20, gpuRating, totVidMem >> 20, CONFIG_VERYHIGH_SPEC)); - CryLogAlways("- Final rating: Machine class %d", finalSpecValue); - - m_sys_GraphicsQuality->Set(finalSpecValue); - - if (detectResolution) - { - if ((m_rWidth->GetFlags() & VF_WASINCONFIG) == 0) - { - m_rWidth->Set(GetSystemMetrics(SM_CXFULLSCREEN)); - } - if ((m_rHeight->GetFlags() & VF_WASINCONFIG) == 0) - { - m_rHeight->Set(GetSystemMetrics(SM_CYFULLSCREEN)); - } - if ((m_rFullscreen->GetFlags() & VF_WASINCONFIG) == 0) - { - m_rFullscreen->Set(1); - } - } -} - - -#else - -#include "System.h" - -void CSystem::AutoDetectSpec(const bool detectResolution) -{ - AZ_UNUSED(detectResolution); -} - - -#endif diff --git a/Code/CryEngine/CrySystem/AutoDetectSpec.h b/Code/CryEngine/CrySystem/AutoDetectSpec.h deleted file mode 100644 index a710141668..0000000000 --- a/Code/CryEngine/CrySystem/AutoDetectSpec.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_AUTODETECTSPEC_H -#define CRYINCLUDE_CRYSYSTEM_AUTODETECTSPEC_H -#pragma once - - - -#if defined(WIN32) || defined(WIN64) - -// exposed AutoDetectSpec() helper functions for reuse in CrySystem -namespace Win32SysInspect -{ - enum DXFeatureLevel - { - DXFL_Undefined, - DXFL_9_1, - DXFL_9_2, - DXFL_9_3, - DXFL_10_0, - DXFL_10_1, - DXFL_11_0 - }; - - const char* GetFeatureLevelAsString(DXFeatureLevel featureLevel); - - void GetNumCPUCores(unsigned int& totAvailToSystem, unsigned int& totAvailToProcess); - bool IsDX11Supported(); - bool GetGPUInfo(char* pName, size_t bufferSize, unsigned int& vendorID, unsigned int& deviceID, unsigned int& totLocalVidMem, DXFeatureLevel& featureLevel); - int GetGPURating(unsigned int vendorId, unsigned int deviceId); - void GetOS(SPlatformInfo::EWinVersion& ver, bool& is64Bit, char* pName, size_t bufferSize); - bool IsVistaKB940105Required(); - - inline size_t SafeMemoryThreshold(size_t memMB) - { - return (memMB * 8) / 10; - } -} - -#endif // #if defined(WIN32) || defined(WIN64) - - -#endif // CRYINCLUDE_CRYSYSTEM_AUTODETECTSPEC_H diff --git a/Code/CryEngine/CrySystem/CMakeLists.txt b/Code/CryEngine/CrySystem/CMakeLists.txt index 3261526e8e..5a43051ed7 100644 --- a/Code/CryEngine/CrySystem/CMakeLists.txt +++ b/Code/CryEngine/CrySystem/CMakeLists.txt @@ -9,46 +9,17 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) -ly_get_list_relative_pal_filename(common_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/Common) add_subdirectory(XML) -# The following target is a 'C' file only library to work around an issue in cmake and VS generators that -# will append 'std=c++17' to both C and C++ compiler flags for clang. Do not add any .cpp files to this -# library. -ly_add_target( - NAME CrySystem.DLMalloc.C STATIC - NAMESPACE Legacy - FILES_CMAKE - crysystem_dlmalloc_files.cmake - INCLUDE_DIRECTORIES - PUBLIC - . - PRIVATE - ${pal_dir} -) - - -ly_get_pal_tool_dirs(pal_tool_dirs ${CMAKE_CURRENT_LIST_DIR}/Platform) - ly_add_target( NAME CrySystem.Static STATIC NAMESPACE Legacy FILES_CMAKE crysystem_files.cmake - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake - PLATFORM_INCLUDE_FILES - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake INCLUDE_DIRECTORIES PUBLIC . - ${pal_dir} - PRIVATE - ${common_dir} - ${pal_tool_dirs} BUILD_DEPENDENCIES - PUBLIC - Legacy::CrySystem.DLMalloc.C PRIVATE 3rdParty::expat 3rdParty::lz4 @@ -68,19 +39,11 @@ ly_add_source_properties( VALUES ${LY_PAL_TOOLS_DEFINES} ) -ly_add_source_properties( - SOURCES SystemCFG.cpp - PROPERTY COMPILE_DEFINITIONS - VALUES LY_BUILD=${LY_VERSION_BUILD_NUMBER} -) - ly_add_target( NAME CrySystem ${PAL_TRAIT_MONOLITHIC_DRIVEN_LIBRARY_TYPE} NAMESPACE Legacy FILES_CMAKE crysystem_shared_files.cmake - PLATFORM_INCLUDE_FILES - ${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake INCLUDE_DIRECTORIES PUBLIC . @@ -90,29 +53,3 @@ ly_add_target( AZ::AzCore Legacy::CryCommon ) - -################################################################################ -# Tests -################################################################################ -if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) - - ly_add_target( - NAME CrySystem.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} - NAMESPACE Legacy - FILES_CMAKE - crysystem_test_files.cmake - INCLUDE_DIRECTORIES - PRIVATE - . - BUILD_DEPENDENCIES - PRIVATE - AZ::AzTest - Legacy::CryCommon - Legacy::CrySystem.Static - AZ::AzFramework - ) - ly_add_googletest( - NAME Legacy::CrySystem.Tests - ) -endif() - diff --git a/Code/CryEngine/CrySystem/CPUDetect.cpp b/Code/CryEngine/CrySystem/CPUDetect.cpp deleted file mode 100644 index 6d924a1514..0000000000 --- a/Code/CryEngine/CrySystem/CPUDetect.cpp +++ /dev/null @@ -1,1622 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "System.h" -#include "AutoDetectSpec.h" - - -#if defined(AZ_RESTRICTED_PLATFORM) -#undef AZ_RESTRICTED_SECTION -#define CPUDETECT_CPP_SECTION_1 1 -#define CPUDETECT_CPP_SECTION_2 2 -#endif - -#if defined(WIN32) -#include -#elif defined(LINUX) || defined(APPLE) -#include // setrlimit, getrlimit -#endif - -#if defined(APPLE) -#include -#include // mach_thread_self -#include // Mac OS Thread affinity API -#include -#endif - -#if defined(LINUX) -#ifndef __GNU_SOURCE -#define __GNU_SOURCE -#endif -#include //already includes sched.h -#endif - -/* features */ -#define FPU_FLAG 0x0001 -#define SERIAL_FLAG 0x40000 -#define MMX_FLAG 0x800000 -#define ISSE_FLAG 0x2000000 - -#ifdef __GNUC__ -# define cpuid(op, eax, ebx, ecx, edx) __asm__("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (op) : "cc"); -#endif - -int g_CpuFlags; - -struct SAutoMaxPriority -{ - SAutoMaxPriority() - { - /* get a copy of the current thread and process priorities */ -#if defined(WIN32) - priority_class = GetPriorityClass(GetCurrentProcess()); - thread_priority = GetThreadPriority(GetCurrentThread()); -#elif defined(LINUX) || defined(APPLE) - nice_priority = getpriority(PRIO_PROCESS, 0); - success = nice_priority >= 0 && - pthread_getschedparam(pthread_self(), &thread_policy, &thread_sched_param) == 0; -#endif - - /* make this thread the highest possible priority */ -#if defined(WIN32) - SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); -#elif defined(LINUX) || defined(APPLE) - if (success) - { - setpriority(PRIO_PROCESS, 0, MAX_NICE_PRIORITY); - - sched_param new_sched_param = thread_sched_param; - new_sched_param.sched_priority = sched_get_priority_max(thread_policy); - pthread_setschedparam(pthread_self(), thread_policy, &new_sched_param); - } -#endif - } - - ~SAutoMaxPriority() - { - /* restore the thread priority */ -#if defined(WIN32) - SetPriorityClass(GetCurrentProcess(), priority_class); - SetThreadPriority(GetCurrentThread(), thread_priority); -#elif defined(LINUX) || defined(APPLE) - if (success) - { - pthread_setschedparam(pthread_self(), thread_policy, &thread_sched_param); - setpriority(PRIO_PROCESS, 0, nice_priority); - } -#endif - } - -#if defined(WIN32) - uint32 priority_class; - int thread_priority; -#elif defined(LINUX) || defined(APPLE) - rlimit nice_limit; - int nice_priority; - int thread_policy; - sched_param thread_sched_param; - bool success; - enum - { - MAX_NICE_PRIORITY = 40 - }; -#endif -}; - -#if AZ_LEGACY_CRYSYSTEM_TRAIT_ASM_VOLATILE_CPUID -static inline void __cpuid(int CPUInfo[4], int InfoType) -{ - asm volatile("cpuid" : "=a" (*CPUInfo), "=b" (*(CPUInfo + 1)), "=c" (*(CPUInfo + 2)), "=d" (*(CPUInfo + 3)) : "a" (InfoType)); -} -#endif - -bool IsAMD() -{ -// Broken out for validation support. -#if defined(WIN32) || (defined(LINUX) && !defined(ANDROID)) || defined(MAC) - #define AZ_SUPPORTS_AMD -#elif defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION CPUDETECT_CPP_SECTION_1 -#include AZ_RESTRICTED_FILE(CPUDetect_cpp) -#endif - -#if defined(AZ_SUPPORTS_AMD) - int CPUInfo[4]; - __cpuid(CPUInfo, 0x00000000); - - char szCPU[13]; - memset(szCPU, 0, sizeof(szCPU)); - *(int*)&szCPU[0] = CPUInfo[1]; - *(int*)&szCPU[4] = CPUInfo[3]; - *(int*)&szCPU[8] = CPUInfo[2]; - - return (strcmp(szCPU, "AuthenticAMD") == 0); -#else - return false; -#endif -} - -bool IsIntel() -{ -#if defined(WIN32) || (defined(LINUX) && !defined(ANDROID)) || defined(MAC) - int CPUInfo[4]; - __cpuid(CPUInfo, 0x00000000); - - char szCPU[13]; - memset(szCPU, 0, sizeof(szCPU)); - *(int*)&szCPU[0] = CPUInfo[1]; - *(int*)&szCPU[4] = CPUInfo[3]; - *(int*)&szCPU[8] = CPUInfo[2]; - - return (strcmp(szCPU, "GenuineIntel") == 0); -#else - return false; -#endif -} - -bool Has64bitExtension() -{ -#if AZ_LEGACY_CRYSYSTEM_TRAIT_HAS64BITEXT - int CPUInfo[4]; - __cpuid(CPUInfo, 0x80000001); // Argument "Processor Signature and AMD Features" - if (CPUInfo[3] & 0x20000000) // Bit 29 in edx is set if 64-bit address extension is supported - { - return true; - } - else - { - return false; - } -#elif defined(WIN64) || defined(LINUX64) || defined(MAC) - return true; -#else - return false; -#endif -} - -bool HTSupported() -{ -#if AZ_LEGACY_CRYSYSTEM_TRAIT_HTSUPPORTED - int CPUInfo[4]; - __cpuid(CPUInfo, 0x00000001); - if (CPUInfo[3] & 0x10000000) // Bit 28 in edx is set if HT is supported - { - return true; - } - else - { - return false; - } -#else - return false; -#endif -} - -uint8 LogicalProcPerPhysicalProc() -{ -#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID - int CPUInfo[4]; - __cpuid(CPUInfo, 0x00000001); - // Bits 16-23 in ebx contain the number of logical processors per physical processor when execute cpuid with eax set to 1 - return (uint8) ((CPUInfo[1] & 0x00FF0000) >> 16); -#else - return 1; -#endif -} - -uint8 GetAPIC_ID() -{ -#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID - int CPUInfo[4]; - __cpuid(CPUInfo, 0x00000001); - // Bits 24-31 in ebx contain the unique initial APIC ID for the processor this code is running on. Default value = 0xff if HT is not supported. - return (uint8) ((CPUInfo[1] & 0xFF000000) >> 24); -#else - return 0; -#endif -} - -void GetCPUName(char* pName) -{ -#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID - if (pName) - { - int CPUInfo[4]; - __cpuid(CPUInfo, 0x80000000); - if (CPUInfo[0] >= 0x80000004) - { - __cpuid(CPUInfo, 0x80000002); - ((int*)pName)[0] = CPUInfo[0]; - ((int*)pName)[1] = CPUInfo[1]; - ((int*)pName)[2] = CPUInfo[2]; - ((int*)pName)[3] = CPUInfo[3]; - - __cpuid(CPUInfo, 0x80000003); - ((int*)pName)[4] = CPUInfo[0]; - ((int*)pName)[5] = CPUInfo[1]; - ((int*)pName)[6] = CPUInfo[2]; - ((int*)pName)[7] = CPUInfo[3]; - - __cpuid(CPUInfo, 0x80000004); - ((int*)pName)[8] = CPUInfo[0]; - ((int*)pName)[9] = CPUInfo[1]; - ((int*)pName)[10] = CPUInfo[2]; - ((int*)pName)[11] = CPUInfo[3]; - } - else - { - pName[0] = '\0'; - } - } -#else - if (pName) - { - pName[0] = '\0'; - } -#endif -} - -bool HasFPUOnChip() -{ -#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID - int CPUInfo[4]; - __cpuid(CPUInfo, 0x00000001); - // Bit 0 in edx indicates presents of on chip FPU - return (CPUInfo[3] & 0x00000001) != 0; -#else - return false; -#endif -} - -void GetCPUSteppingModelFamily(int& stepping, int& model, int& family) -{ -#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID - int CPUInfo[4]; - __cpuid(CPUInfo, 0x00000001); - stepping = CPUInfo[0] & 0xF; // Bit 0-3 in eax specifies stepping - model = (CPUInfo[0] >> 4) & 0xF; // Bit 4-7 in eax specifies model - family = (CPUInfo[0] >> 8) & 0xF; // Bit 8-11 in eax specifies family -#else - stepping = 0; - model = 0; - family = 0; -#endif -} - -#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASCPUID -unsigned long GetCPUFeatureSet() -{ - unsigned long features = 0; - - int CPUInfo[4]; - - __cpuid(CPUInfo, 0); - const int nIds = CPUInfo[0]; - - __cpuid(CPUInfo, 0x80000000); - const unsigned int nExIds = CPUInfo[0]; - - if (nIds > 0) - { - __cpuid(CPUInfo, 0x00000001); - - if (CPUInfo[3] & (1 << 26)) - { - features |= CFI_SSE2; - } - if (CPUInfo[3] & (1 << 25)) - { - features |= CFI_SSE; - } - if (CPUInfo[2] & (1 << 0)) - { - features |= CFI_SSE3; - } - if (CPUInfo[2] & (1 << 29)) - { - features |= CFI_F16C; - } - if (CPUInfo[2] & (1 << 19)) - { - features |= CFI_SSE41; - } - } - - if (nExIds > 0x80000000) - { - __cpuid(CPUInfo, 0x80000001); - if (CPUInfo[3] & (1 << 31)) - { - features |= CFI_3DNOW; - } - } - - return features; -} -#endif - -#if AZ_LEGACY_CRYSYSTEM_TRAIT_DEFINE_DETECT_PROCESSOR -static unsigned long __stdcall DetectProcessor(void* arg) -{ - const char hex_chars[16] = - { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' - }; - unsigned long signature = 0; - unsigned long cache_temp; - unsigned long cache_eax = 0; - unsigned long cache_ebx = 0; - unsigned long cache_ecx = 0; - unsigned long cache_edx = 0; - unsigned long features_edx = 0; - unsigned long serial_number[3]; - unsigned char cpu_type; - unsigned char fpu_type; - unsigned char CPUID_flag = 0; - unsigned char celeron_flag = 0; - unsigned char pentiumxeon_flag = 0; - unsigned char amd3d_flag = 0; - unsigned char name_flag = 0; - char vendor[13]; - vendor[0] = '\0'; - char name[49]; - name[0] = '\0'; - char* serial; - const char* cpu_string; - const char* cpu_extra_string; - const char* fpu_string; - const char* vendor_string; - SCpu* p = (SCpu*) arg; - - memset(p, 0, sizeof(*p)); - - if (IsAMD() && Has64bitExtension()) - { - p->meVendor = eCVendor_AMD; - p->mFeatures |= GetCPUFeatureSet(); - p->mbSerialPresent = false; - azstrcpy(p->mSerialNumber, AZ_ARRAY_SIZE(p->mSerialNumber), ""); - GetCPUSteppingModelFamily(p->mStepping, p->mModel, p->mFamily); - azstrcpy(p->mVendor, AZ_ARRAY_SIZE(p->mVendor), "AMD"); - GetCPUName(p->mCpuType); - azstrcpy(p->mFpuType, AZ_ARRAY_SIZE(p->mFpuType), HasFPUOnChip() ? "On-Chip" : "Unknown"); - p->mbPhysical = true; - - return 1; - } - else if (IsIntel() && Has64bitExtension()) - { - p->meVendor = eCVendor_Intel; - p->mFeatures |= GetCPUFeatureSet(); - p->mbSerialPresent = false; - azstrcpy(p->mSerialNumber, AZ_ARRAY_SIZE(p->mSerialNumber), ""); - GetCPUSteppingModelFamily(p->mStepping, p->mModel, p->mFamily); - azstrcpy(p->mVendor, AZ_ARRAY_SIZE(p->mVendor), "Intel"); - GetCPUName(p->mCpuType); - azstrcpy(p->mFpuType, AZ_ARRAY_SIZE(p->mFpuType), HasFPUOnChip() ? "On-Chip" : "Unknown"); - - p->mbPhysical = true; - - return 1; - } - - cpu_type = 0xF; - fpu_type = 3; - signature = 0; - - p->mFamily = cpu_type; - p->mModel = (signature >> 4) & 0xf; - p->mStepping = signature & 0xf; - - p->mFeatures = 0; - - p->mFeatures |= amd3d_flag ? CFI_3DNOW : 0; - p->mFeatures |= (features_edx & MMX_FLAG) ? CFI_MMX : 0; - p->mFeatures |= (features_edx & ISSE_FLAG) ? CFI_SSE : 0; - p->mbSerialPresent = ((features_edx & SERIAL_FLAG) != 0); - - if (features_edx & SERIAL_FLAG) - { - serial_number[0] = serial_number[1] = serial_number[2] = 0; - - /* format number */ - serial = p->mSerialNumber; - - serial[0] = hex_chars[(serial_number[2] >> 28) & 0x0f]; - serial[1] = hex_chars[(serial_number[2] >> 24) & 0x0f]; - serial[2] = hex_chars[(serial_number[2] >> 20) & 0x0f]; - serial[3] = hex_chars[(serial_number[2] >> 16) & 0x0f]; - - serial[4] = '-'; - - serial[5] = hex_chars[(serial_number[2] >> 12) & 0x0f]; - serial[6] = hex_chars[(serial_number[2] >> 8) & 0x0f]; - serial[7] = hex_chars[(serial_number[2] >> 4) & 0x0f]; - serial[8] = hex_chars[(serial_number[2] >> 0) & 0x0f]; - - serial[9] = '-'; - - serial[10] = hex_chars[(serial_number[1] >> 28) & 0x0f]; - serial[11] = hex_chars[(serial_number[1] >> 24) & 0x0f]; - serial[12] = hex_chars[(serial_number[1] >> 20) & 0x0f]; - serial[13] = hex_chars[(serial_number[1] >> 16) & 0x0f]; - - serial[14] = '-'; - - serial[15] = hex_chars[(serial_number[1] >> 12) & 0x0f]; - serial[16] = hex_chars[(serial_number[1] >> 8) & 0x0f]; - serial[17] = hex_chars[(serial_number[1] >> 4) & 0x0f]; - serial[18] = hex_chars[(serial_number[1] >> 0) & 0x0f]; - - serial[19] = '-'; - - serial[20] = hex_chars[(serial_number[0] >> 28) & 0x0f]; - serial[21] = hex_chars[(serial_number[0] >> 24) & 0x0f]; - serial[22] = hex_chars[(serial_number[0] >> 20) & 0x0f]; - serial[23] = hex_chars[(serial_number[0] >> 16) & 0x0f]; - - serial[24] = '-'; - - serial[25] = hex_chars[(serial_number[0] >> 12) & 0x0f]; - serial[26] = hex_chars[(serial_number[0] >> 8) & 0x0f]; - serial[27] = hex_chars[(serial_number[0] >> 4) & 0x0f]; - serial[28] = hex_chars[(serial_number[0] >> 0) & 0x0f]; - - serial[29] = 0; - } - - vendor_string = "Unknown"; - cpu_string = "Unknown"; - cpu_extra_string = ""; - fpu_string = "Unknown"; - - if (!CPUID_flag) - { - switch (cpu_type) - { - case 0: - cpu_string = "8086"; - break; - - case 2: - cpu_string = "80286"; - break; - - case 3: - cpu_string = "80386"; - switch (fpu_type) - { - case 2: - fpu_string = "80287"; - break; - - case 1: - fpu_string = "80387"; - break; - - default: - fpu_string = "None"; - break; - } - break; - - case 4: - if (fpu_type) - { - cpu_string = "80486DX, 80486DX2 or 80487SX"; - fpu_string = "on-chip"; - } - else - { - cpu_string = "80486SX"; - } - break; - } - } - else - { /* using CPUID instruction */ - if (!name_flag) - { - if (!strcmp(vendor, "GenuineIntel")) - { - vendor_string = "Intel"; - switch (cpu_type) - { - case 4: - switch (p->mModel) - { - case 0: - case 1: - cpu_string = "80486DX"; - break; - - case 2: - cpu_string = "80486SX"; - break; - - case 3: - cpu_string = "80486DX2"; - break; - - case 4: - cpu_string = "80486SL"; - break; - - case 5: - cpu_string = "80486SX2"; - break; - - case 7: - cpu_string = "Write-Back Enhanced 80486DX2"; - break; - - case 8: - cpu_string = "80486DX4"; - break; - - default: - cpu_string = "80486"; - } - break; - - case 5: - switch (p->mModel) - { - default: - case 1: - case 2: - case 3: - cpu_string = "Pentium"; - break; - - case 4: - cpu_string = "Pentium MMX"; - break; - } - break; - - case 6: - switch (p->mModel) - { - case 1: - cpu_string = "Pentium Pro"; - break; - - case 3: - cpu_string = "Pentium II"; - break; - - case 5: - case 7: - { - cache_temp = cache_eax & 0xFF000000; - if (cache_temp == 0x40000000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x44000000) && (cache_temp <= 0x45000000)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_eax & 0xFF0000; - if (cache_temp == 0x400000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x440000) && (cache_temp <= 0x450000)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_eax & 0xFF00; - if (cache_temp == 0x4000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x4400) && (cache_temp <= 0x4500)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_ebx & 0xFF000000; - if (cache_temp == 0x40000000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x44000000) && (cache_temp <= 0x45000000)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_ebx & 0xFF0000; - if (cache_temp == 0x400000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x440000) && (cache_temp <= 0x450000)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_ebx & 0xFF00; - if (cache_temp == 0x4000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x4400) && (cache_temp <= 0x4500)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_ebx & 0xFF; - if (cache_temp == 0x40) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x44) && (cache_temp <= 0x45)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_ecx & 0xFF000000; - if (cache_temp == 0x40000000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x44000000) && (cache_temp <= 0x45000000)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_ecx & 0xFF0000; - if (cache_temp == 0x400000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x440000) && (cache_temp <= 0x450000)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_ecx & 0xFF00; - if (cache_temp == 0x4000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x4400) && (cache_temp <= 0x4500)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_ecx & 0xFF; - if (cache_temp == 0x40) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x44) && (cache_temp <= 0x45)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_edx & 0xFF000000; - if (cache_temp == 0x40000000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x44000000) && (cache_temp <= 0x45000000)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_edx & 0xFF0000; - if (cache_temp == 0x400000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x440000) && (cache_temp <= 0x450000)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_edx & 0xFF00; - if (cache_temp == 0x4000) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x4400) && (cache_temp <= 0x4500)) - { - pentiumxeon_flag = 1; - } - cache_temp = cache_edx & 0xFF; - if (cache_temp == 0x40) - { - celeron_flag = 1; - } - if ((cache_temp >= 0x44) && (cache_temp <= 0x45)) - { - pentiumxeon_flag = 1; - } - - if (celeron_flag) - { - cpu_string = "Celeron"; - } - else - { - if (pentiumxeon_flag) - { - if (p->mModel == 5) - { - cpu_string = "Pentium II Xeon"; - } - else - { - cpu_string = "Pentium III Xeon"; - } - } - else - { - if (p->mModel == 5) - { - cpu_string = "Pentium II"; - } - else - { - cpu_string = "Pentium III"; - } - } - } - } - break; - - case 6: - cpu_string = "Celeron"; - break; - - case 8: - cpu_string = "Pentium III"; - break; - } - break; - } - - if (signature & 0x1000) - { - cpu_extra_string = " OverDrive"; - } - else - if (signature & 0x2000) - { - cpu_extra_string = " dual upgrade"; - } - } - else - if (!strcmp(vendor, "CyrixInstead")) - { - vendor_string = "Cyrix"; - switch (p->mFamily) - { - case 4: - switch (p->mModel) - { - case 4: - cpu_string = "MediaGX"; - break; - } - break; - - case 5: - switch (p->mModel) - { - case 2: - cpu_string = "6x86"; - break; - - case 4: - cpu_string = "GXm"; - break; - } - break; - - case 6: - switch (p->mModel) - { - case 0: - cpu_string = "6x86MX"; - break; - } - break; - } - } - else - if (!strcmp(vendor, "AuthenticAMD")) - { - cry_strcpy(p->mVendor, "AMD"); - switch (p->mFamily) - { - case 4: - cpu_string = "Am486 or Am5x86"; - break; - - case 5: - switch (p->mModel) - { - case 0: - case 1: - case 2: - case 3: - cpu_string = "K5"; - break; - - case 4: - case 5: - case 6: - case 7: - cpu_string = "K6"; - break; - - case 8: - cpu_string = "K6-2"; - break; - - case 9: - cpu_string = "K6-III"; - break; - } - break; - - case 6: - cpu_string = "Athlon"; - break; - } - } - else - if (!strcmp(vendor, "CentaurHauls")) - { - vendor_string = "Centaur"; - switch (cpu_type) - { - case 5: - switch (p->mModel) - { - case 4: - cpu_string = "WinChip"; - break; - - case 8: - cpu_string = "WinChip2"; - break; - } - break; - } - } - else - if (!strcmp(vendor, "UMC UMC UMC ")) - { - vendor_string = "UMC"; - } - else - if (!strcmp(vendor, "NexGenDriven")) - { - vendor_string = "NexGen"; - } - } - else - { - vendor_string = vendor; - cpu_string = name; - } - - if (features_edx & FPU_FLAG) - { - fpu_string = "On-Chip"; - } - else - { - fpu_string = "Unknown"; - } - } - - stack_string sCpuType = stack_string(cpu_string) + cpu_extra_string; - - cry_strcpy(p->mCpuType, sCpuType.c_str()); - cry_strcpy(p->mFpuType, fpu_string); - cry_strcpy(p->mVendor, vendor_string); - - if (!azstricmp(vendor_string, "Intel")) - { - p->meVendor = eCVendor_Intel; - } - else - if (!azstricmp(vendor_string, "Cyrix")) - { - p->meVendor = eCVendor_Cyrix; - } - else - if (!azstricmp(vendor_string, "AMD")) - { - p->meVendor = eCVendor_AMD; - } - else - if (!azstricmp(vendor_string, "Centaur")) - { - p->meVendor = eCVendor_Centaur; - } - else - if (!azstricmp(vendor_string, "NexGen")) - { - p->meVendor = eCVendor_NexGen; - } - else - if (!azstricmp(vendor_string, "UMC")) - { - p->meVendor = eCVendor_UMC; - } - else - { - p->meVendor = eCVendor_Unknown; - } - - if (strstr(cpu_string, "8086")) - { - p->meModel = eCpu_8086; - } - else - if (strstr(cpu_string, "80286")) - { - p->meModel = eCpu_80286; - } - else - if (strstr(cpu_string, "80386")) - { - p->meModel = eCpu_80386; - } - else - if (strstr(cpu_string, "80486")) - { - p->meModel = eCpu_80486; - } - else - if (!azstricmp(cpu_string, "Pentium MMX") || !azstricmp(cpu_string, "Pentium")) - { - p->meModel = eCpu_Pentium; - } - else - if (!azstricmp(cpu_string, "Pentium Pro")) - { - p->meModel = eCpu_PentiumPro; - } - else - if (!azstricmp(cpu_string, "Pentium II")) - { - p->meModel = eCpu_Pentium2; - } - else - if (!azstricmp(cpu_string, "Pentium III")) - { - p->meModel = eCpu_Pentium3; - } - else - if (!azstricmp(cpu_string, "Pentium 4")) - { - p->meModel = eCpu_Pentium4; - } - else - if (!azstricmp(cpu_string, "Celeron")) - { - p->meModel = eCpu_Celeron; - } - else - if (!azstricmp(cpu_string, "Pentium II Xeon")) - { - p->meModel = eCpu_Pentium2Xeon; - } - else - if (!azstricmp(cpu_string, "Pentium III Xeon")) - { - p->meModel = eCpu_Pentium3Xeon; - } - else - if (!azstricmp(cpu_string, "MediaGX")) - { - p->meModel = eCpu_CyrixMediaGX; - } - else - if (!azstricmp(cpu_string, "6x86")) - { - p->meModel = eCpu_Cyrix6x86; - } - else - if (!azstricmp(cpu_string, "GXm")) - { - p->meModel = eCpu_CyrixGXm; - } - else - if (!azstricmp(cpu_string, "6x86MX")) - { - p->meModel = eCpu_Cyrix6x86MX; - } - else - if (!azstricmp(cpu_string, "Am486 or Am5x86")) - { - p->meModel = eCpu_Am5x86; - } - else - if (!azstricmp(cpu_string, "K5")) - { - p->meModel = eCpu_AmK5; - } - else - if (!azstricmp(cpu_string, "K6")) - { - p->meModel = eCpu_AmK6; - } - else - if (!azstricmp(cpu_string, "K6-2")) - { - p->meModel = eCpu_AmK6_2; - } - else - if (!azstricmp(cpu_string, "K6-III")) - { - p->meModel = eCpu_AmK6_3; - } - else - if (!azstricmp(cpu_string, "Athlon")) - { - p->meModel = eCpu_AmAthlon; - } - else - if (!azstricmp(cpu_string, "Duron")) - { - p->meModel = eCpu_AmDuron; - } - else - if (!azstricmp(cpu_string, "WinChip")) - { - p->meModel = eCpu_CenWinChip; - } - else - if (!azstricmp(cpu_string, "WinChip2")) - { - p->meModel = eCpu_CenWinChip2; - } - else - { - p->meModel = eCpu_Unknown; - } - - p->mbPhysical = true; - if (!strcmp(vendor_string, "GenuineIntel") && p->mStepping > 4 && HTSupported()) - { - p->mbPhysical = (GetAPIC_ID() & LogicalProcPerPhysicalProc() - 1) == 0; - } - - return 1; -} -#endif //AZ_LEGACY_CRYSYSTEM_TRAIT_DEFINE_DETECT_PROCESSOR - -#if defined(MAC) || (defined(LINUX) && !defined(ANDROID)) -static void* DetectProcessorThreadProc(void* pData) -{ - DetectProcessor(pData); - return NULL; -} -#endif // MAC LINUX - -// #define SQRT_TEST -#ifdef SQRT_TEST -/* ------------------------------------------------------------------------------ */ - -ILINE float CorrectInvSqrt(float fNum, float fInvSqrtEst) -{ - // Newton-Rhapson method for improving estimated inv sqrt. - // f(x) = x^(-1/2) - // f(n) = f(a) + (n-a)f'(a) - // = a^(-1/2) + (n-a)(-1/2)a^(-3/2) - // = a^(-1/2)*3/2 - na^(-3/2)/2 - // = e*3/2 - ne^3/2 - return fInvSqrtEst * (1.5f - fNum * fInvSqrtEst * fInvSqrtEst * 0.5f); -} - - -float Null(float f) { return f; } -float Inv(float f) { return 1.f / f; } - -float Square(float f) { return f * f; } -float InvSquare(float f) { return 1.f / (f * f); } - -float Sqrt(float f) { return sqrtf(f); } -float SqrtT(float f) { return sqrt_tpl(f); } -float SqrtFT(float f) { return sqrt_fast_tpl(f); } - -float InvSqrt(float f) { return 1.f / sqrtf(f); } -float ISqrtT(float f) { return isqrt_tpl(f); } -float ISqrtFT(float f) { return isqrt_fast_tpl(f); } - -float SSEInv(float f) -{ - __m128 s = _mm_rcp_ss(_mm_load_ss(&f)); - float r; - _mm_store_ss(&r, s); - return r; -} -float SSESqrt(float f) -{ - __m128 s = _mm_sqrt_ss(_mm_load_ss(&f)); - float r; - _mm_store_ss(&r, s); - return r; -} -float SSEISqrt(float f) -{ - __m128 s = _mm_sqrt_ss(_mm_load_ss(&f)); - float r; - _mm_store_ss(&r, s); - return 1.f / r; -} -float SSERSqrt(float f) -{ - __m128 s = _mm_rsqrt_ss(_mm_load_ss(&f)); - float r; - _mm_store_ss(&r, s); - return r; -} -float SSERSqrtInv(float f) -{ - __m128 s = _mm_rcp_ss(_mm_rsqrt_ss(_mm_load_ss(&f))); - float r; - _mm_store_ss(&r, s); - return r; -} -float SSERSqrtNR(float f) -{ - __m128 s = _mm_rsqrt_ss(_mm_load_ss(&f)); - float r; - _mm_store_ss(&r, s); - return CorrectInvSqrt(f, r); -} -float SSERISqrtNR(float f) -{ - __m128 s = _mm_rsqrt_ss(_mm_load_ss(&f)); - float r; - _mm_store_ss(&r, s); - return 1.f / CorrectInvSqrt(f, r); -} - -inline float cryISqrtf(float fVal) -{ - unsigned int* n1 = (unsigned int*)&fVal; - unsigned int n = 0x5f3759df - (*n1 >> 1); - float* n2 = (float*)&n; - fVal = (1.5f - (fVal * 0.5f) * *n2 * *n2) * *n2; - return fVal; -} - -float cryISqrtNRf(float f) -{ - return CorrectInvSqrt(f, cryISqrtf(f)); -} - -inline float crySqrtf(float fVal) -{ - return 1.0f / cryISqrtf(fVal); -} - -/* ------------------------------------------------------------------------------ */ -struct SMathTest -{ - typedef int64 TTime; - static inline TTime GetTime() - { - return CryGetTicks(); - } - - static const int T = 100, N = 1000; - float fNullTime; - - float aTestVals[T]; - float aResVals[T]; - - typedef float (* FFloatFunc)(float f); - - float Timer(const char* sName, FFloatFunc func, FFloatFunc finv) - { - for (int i = 0; i < T; i++) - { - aResVals[i] = func(aTestVals[i]); - } - TTime tStart = GetTime(); - for (int r = 0; r < N; r++) - { - for (int i = 0; i < T; i++) - { - aResVals[i] = func(aTestVals[i]); - } - } - float fTime = (GetTime() - tStart) / float(N * T); - - // Error computation. - float fAvgErr = 0.f, fMaxErr = 0.f; - for (int i = 0; i < T; i++) - { - float fErr = abs(finv(aResVals[i]) / aTestVals[i] - 1.f); - fAvgErr += fErr; - fMaxErr = max(fMaxErr, fErr); - } - fAvgErr /= float(T); - - CryLogAlways("%-20s : %5.2f cycles, avg err %.2e, max err %.2e", sName, fTime - fNullTime, fAvgErr, fMaxErr); - - return fTime; - }; - - SMathTest() - { - for (int i = 0; i < T; i++) - { - aTestVals[i] = powf(cry_random(1.f, 2.f), cry_random(-30.f, 30.f)); - } - - CryLogAlways("--- Math Test ---"); - - fNullTime = 0.f; - fNullTime = Timer("(null)", &Null, &Null); - - CryLogAlways("-- Inverse methods"); - Timer("1/f", &Inv, &Inv); - Timer("rcpss", &SSEInv, &Inv); - - CryLogAlways("-- Sqrt methods"); - Timer("sqrtf()", &Sqrt, &Square); - Timer("sqrt_tpl()", &SqrtT, &Square); - Timer("sqrt_fast_tpl()", &SqrtFT, &Square); - Timer("crySqrt()", &crySqrtf, &Square); - - // Timer("sqrtss", &SSESqrt, &Square); - // Timer("rsqrtss,rcpss", &SSERSqrtInv, &Square); - Timer("1/rsqrtss,correction", &SSERISqrtNR, &Square); - - CryLogAlways("-- InvSqrt methods"); - Timer("1/sqrtf()", &InvSqrt, &InvSquare); - Timer("isqrt_tpl()", &ISqrtT, &InvSquare); - Timer("isqrt_fast_tpl()", &ISqrtFT, &InvSquare); - Timer("cryISqrt()", &cryISqrtf, &InvSquare); - - Timer("1/sqrtss", &SSEISqrt, &InvSquare); - // Timer("rsqrtss", &SSERSqrt, &InvSquare); - // Timer("rsqrtss,correction", &SSERSqrtNR, &InvSquare); - Timer("cryISqrt,correction", &cryISqrtNRf, &InvSquare); - - CryLogAlways("--------------------"); - } -}; - -#endif // SQRT_TEST - -#if defined(LINUX) -// collection of functions to read from /proc/cpuinfo - -static bool proc_read_str(char* buffer, char* output, size_t output_length) -{ - if (!buffer || !output || output_length <= 0) - { - return false; - } - while (*buffer && *buffer != ':') - { - ++buffer; - } - if (*buffer == ':') - { - buffer += 2; - cry_strcpy(output, output_length, buffer); - const int len = strlen(output); - if (len > 0 && output[len - 1] == '\n') - { - output[len - 1] = '\0'; - } - return true; - } - return false; -} - - -static bool proc_read_int(char* buffer, int& output) -{ - if (!buffer) - { - return false; - } - while (*buffer && *buffer != ':') - { - ++buffer; - } - if (*buffer == ':') - { - buffer += 2; - output = atoi(buffer); - return true; - } - return false; -} -#endif - -/* ------------------------------------------------------------------------------ */ -void CCpuFeatures::Detect(void) -{ - m_NumSystemProcessors = 1; - m_NumAvailProcessors = 0; - - ////////////////////////////////////////////////////////////////////////// -#if AZ_LEGACY_CRYSYSTEM_TRAIT_HASAFFINITYMASK - CryLogAlways(""); - - DWORD_PTR process_affinity_mask = 1; - - /* get the system info to derive the number of processors within the system. */ - - SYSTEM_INFO sys_info; - DWORD_PTR system_affinity_mask; - GetSystemInfo(&sys_info); - m_NumLogicalProcessors = m_NumSystemProcessors = sys_info.dwNumberOfProcessors; - m_NumAvailProcessors = 0; - GetProcessAffinityMask(GetCurrentProcess(), &process_affinity_mask, &system_affinity_mask); - - for (unsigned char c = 0; c < m_NumSystemProcessors; c++) - { - if (process_affinity_mask & ((DWORD_PTR)1 << c)) - { - m_NumAvailProcessors++; - SetProcessAffinityMask(GetCurrentProcess(), DWORD_PTR(1) << c); - DetectProcessor(&m_Cpu[c]); - m_Cpu[c].mAffinityMask = ((DWORD_PTR)1 << c); - } - } - - SetProcessAffinityMask(GetCurrentProcess(), process_affinity_mask); - - m_bOS_ISSE = false; - m_bOS_ISSE_EXCEPTIONS = false; -#elif defined(LINUX) - // Retrieve information from /proc/cpuinfo - FILE* cpu_info = fopen("/proc/cpuinfo", "r"); - if (!cpu_info) - { - m_NumLogicalProcessors = m_NumSystemProcessors = m_NumAvailProcessors = 1; - CryLogAlways("Could not open /proc/cpuinfo, defaulting values to 1."); - } - else - { - int nCores = 0; - int nCpu = -1; - int index = 0; - char buffer[512]; - while (!feof(cpu_info)) - { - if (nCpu >= MAX_CPU) - { - --nCpu; //Decrement so the sets after the while loop matches the number of CPUs examined - CryLogAlways("Found a higher than expected number of CPUs, defaulting to %d", MAX_CPU); - break; - } - - fgets(buffer, sizeof(buffer), cpu_info); - - if (buffer[0] == '\0' || buffer[0] == '\n') - { - continue; - } - - if (strncmp("processor", buffer, (index = strlen("processor"))) == 0) - { - ++nCpu; - } - else if (strncmp("vendor_id", buffer, (index = strlen("vendor_id"))) == 0) - { - proc_read_str(&buffer[index], m_Cpu[nCpu].mVendor, sizeof(m_Cpu[nCpu].mVendor)); - } - else if (strncmp("model name", buffer, (index = strlen("model name"))) == 0) - { - proc_read_str(&buffer[index], m_Cpu[nCpu].mCpuType, sizeof(m_Cpu[nCpu].mCpuType)); - } - else if (strncmp("cpu cores", buffer, (index = strlen("cpu cores"))) == 0 && nCores == 0) - { - proc_read_int(&buffer[index], nCores); - } - else if (strncmp("fpu", buffer, (index = strlen("fpu"))) == 0) - { - while (buffer[index] != ':' && index < 512) - { - ++index; - } - if (buffer[index] == ':') - { - if (strncmp(&buffer[index + 2], "yes", 3) == 0) - { - snprintf(m_Cpu[nCpu].mFpuType, sizeof(m_Cpu[nCpu].mFpuType), "On-Chip"); - } - else - { - snprintf(m_Cpu[nCpu].mFpuType, sizeof(m_Cpu[nCpu].mFpuType), "Unkown"); - } - } - } - else if (strncmp("cpu family", buffer, (index = strlen("cpu family"))) == 0) - { - proc_read_int(&buffer[index], m_Cpu[nCpu].mFamily); - } - else if (strncmp("model", buffer, (index = strlen("model"))) == 0) - { - proc_read_int(&buffer[index], m_Cpu[nCpu].mModel); - } - else if (strncmp("stepping", buffer, (index = strlen("stepping"))) == 0) - { - proc_read_int(&buffer[index], m_Cpu[nCpu].mStepping); - } - else if (strncmp("flags", buffer, (index = strlen("flags"))) == 0) - { - if (strstr(buffer + index, "mmx")) - { - m_Cpu[nCpu].mFeatures |= CFI_MMX; - } - - if (strstr(buffer + index, "sse")) - { - m_Cpu[nCpu].mFeatures |= CFI_SSE; - } - - if (strstr(buffer + index, "sse2")) - { - m_Cpu[nCpu].mFeatures |= CFI_SSE2; - } - } - } - m_NumLogicalProcessors = m_NumAvailProcessors = nCpu + 1; - m_NumSystemProcessors = nCores; - } - - -#elif defined(APPLE) - size_t len; - unsigned int ncpu; - - len = sizeof(ncpu); - if (sysctlbyname ("hw.physicalcpu_max", &ncpu, &len, NULL, 0) == 0) - { - m_NumSystemProcessors = ncpu; - } - else - { - CryLogAlways("Failed to detect the number of available processors, defaulting to 1"); - m_NumSystemProcessors = 1; - } - - if (sysctlbyname ("hw.logicalcpu_max", &ncpu, &len, NULL, 0) == 0) - { - m_NumAvailProcessors = m_NumLogicalProcessors = ncpu; - } - else - { - CryLogAlways("Failed to detect the number of available logical processors, defaulting to 1"); - m_NumAvailProcessors = m_NumLogicalProcessors = 1; - } - uint64_t cpu_freq; - len = sizeof(cpu_freq); - if (sysctlbyname ("hw.cpufrequency_max", &cpu_freq, &len, NULL, 0) != 0) - { - CryLogAlways("Failed to detect cpu frequency , defaulting to 0"); - cpu_freq = 0; - } - - // On macs, the processors are always the same model, so we can easily - // calculate once and apply the settings for all. - SCpu cpuInfo; -#if !defined(IOS) - DetectProcessor(&cpuInfo); -#endif - for (int c = 0; c < m_NumAvailProcessors; c++) - { - m_Cpu[c] = cpuInfo; - } - -#elif defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION CPUDETECT_CPP_SECTION_2 -#include AZ_RESTRICTED_FILE(CPUDetect_cpp) -#endif - - -#if defined(WIN32) || defined(WIN64) - CryLogAlways("Total number of logical processors: %d", m_NumSystemProcessors); - CryLogAlways("Number of available logical processors: %d", m_NumAvailProcessors); - - unsigned int numSysCores(1), numProcessCores(1); - Win32SysInspect::GetNumCPUCores(numSysCores, numProcessCores); - m_NumSystemProcessors = numSysCores; - m_NumAvailProcessors = numProcessCores; - CryLogAlways("Total number of system cores: %d", m_NumSystemProcessors); - CryLogAlways("Number of cores available to process: %d", m_NumAvailProcessors); - -#else - CryLogAlways("Number of system processors: %d", m_NumSystemProcessors); - CryLogAlways("Number of available processors: %d", m_NumAvailProcessors); -#endif - - if (m_NumAvailProcessors > MAX_CPU) - { - m_NumAvailProcessors = MAX_CPU; - } - - for (int i = 0; i < m_NumAvailProcessors; i++) - { - SCpu* p = &m_Cpu[i]; - - CryLogAlways(" "); - CryLogAlways("Processor %d:", i); - CryLogAlways(" CPU: %s %s", p->mVendor, p->mCpuType); - CryLogAlways(" Family: %d, Model: %d, Stepping: %d", p->mFamily, p->mModel, p->mStepping); - CryLogAlways(" FPU: %s", p->mFpuType); - CryLogAlways(" 3DNow!: %s", (p->mFeatures & CFI_3DNOW) ? "present" : "not present"); - CryLogAlways(" MMX: %s", (p->mFeatures & CFI_MMX) ? "present" : "not present"); - CryLogAlways(" SSE: %s", (p->mFeatures & CFI_SSE) ? "present" : "not present"); - CryLogAlways(" SSE2: %s", (p->mFeatures & CFI_SSE2) ? "present" : "not present"); - CryLogAlways(" SSE3: %s", (p->mFeatures & CFI_SSE3) ? "present" : "not present"); - CryLogAlways(" SSE4.1: %s", (p->mFeatures& CFI_SSE41) ? "present" : "not present"); - if (p->mbSerialPresent) - { - CryLogAlways(" Serial number: %s", p->mSerialNumber); - } - else - { - CryLogAlways(" Serial number not present or disabled"); - } - } - -#ifdef SQRT_TEST - SMathTest test; -#endif - - CryLogAlways(" "); - - //m_NumPhysicsProcessors = m_NumSystemProcessors; - for (int i = m_NumPhysicsProcessors = 0; i < m_NumAvailProcessors; i++) - { - if (m_Cpu[i].mbPhysical) - { - ++m_NumPhysicsProcessors; - } - } - - // Set the cpu flags global variable - g_CpuFlags = 0; - if (hasMMX()) - { - g_CpuFlags |= CPUF_MMX; - } - if (hasSSE()) - { - g_CpuFlags |= CPUF_SSE; - } - if (hasSSE2()) - { - g_CpuFlags |= CPUF_SSE2; - } - if (hasSSE3()) - { - g_CpuFlags |= CPUF_SSE3; - } - if (hasSSE41()) - { - g_CpuFlags |= CPUF_SSE41; - } - if (has3DNow()) - { - g_CpuFlags |= CPUF_3DNOW; - } - if (hasF16C()) - { - g_CpuFlags |= CPUF_F16C; - } -} - diff --git a/Code/CryEngine/CrySystem/CPUDetect.h b/Code/CryEngine/CrySystem/CPUDetect.h deleted file mode 100644 index e2851d5f23..0000000000 --- a/Code/CryEngine/CrySystem/CPUDetect.h +++ /dev/null @@ -1,180 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_CPUDETECT_H -#define CRYINCLUDE_CRYSYSTEM_CPUDETECT_H -#pragma once - - -//------------------------------------------------------- -/// Cpu class -//------------------------------------------------------- -#if defined(WIN64) || defined(LINUX) - #define MAX_CPU 96 -#else - #define MAX_CPU 32 -#endif - -/// Cpu Features -#define CFI_FPUEMULATION 0x01 -#define CFI_MMX 0x02 -#define CFI_3DNOW 0x04 -#define CFI_SSE 0x08 -#define CFI_SSE2 0x10 -#define CFI_SSE3 0x20 -#define CFI_F16C 0x40 -#define CFI_SSE41 0x80 - -/// Type of Cpu Vendor. -enum ECpuVendor -{ - eCVendor_Unknown, - eCVendor_Intel, - eCVendor_Cyrix, - eCVendor_AMD, - eCVendor_Centaur, - eCVendor_NexGen, - eCVendor_UMC, - eCVendor_M68K -}; - -/// Type of Cpu Model. -enum ECpuModel -{ - eCpu_Unknown, - - eCpu_8086, - eCpu_80286, - eCpu_80386, - eCpu_80486, - eCpu_Pentium, - eCpu_PentiumPro, - eCpu_Pentium2, - eCpu_Pentium3, - eCpu_Pentium4, - eCpu_Pentium2Xeon, - eCpu_Pentium3Xeon, - eCpu_Celeron, - eCpu_CeleronA, - - eCpu_Am5x86, - eCpu_AmK5, - eCpu_AmK6, - eCpu_AmK6_2, - eCpu_AmK6_3, - eCpu_AmK6_3D, - eCpu_AmAthlon, - eCpu_AmDuron, - - eCpu_CyrixMediaGX, - eCpu_Cyrix6x86, - eCpu_CyrixGXm, - eCpu_Cyrix6x86MX, - - eCpu_CenWinChip, - eCpu_CenWinChip2, -}; - -struct SCpu -{ - ECpuVendor meVendor; - ECpuModel meModel; - unsigned long mFeatures; - bool mbSerialPresent; - char mSerialNumber[30]; - int mFamily; - int mModel; - int mStepping; - char mVendor[64]; - char mCpuType[64]; - char mFpuType[64]; - bool mbPhysical; // false for hyperthreaded - DWORD_PTR mAffinityMask; - - // constructor - SCpu() - : meVendor(eCVendor_Unknown) - , meModel(eCpu_Unknown) - , mFeatures(0) - , mbSerialPresent(false) - , mFamily(0) - , mModel(0) - , mStepping(0) - , mbPhysical(true) - , mAffinityMask(0) - { - memset(mSerialNumber, 0, sizeof(mSerialNumber)); - memset(mVendor, 0, sizeof(mVendor)); - memset(mCpuType, 0, sizeof(mCpuType)); - memset(mFpuType, 0, sizeof(mFpuType)); - } -}; - -class CCpuFeatures -{ -private: - int m_NumLogicalProcessors; - int m_NumSystemProcessors; - int m_NumAvailProcessors; - int m_NumPhysicsProcessors; - bool m_bOS_ISSE; - bool m_bOS_ISSE_EXCEPTIONS; -public: - - SCpu m_Cpu[MAX_CPU]; - -public: - CCpuFeatures() - { - m_NumLogicalProcessors = 0; - m_NumSystemProcessors = 0; - m_NumAvailProcessors = 0; - m_NumPhysicsProcessors = 0; - m_bOS_ISSE = 0; - m_bOS_ISSE_EXCEPTIONS = 0; - ZeroMemory(m_Cpu, sizeof(m_Cpu)); - } - - void Detect(void); - bool hasSSE() { return (m_Cpu[0].mFeatures & CFI_SSE) != 0; } - bool hasSSE2() { return (m_Cpu[0].mFeatures & CFI_SSE2) != 0; } - bool hasSSE3() { return (m_Cpu[0].mFeatures & CFI_SSE3) != 0; } - bool hasSSE41() { return (m_Cpu[0].mFeatures & CFI_SSE41) != 0; } - bool has3DNow() { return (m_Cpu[0].mFeatures & CFI_3DNOW) != 0; } - bool hasMMX() { return (m_Cpu[0].mFeatures & CFI_MMX) != 0; } - bool hasF16C() { return (m_Cpu[0].mFeatures & CFI_F16C) != 0; } - - unsigned int GetLogicalCPUCount() { return m_NumLogicalProcessors; } - unsigned int GetPhysCPUCount() { return m_NumPhysicsProcessors; } - unsigned int GetCPUCount() { return m_NumAvailProcessors; } - DWORD_PTR GetCPUAffinityMask(unsigned int iCPU) { assert(iCPU < MAX_CPU); return iCPU < GetCPUCount() ? m_Cpu[iCPU].mAffinityMask : 0; } - DWORD_PTR GetPhysCPUAffinityMask(unsigned int iCPU) - { - if (iCPU > GetPhysCPUCount()) - { - return 0; - } - int i; - for (i = 0; (int)iCPU >= 0; i++) - { - if (m_Cpu[i].mbPhysical) - { - --iCPU; - } - } - PREFAST_ASSUME(i > 0 && i < MAX_CPU); - return m_Cpu[i - 1].mAffinityMask; - } -}; - -#endif // CRYINCLUDE_CRYSYSTEM_CPUDETECT_H diff --git a/Code/CryEngine/CrySystem/ClientHandler.cpp b/Code/CryEngine/CrySystem/ClientHandler.cpp deleted file mode 100644 index a708d876f9..0000000000 --- a/Code/CryEngine/CrySystem/ClientHandler.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" - -#include "ProjectDefines.h" -#if defined(MAP_LOADING_SLICING) - -#include "ClientHandler.h" - -ClientHandler::ClientHandler(const char* bucket, int affinity, int clientTimeout) - : HandlerBase(bucket, affinity) -{ - m_clientTimeout = clientTimeout; - Reset(); -} - -void ClientHandler::Reset() -{ - m_srvLock.reset(0); - for (int i = 0; i < MAX_CLIENTS_NUM; i++) - { - std::unique_ptr srv(new SSyncLock(m_serverLockName, i, false)); - - // first get the client lock up! - if (!srv->IsValid()) - { - //try to create client lock - m_clientLock.reset(new SSyncLock(m_clientLockName, i, true)); - if (m_clientLock->IsValid()) - { - break; - } - else - { - m_clientLock.reset(0); - } - } - } -} - -bool ClientHandler::ServerIsValid() -{ - if (!m_srvLock.get()) - { - if (m_clientLock.get() && m_clientLock->IsValid()) - { - m_srvLock.reset(new SSyncLock(m_serverLockName, m_clientLock->number, false)); - if (m_srvLock->IsValid()) - { - SetAffinity(); - //got synched - return true; - } - m_srvLock.reset(0); - } - return false; - } - return m_srvLock->IsValid(); -} - -bool ClientHandler::Sync() -{ - if (ServerIsValid()) - { - m_clientLock->Signal();//signal that we're done and - if (m_srvLock->Wait(m_clientTimeout))//wait for server - { - //bla bla, track waiting - return true; - } - else - { - Reset(); - } - } - return false; -} - -#endif // defined(MAP_LOADING_SLICING) diff --git a/Code/CryEngine/CrySystem/ClientHandler.h b/Code/CryEngine/CrySystem/ClientHandler.h deleted file mode 100644 index ce325270ad..0000000000 --- a/Code/CryEngine/CrySystem/ClientHandler.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_CLIENTHANDLER_H -#define CRYINCLUDE_CRYSYSTEM_CLIENTHANDLER_H -#pragma once - -#include "HandlerBase.h" -#include "SyncLock.h" - -struct ClientHandler - : public HandlerBase -{ - ClientHandler(const char* bucket, int affinity, int clientTimeout); - - void Reset(); - bool ServerIsValid(); - bool Sync(); - -private: - int m_clientTimeout; - std::unique_ptr m_clientLock; - std::unique_ptr m_srvLock; -}; - -#endif diff --git a/Code/CryEngine/CrySystem/Components/MathConversionTests.cpp b/Code/CryEngine/CrySystem/Components/MathConversionTests.cpp deleted file mode 100644 index 2ee2bc71f2..0000000000 --- a/Code/CryEngine/CrySystem/Components/MathConversionTests.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "CrySystem_precompiled.h" -#include - -#include -#include -#include - -//namespace MathConversionUnitTests -//{ -const float kEpsilon = 0.01f; - -bool IsNearlyEqual(const AZ::Vector3& az, const Vec3& ly) -{ - return fcmp(az.GetX(), ly.x, kEpsilon) - && fcmp(az.GetY(), ly.y, kEpsilon) - && fcmp(az.GetZ(), ly.z, kEpsilon); -} - -bool IsNearlyEqual(const AZ::Quaternion& az, const Quat& ly) -{ - return fcmp(az.GetX(), ly.v.x, kEpsilon) - && fcmp(az.GetY(), ly.v.y, kEpsilon) - && fcmp(az.GetZ(), ly.v.z, kEpsilon) - && fcmp(az.GetW(), ly.w, kEpsilon); -} - -bool IsNearlyEqual(const AZ::Transform& az, const Matrix34& ly) -{ - float azFloats[12]; - const AZ::Matrix3x4 matrix3x4 = AZ::Matrix3x4::CreateFromTransform(az); - matrix3x4.StoreToRowMajorFloat12(azFloats); - - const float* lyFloats = ly.GetData(); - - for (int i = 0; i < 12; ++i) - { - if (!fcmp(azFloats[i], lyFloats[i], kEpsilon)) - { - return false; - } - } - return true; -} - -bool IsNearlyEqual(const AZ::Transform& az, const QuatT& ly) -{ - return IsNearlyEqual(az.GetTranslation(), ly.t) - && IsNearlyEqual(az.GetRotation(), ly.q); -} - -TEST(MathConversionTests, BasicConversions) -{ - { // check vector3 comparisons - AZ::Vector3 az(1.f, 2.f, 3.f); - Vec3 ly(1.f, 2.f, 3.f); - EXPECT_TRUE(IsNearlyEqual(az, ly)); - - // reverse XYZ - ly = Vec3(3.f, 2.f, 1.f); - EXPECT_TRUE(!IsNearlyEqual(az, ly)); - - // off by 0.1 - ly = Vec3(1.1f, 2.1f, 3.1f); - EXPECT_TRUE(!IsNearlyEqual(az, ly)); - } - - { // check vector3 conversions - Vec3 ly1(1.f, 2.f, 3.f); - AZ::Vector3 az = LYVec3ToAZVec3(ly1); - EXPECT_TRUE(IsNearlyEqual(az, ly1)); - - Vec3 ly2 = AZVec3ToLYVec3(az); - EXPECT_TRUE(IsNearlyEqual(az, ly1)); - EXPECT_TRUE(ly1.IsEquivalent(ly2)); - } - - { // check quaternion comparisons - AZ::Quaternion az(AZ::Quaternion::CreateIdentity()); - Quat ly(IDENTITY); - EXPECT_TRUE(IsNearlyEqual(az, ly)); - - az = AZ::Quaternion(1.f, 2.f, 3.f, 4.f); - ly = Quat(4.f, 1.f, 2.f, 3.f); - EXPECT_TRUE(IsNearlyEqual(az, ly)); - - // w in wrong place - ly = Quat(1.f, 2.f, 3.f, 4.f); - EXPECT_TRUE(!IsNearlyEqual(az, ly)); - } - - { // check quaternion conversions - Quat ly1(4.f, 1.f, 2.f, 3.f); - AZ::Quaternion az = LYQuaternionToAZQuaternion(ly1); - EXPECT_TRUE(IsNearlyEqual(az, ly1)); - - Quat ly2 = AZQuaternionToLYQuaternion(az); - EXPECT_TRUE(IsNearlyEqual(az, ly2)); - EXPECT_TRUE(Quat::IsEquivalent(ly1, ly2)); - } - - { // check transform comparisons - AZ::Transform az = AZ::Transform::Identity(); - Matrix34 ly = Matrix34::CreateIdentity(); - EXPECT_TRUE(IsNearlyEqual(az, ly)); - - // rotating pi/2 will get us a non-symmetric matrix. - // good for testing that we're not confusing rows & columns - float rotation = gf_PI / 2.f; - - ly = Matrix34::CreateRotationX(rotation, Vec3(1.f, 2.f, 3.f)); - az = AZ::Transform::CreateRotationX(rotation); - az.SetTranslation(1.f, 2.f, 3.f); - EXPECT_TRUE(IsNearlyEqual(az, ly)); - - // rotate around different axis - ly = Matrix34::CreateRotationY(rotation, Vec3(1.f, 2.f, 3.f)); - EXPECT_TRUE(!IsNearlyEqual(az, ly)); - } - - { // check transform conversions - Matrix34 ly1 = Matrix34::CreateRotationXYZ(Ang3(0.1f, 0.5f, 0.9f), Vec3(1.f, 2.f, 3.f)); - AZ::Transform az = LYTransformToAZTransform(ly1); - EXPECT_TRUE(IsNearlyEqual(az, ly1)); - - Matrix34 ly2 = AZTransformToLYTransform(az); - EXPECT_TRUE(IsNearlyEqual(az, ly2)); - EXPECT_TRUE(Matrix34::IsEquivalent(ly1, ly2)); - } - - { // check QuatT comparisons - AZ::Transform az = AZ::Transform::Identity(); - QuatT ly(IDENTITY); - EXPECT_TRUE(IsNearlyEqual(az, ly)); - - az = AZ::Transform::CreateRotationX(AZ::Constants::HalfPi); - az.SetTranslation(1.f, 2.f, 3.f); - ly.q.SetRotationX(AZ::Constants::HalfPi); - ly.t.Set(1.f, 2.f, 3.f); - EXPECT_TRUE(IsNearlyEqual(az, ly)); - - // off by 0.1 - ly.t.z += 0.1f; - EXPECT_TRUE(!IsNearlyEqual(az, ly)); - } - - { // check QuatT conversions - QuatT ly1(Quat::CreateRotationX(AZ::Constants::HalfPi), Vec3(5.f, 6.f, 7.f)); - AZ::Transform az = LYQuatTToAZTransform(ly1); - EXPECT_TRUE(IsNearlyEqual(az, ly1)); - - QuatT ly2 = AZTransformToLYQuatT(az); - EXPECT_TRUE(IsNearlyEqual(az, ly2)); - EXPECT_TRUE(QuatT::IsEquivalent(ly1, ly2)); - } -} -//} // namespace MathConversionUnitTests diff --git a/Code/CryEngine/CrySystem/CompressedFile.cpp b/Code/CryEngine/CrySystem/CompressedFile.cpp deleted file mode 100644 index 9166466e3d..0000000000 --- a/Code/CryEngine/CrySystem/CompressedFile.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "System.h" -#include "CryZlib.h" - -bool CSystem::CompressDataBlock(const void* input, size_t inputSize, void* output, size_t& outputSize, int level) -{ - uLongf destLen = outputSize; - Bytef* dest = static_cast(output); - uLong sourceLen = inputSize; - const Bytef* source = static_cast(input); - bool ok = Z_OK == compress2(dest, &destLen, source, sourceLen, level); - outputSize = destLen; - return ok; -} - -bool CSystem::DecompressDataBlock(const void* input, size_t inputSize, void* output, size_t& outputSize) -{ - uLongf destLen = outputSize; - Bytef* dest = static_cast(output); - uLong sourceLen = inputSize; - const Bytef* source = static_cast(input); - bool ok = Z_OK == uncompress(dest, &destLen, source, sourceLen); - outputSize = destLen; - return ok; -} diff --git a/Code/CryEngine/CrySystem/CrashHandler.rc b/Code/CryEngine/CrySystem/CrashHandler.rc deleted file mode 100644 index 01afa72550..0000000000 --- a/Code/CryEngine/CrySystem/CrashHandler.rc +++ /dev/null @@ -1,114 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_CRITICAL_ERROR, DIALOG - BEGIN - LEFTMARGIN, 5 - RIGHTMARGIN, 260 - BOTTOMMARGIN, 223 - END - - IDD_EXCEPTION, DIALOG - BEGIN - END - - IDD_CONFIRM_SAVE_LEVEL, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 239 - TOPMARGIN, 7 - BOTTOMMARGIN, 96 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_CRITICAL_ERROR DIALOGEX 0, 0, 267, 230 -STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION -CAPTION "Critical Exception" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "&Abort",IDB_EXIT,100,207,58,14 - EDITTEXT IDC_CALLSTACK,10,95,245,102,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL | WS_HSCROLL - EDITTEXT IDC_EXCEPTION_CODE,10,25,50,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Call Stack Trace",IDC_STATIC,13,85,54,8 - LTEXT "Code",IDC_STATIC,10,15,18,8 - LTEXT "Address:",IDC_STATIC,66,15,28,8 - EDITTEXT IDC_EXCEPTION_ADDRESS,65,25,75,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Description",IDC_STATIC,10,40,36,8 - GROUPBOX "Exception Info",IDC_STATIC,5,5,255,200 - EDITTEXT IDC_EXCEPTION_MODULE,145,25,110,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Module",IDC_STATIC,145,15,24,8 - EDITTEXT IDC_EXCEPTION_DESC,10,50,245,30,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "&Ignore",IDB_IGNORE,160,207,59,14,WS_DISABLED -END - -IDD_EXCEPTION DIALOG 0, 0, 138, 52 -STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "Exception" -FONT 8, "MS Sans Serif" -BEGIN - LTEXT "Exception Intercepted\r\nRetrieving Info...",IDC_STATIC,33,18,71,19 -END - -IDD_CONFIRM_SAVE_LEVEL DIALOGEX 0, 0, 280, 123 -STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION -EXSTYLE WS_EX_TOPMOST -CAPTION "Engine, Game or Editor Crash" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - PUSHBUTTON "Save",IDB_CONFIRM_SAVE,4,96,68,20 - PUSHBUTTON "Cancel",IDB_DONT_SAVE,206,96,68,20 - LTEXT "Open 3D Engine has encountered an error and needs to close.\n\nA backup has been saved to the '_savebackup' subfolder.\n\nIf you are unable to save your file, you can recover by copying the contents of the _savebackup folder over the broken files.",IDC_STATIC,60,8,210,61 - LTEXT "Attempt save?",IDC_STATIC,60,72,180,21 - CONTROL 128,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,8,8,48,40 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -IDB_CRASH_FACE BITMAP "crash_face.bmp" -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/Code/CryEngine/CrySystem/CryAsyncMemcpy.cpp b/Code/CryEngine/CrySystem/CryAsyncMemcpy.cpp deleted file mode 100644 index b2aaea1634..0000000000 --- a/Code/CryEngine/CrySystem/CryAsyncMemcpy.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include -#include - -namespace -{ - static void cryAsyncMemcpy_Int( - void* dst - , const void* src - , size_t size - , int nFlags - , volatile int* sync) - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::System); - - cryMemcpy(dst, src, size, nFlags); - if (sync) - { - CryInterlockedDecrement(sync); - } - } -} - -#if !defined(CRY_ASYNC_MEMCPY_DELEGATE_TO_CRYSYSTEM) -CRY_ASYNC_MEMCPY_API void cryAsyncMemcpy( -#else -CRY_ASYNC_MEMCPY_API void cryAsyncMemcpyDelegate( -#endif - void* dst - , const void* src - , size_t size - , int nFlags - , volatile int* sync) -{ - AZ::Job* job = AZ::CreateJobFunction( - [dst, src, size, nFlags, sync]() - { - cryAsyncMemcpy_Int(dst, src, size, nFlags, sync); - }, - true); // Auto-delete - job->Start(); -} - - - diff --git a/Code/CryEngine/CrySystem/CryDLMalloc.c b/Code/CryEngine/CrySystem/CryDLMalloc.c deleted file mode 100644 index bcb835b0d5..0000000000 --- a/Code/CryEngine/CrySystem/CryDLMalloc.c +++ /dev/null @@ -1,6645 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#define DEFAULT_GRANULARITY (64 * 1024) //this gets #undef and redefined in the .inl this has to come before that - -#if defined(AZ_RESTRICTED_PLATFORM) -#undef AZ_RESTRICTED_SECTION -#define CRYDLMALLOC_C_SECTION_1 1 -#define CRYDLMALLOC_C_SECTION_2 2 - -#include "../../Framework/AzCore/AzCore/PlatformRestrictedFileDef.h" -#define AZ_RESTRICTED_SECTION CRYDLMALLOC_C_SECTION_1 -#include AZ_RESTRICTED_FILE(CryDLMalloc_c) -#elif defined(_WIN32) || defined(LINUX) || defined(APPLE) -#define TRAIT_ENABLE_DLMALLOC 1 -#endif - -#if defined(BUCKET_SIMULATOR) || TRAIT_ENABLE_DLMALLOC -/* - This is a version (aka dlmalloc) of malloc/free/realloc written by - Doug Lea and released to the public domain, as explained at - http://creativecommons.org/licenses/publicdomain. Send questions, - comments, complaints, performance data, etc to dl@cs.oswego.edu - -* Version 2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee) - - Note: There may be an updated version of this malloc obtainable at - ftp://gee.cs.oswego.edu/pub/misc/malloc.c - Check before installing! - -* Quickstart - - This library is all in one file to simplify the most common usage: - ftp it, compile it (-O3), and link it into another program. All of - the compile-time options default to reasonable values for use on - most platforms. You might later want to step through various - compile-time and dynamic tuning options. - - For convenience, an include file for code using this malloc is at: - ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.4.h - You don't really need this .h file unless you call functions not - defined in your system include files. The .h file contains only the - excerpts from this file needed for using this malloc on ANSI C/C++ - systems, so long as you haven't changed compile-time options about - naming and tuning parameters. If you do, then you can create your - own malloc.h that does include all settings by cutting at the point - indicated below. Note that you may already by default be using a C - library containing a malloc that is based on some version of this - malloc (for example in linux). You might still want to use the one - in this file to customize settings or to avoid overheads associated - with library versions. - -* Vital statistics: - - Supported pointer/size_t representation: 4 or 8 bytes - size_t MUST be an unsigned type of the same width as - pointers. (If you are using an ancient system that declares - size_t as a signed type, or need it to be a different width - than pointers, you can use a previous release of this malloc - (e.g. 2.7.2) supporting these.) - - Alignment: 8 bytes (default) - This suffices for nearly all current machines and C compilers. - However, you can define MALLOC_ALIGNMENT to be wider than this - if necessary (up to 128bytes), at the expense of using more space. - - Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) - 8 or 16 bytes (if 8byte sizes) - Each malloced chunk has a hidden word of overhead holding size - and status information, and additional cross-check word - if FOOTERS is defined. - - Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) - 8-byte ptrs: 32 bytes (including overhead) - - Even a request for zero bytes (i.e., malloc(0)) returns a - pointer to something of the minimum allocatable size. - The maximum overhead wastage (i.e., number of extra bytes - allocated than were requested in malloc) is less than or equal - to the minimum size, except for requests >= mmap_threshold that - are serviced via mmap(), where the worst case wastage is about - 32 bytes plus the remainder from a system page (the minimal - mmap unit); typically 4096 or 8192 bytes. - - Security: static-safe; optionally more or less - The "security" of malloc refers to the ability of malicious - code to accentuate the effects of errors (for example, freeing - space that is not currently malloc'ed or overwriting past the - ends of chunks) in code that calls malloc. This malloc - guarantees not to modify any memory locations below the base of - heap, i.e., static variables, even in the presence of usage - errors. The routines additionally detect most improper frees - and reallocs. All this holds as long as the static bookkeeping - for malloc itself is not corrupted by some other means. This - is only one aspect of security -- these checks do not, and - cannot, detect all possible programming errors. - - If FOOTERS is defined nonzero, then each allocated chunk - carries an additional check word to verify that it was malloced - from its space. These check words are the same within each - execution of a program using malloc, but differ across - executions, so externally crafted fake chunks cannot be - freed. This improves security by rejecting frees/reallocs that - could corrupt heap memory, in addition to the checks preventing - writes to statics that are always on. This may further improve - security at the expense of time and space overhead. (Note that - FOOTERS may also be worth using with MSPACES.) - - By default detected errors cause the program to abort (calling - "abort()"). You can override this to instead proceed past - errors by defining PROCEED_ON_ERROR. In this case, a bad free - has no effect, and a malloc that encounters a bad address - caused by user overwrites will ignore the bad address by - dropping pointers and indices to all known memory. This may - be appropriate for programs that should continue if at all - possible in the face of programming errors, although they may - run out of memory because dropped memory is never reclaimed. - - If you don't like either of these options, you can define - CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything - else. And if if you are sure that your program using malloc has - no errors or vulnerabilities, you can define INSECURE to 1, - which might (or might not) provide a small performance improvement. - - Thread-safety: NOT thread-safe unless USE_LOCKS defined - When USE_LOCKS is defined, each public call to malloc, free, - etc is surrounded with either a pthread mutex or a win32 - spinlock (depending on WIN32). This is not especially fast, and - can be a major bottleneck. It is designed only to provide - minimal protection in concurrent environments, and to provide a - basis for extensions. If you are using malloc in a concurrent - program, consider instead using nedmalloc - (http://www.nedprod.com/programs/portable/nedmalloc/) or - ptmalloc (See http://www.malloc.de), which are derived - from versions of this malloc. - - System requirements: Any combination of MORECORE and/or MMAP/MUNMAP - This malloc can use unix sbrk or any emulation (invoked using - the CALL_MORECORE macro) and/or mmap/munmap or any emulation - (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system - memory. On most unix systems, it tends to work best if both - MORECORE and MMAP are enabled. On Win32, it uses emulations - based on VirtualAlloc. It also uses common C library functions - like memset. - - Compliance: I believe it is compliant with the Single Unix Specification - (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably - others as well. - -* Overview of algorithms - - This is not the fastest, most space-conserving, most portable, or - most tunable malloc ever written. However it is among the fastest - while also being among the most space-conserving, portable and - tunable. Consistent balance across these factors results in a good - general-purpose allocator for malloc-intensive programs. - - In most ways, this malloc is a best-fit allocator. Generally, it - chooses the best-fitting existing chunk for a request, with ties - broken in approximately least-recently-used order. (This strategy - normally maintains low fragmentation.) However, for requests less - than 256bytes, it deviates from best-fit when there is not an - exactly fitting available chunk by preferring to use space adjacent - to that used for the previous small request, as well as by breaking - ties in approximately most-recently-used order. (These enhance - locality of series of small allocations.) And for very large requests - (>= 256Kb by default), it relies on system memory mapping - facilities, if supported. (This helps avoid carrying around and - possibly fragmenting memory used only for large chunks.) - - All operations (except malloc_stats and mallinfo) have execution - times that are bounded by a constant factor of the number of bits in - a size_t, not counting any clearing in calloc or copying in realloc, - or actions surrounding MORECORE and MMAP that have times - proportional to the number of non-contiguous regions returned by - system allocation routines, which is often just 1. In real-time - applications, you can optionally suppress segment traversals using - NO_SEGMENT_TRAVERSAL, which assures bounded execution even when - system allocators return non-contiguous spaces, at the typical - expense of carrying around more memory and increased fragmentation. - - The implementation is not very modular and seriously overuses - macros. Perhaps someday all C compilers will do as good a job - inlining modular code as can now be done by brute-force expansion, - but now, enough of them seem not to. - - Some compilers issue a lot of warnings about code that is - dead/unreachable only on some platforms, and also about intentional - uses of negation on unsigned types. All known cases of each can be - ignored. - - For a longer but out of date high-level description, see - http://gee.cs.oswego.edu/dl/html/malloc.html - -* MSPACES - If MSPACES is defined, then in addition to malloc, free, etc., - this file also defines mspace_malloc, mspace_free, etc. These - are versions of malloc routines that take an "mspace" argument - obtained using create_mspace, to control all internal bookkeeping. - If ONLY_MSPACES is defined, only these versions are compiled. - So if you would like to use this allocator for only some allocations, - and your system malloc for others, you can compile with - ONLY_MSPACES and then do something like... - static mspace mymspace = create_mspace(0,0); // for example - #define mymalloc(bytes) mspace_malloc(mymspace, bytes) - - (Note: If you only need one instance of an mspace, you can instead - use "USE_DL_PREFIX" to relabel the global malloc.) - - You can similarly create thread-local allocators by storing - mspaces as thread-locals. For example: - static __thread mspace tlms = 0; - void* tlmalloc(size_t bytes) { - if (tlms == 0) tlms = create_mspace(0, 0); - return mspace_malloc(tlms, bytes); - } - void tlfree(void* mem) { mspace_free(tlms, mem); } - - Unless FOOTERS is defined, each mspace is completely independent. - You cannot allocate from one and free to another (although - conformance is only weakly checked, so usage errors are not always - caught). If FOOTERS is defined, then each chunk carries around a tag - indicating its originating mspace, and frees are directed to their - originating spaces. - - ------------------------- Compile-time options --------------------------- - -Be careful in setting #define values for numerical constants of type -size_t. On some systems, literal values are not automatically extended -to size_t precision unless they are explicitly casted. You can also -use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below. - -WIN32 default: defined if _WIN32 defined - Defining WIN32 sets up defaults for MS environment and compilers. - Otherwise defaults are for unix. Beware that there seem to be some - cases where this malloc might not be a pure drop-in replacement for - Win32 malloc: Random-looking failures from Win32 GDI API's (eg; - SetDIBits()) may be due to bugs in some video driver implementations - when pixel buffers are malloc()ed, and the region spans more than - one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb) - default granularity, pixel buffers may straddle virtual allocation - regions more often than when using the Microsoft allocator. You can - avoid this by using VirtualAlloc() and VirtualFree() for all pixel - buffers rather than using malloc(). If this is not possible, - recompile this malloc with a larger DEFAULT_GRANULARITY. - -MALLOC_ALIGNMENT default: (size_t)8 - Controls the minimum alignment for malloc'ed chunks. It must be a - power of two and at least 8, even on machines for which smaller - alignments would suffice. It may be defined as larger than this - though. Note however that code and data structures are optimized for - the case of 8-byte alignment. - -MSPACES default: 0 (false) - If true, compile in support for independent allocation spaces. - This is only supported if HAVE_MMAP is true. - -ONLY_MSPACES default: 0 (false) - If true, only compile in mspace versions, not regular versions. - -USE_LOCKS default: 0 (false) - Causes each call to each public routine to be surrounded with - pthread or WIN32 mutex lock/unlock. (If set true, this can be - overridden on a per-mspace basis for mspace versions.) If set to a - non-zero value other than 1, locks are used, but their - implementation is left out, so lock functions must be supplied manually, - as described below. - -USE_SPIN_LOCKS default: 1 iff USE_LOCKS and on x86 using gcc or MSC - If true, uses custom spin locks for locking. This is currently - supported only for x86 platforms using gcc or recent MS compilers. - Otherwise, posix locks or win32 critical sections are used. - -FOOTERS default: 0 - If true, provide extra checking and dispatching by placing - information in the footers of allocated chunks. This adds - space and time overhead. - -INSECURE default: 0 - If true, omit checks for usage errors and heap space overwrites. - -USE_DL_PREFIX default: NOT defined - Causes compiler to prefix all public routines with the string 'dl'. - This can be useful when you only want to use this malloc in one part - of a program, using your regular system malloc elsewhere. - -ABORT default: defined as abort() - Defines how to abort on failed checks. On most systems, a failed - check cannot die with an "assert" or even print an informative - message, because the underlying print routines in turn call malloc, - which will fail again. Generally, the best policy is to simply call - abort(). It's not very useful to do more than this because many - errors due to overwriting will show up as address faults (null, odd - addresses etc) rather than malloc-triggered checks, so will also - abort. Also, most compilers know that abort() does not return, so - can better optimize code conditionally calling it. - -PROCEED_ON_ERROR default: defined as 0 (false) - Controls whether detected bad addresses cause them to bypassed - rather than aborting. If set, detected bad arguments to free and - realloc are ignored. And all bookkeeping information is zeroed out - upon a detected overwrite of freed heap space, thus losing the - ability to ever return it from malloc again, but enabling the - application to proceed. If PROCEED_ON_ERROR is defined, the - static variable malloc_corruption_error_count is compiled in - and can be examined to see if errors have occurred. This option - generates slower code than the default abort policy. - -DEBUG default: NOT defined - The DEBUG setting is mainly intended for people trying to modify - this code or diagnose problems when porting to new platforms. - However, it may also be able to better isolate user errors than just - using runtime checks. The assertions in the check routines spell - out in more detail the assumptions and invariants underlying the - algorithms. The checking is fairly extensive, and will slow down - execution noticeably. Calling malloc_stats or mallinfo with DEBUG - set will attempt to check every non-mmapped allocated and free chunk - in the course of computing the summaries. - -ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) - Debugging assertion failures can be nearly impossible if your - version of the assert macro causes malloc to be called, which will - lead to a cascade of further failures, blowing the runtime stack. - ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), - which will usually make debugging easier. - -MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 - The action to take before "return 0" when malloc fails to be able to - return memory because there is none available. - -HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES - True if this system supports sbrk or an emulation of it. - -MORECORE default: sbrk - The name of the sbrk-style system routine to call to obtain more - memory. See below for guidance on writing custom MORECORE - functions. The type of the argument to sbrk/MORECORE varies across - systems. It cannot be size_t, because it supports negative - arguments, so it is normally the signed type of the same width as - size_t (sometimes declared as "intptr_t"). It doesn't much matter - though. Internally, we only call it with arguments less than half - the max value of a size_t, which should work across all reasonable - possibilities, although sometimes generating compiler warnings. - -MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE - If true, take advantage of fact that consecutive calls to MORECORE - with positive arguments always return contiguous increasing - addresses. This is true of unix sbrk. It does not hurt too much to - set it true anyway, since malloc copes with non-contiguities. - Setting it false when definitely non-contiguous saves time - and possibly wasted space it would take to discover this though. - -MORECORE_CANNOT_TRIM default: NOT defined - True if MORECORE cannot release space back to the system when given - negative arguments. This is generally necessary only if you are - using a hand-crafted MORECORE function that cannot handle negative - arguments. - -NO_SEGMENT_TRAVERSAL default: 0 - If non-zero, suppresses traversals of memory segments - returned by either MORECORE or CALL_MMAP. This disables - merging of segments that are contiguous, and selectively - releasing them to the OS if unused, but bounds execution times. - -HAVE_MMAP default: 1 (true) - True if this system supports mmap or an emulation of it. If so, and - HAVE_MORECORE is not true, MMAP is used for all system - allocation. If set and HAVE_MORECORE is true as well, MMAP is - primarily used to directly allocate very large blocks. It is also - used as a backup strategy in cases where MORECORE fails to provide - space from system. Note: A single call to MUNMAP is assumed to be - able to unmap memory that may have be allocated using multiple calls - to MMAP, so long as they are adjacent. - -HAVE_MREMAP default: 1 on linux, else 0 - If true realloc() uses mremap() to re-allocate large blocks and - extend or shrink allocation spaces. - -MMAP_CLEARS default: 1 except on WINCE. - True if mmap clears memory so calloc doesn't need to. This is true - for standard unix mmap using /dev/zero and on WIN32 except for WINCE. - -USE_BUILTIN_FFS default: 0 (i.e., not used) - Causes malloc to use the builtin ffs() function to compute indices. - Some compilers may recognize and intrinsify ffs to be faster than the - supplied C version. Also, the case of x86 using gcc is special-cased - to an asm instruction, so is already as fast as it can be, and so - this setting has no effect. Similarly for Win32 under recent MS compilers. - (On most x86s, the asm version is only slightly faster than the C version.) - -malloc_getpagesize default: derive from system includes, or 4096. - The system page size. To the extent possible, this malloc manages - memory from the system in page-size units. This may be (and - usually is) a function rather than a constant. This is ignored - if WIN32, where page size is determined using getSystemInfo during - initialization. - -USE_DEV_RANDOM default: 0 (i.e., not used) - Causes malloc to use /dev/random to initialize secure magic seed for - stamping footers. Otherwise, the current time is used. - -NO_MALLINFO default: 0 - If defined, don't compile "mallinfo". This can be a simple way - of dealing with mismatches between system declarations and - those in this file. - -MALLINFO_FIELD_TYPE default: size_t - The type of the fields in the mallinfo struct. This was originally - defined as "int" in SVID etc, but is more usefully defined as - size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set - -REALLOC_ZERO_BYTES_FREES default: not defined - This should be set if a call to realloc with zero bytes should - be the same as a call to free. Some people think it should. Otherwise, - since this malloc returns a unique pointer for malloc(0), so does - realloc(p, 0). - -LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H -LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H -LACKS_STDLIB_H default: NOT defined unless on WIN32 - Define these if your system does not have these header files. - You might need to manually insert some of the declarations they provide. - -DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, - system_info.dwAllocationGranularity in WIN32, - otherwise 64K. - Also settable using mallopt(M_GRANULARITY, x) - The unit for allocating and deallocating memory from the system. On - most systems with contiguous MORECORE, there is no reason to - make this more than a page. However, systems with MMAP tend to - either require or encourage larger granularities. You can increase - this value to prevent system allocation functions to be called so - often, especially if they are slow. The value must be at least one - page and must be a power of two. Setting to 0 causes initialization - to either page size or win32 region size. (Note: In previous - versions of malloc, the equivalent of this option was called - "TOP_PAD") - -DEFAULT_TRIM_THRESHOLD default: 2MB - Also settable using mallopt(M_TRIM_THRESHOLD, x) - The maximum amount of unused top-most memory to keep before - releasing via malloc_trim in free(). Automatic trimming is mainly - useful in long-lived programs using contiguous MORECORE. Because - trimming via sbrk can be slow on some systems, and can sometimes be - wasteful (in cases where programs immediately afterward allocate - more large chunks) the value should be high enough so that your - overall system performance would improve by releasing this much - memory. As a rough guide, you might set to a value close to the - average size of a process (program) running on your system. - Releasing this much memory would allow such a process to run in - memory. Generally, it is worth tuning trim thresholds when a - program undergoes phases where several large chunks are allocated - and released in ways that can reuse each other's storage, perhaps - mixed with phases where there are no such chunks at all. The trim - value must be greater than page size to have any useful effect. To - disable trimming completely, you can set to MAX_SIZE_T. Note that the trick - some people use of mallocing a huge space and then freeing it at - program startup, in an attempt to reserve system memory, doesn't - have the intended effect under automatic trimming, since that memory - will immediately be returned to the system. - -DEFAULT_MMAP_THRESHOLD default: 256K - Also settable using mallopt(M_MMAP_THRESHOLD, x) - The request size threshold for using MMAP to directly service a - request. Requests of at least this size that cannot be allocated - using already-existing space will be serviced via mmap. (If enough - normal freed space already exists it is used instead.) Using mmap - segregates relatively large chunks of memory so that they can be - individually obtained and released from the host system. A request - serviced through mmap is never reused by any other request (at least - not directly; the system may just so happen to remap successive - requests to the same locations). Segregating space in this way has - the benefits that: Mmapped space can always be individually released - back to the system, which helps keep the system level memory demands - of a long-lived program low. Also, mapped memory doesn't become - `locked' between other chunks, as can happen with normally allocated - chunks, which means that even trimming via malloc_trim would not - release them. However, it has the disadvantage that the space - cannot be reclaimed, consolidated, and then used to service later - requests, as happens with normal chunks. The advantages of mmap - nearly always outweigh disadvantages for "large" chunks, but the - value of "large" may vary across systems. The default is an - empirically derived value that works well in most systems. You can - disable mmap by setting to MAX_SIZE_T. - -MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP - The number of consolidated frees between checks to release - unused segments when freeing. When using non-contiguous segments, - especially with multiple mspaces, checking only for topmost space - doesn't always suffice to trigger trimming. To compensate for this, - free() will, with a period of MAX_RELEASE_CHECK_RATE (or the - current number of segments, if greater) try to release unused - segments to the OS when freeing chunks that result in - consolidation. The best value for this parameter is a compromise - between slowing down frees with relatively costly checks that - rarely trigger versus holding on to unused memory. To effectively - disable, set to MAX_SIZE_T. This may lead to a very slight speed - improvement at the expense of carrying around more memory. -*/ - -/* Version identifier to allow people to support multiple versions */ - -#ifndef DLMALLOC_VERSION -#define DLMALLOC_VERSION 20804 -#endif /* DLMALLOC_VERSION */ - - -#define MAX_RELEASE_CHECK_RATE 255 -#define REALLOC_ZERO_BYTES_FREES -#define USE_DL_PREFIX 1 - -#define mspace_create_overhead dlmspace_create_overhead -#define create_mspace dlcreate_mspace -#define destroy_mspace dldestroy_mspace -#define create_mspace_with_base dlcreate_mspace_with_base -#define mspace_track_large_chunks dlmspace_track_large_chunks -#define mspace_malloc dlmspace_malloc -#define mspace_free dlmspace_free -#define mspace_realloc dlmspace_realloc -#define mspace_calloc dlmspace_calloc -#define mspace_memalign dlmspace_memalign -#define mspace_independent_calloc dlmspace_independent_calloc -#define mspace_independent_comalloc dlmspace_independent_comalloc -#define mspace_footprint dlmspace_footprint -#define mspace_max_footprint dlmspace_max_footprint -#define mspace_mallinfo dlmspace_mallinfo -#define mspace_usable_size dlmspace_usable_size -#define mspace_malloc_stats dlmspace_malloc_stats -#define mspace_get_used_space dlmspace_get_used_space -#define mspace_trim dlmspace_trim -#define mspace_mallopt dlmspace_mallopt - -// Avoid x64 warnings with size_t converted to int -#pragma warning(disable : 4267) -#pragma warning(disable : 6239) -#pragma warning(disable : 6297) -#pragma warning(disable : 28182) - -// Conditional expression is constant -#pragma warning(disable : 4127) - -#ifdef BUCKET_SIMULATOR - -#define HAVE_MORECORE 0 -#define MORECORE SimSBrk -#define DEFAULT_MMAP_THRESHOLD (1024 * 1024) -#define DEFAULT_TRIM_THRESHOLD (256 * 1024) - -#include -#include -#include -#include /* For size_t */ -#include - -static void* s_sbrkBase; -static void* s_sbrkEnd; -static void* s_sbrkMax; - -extern volatile int dlmallocmapped; - -void* SimSBrk(ptrdiff_t size) -{ - void* ret = NULL; - - if (!s_sbrkBase) - { - s_sbrkBase = VirtualAlloc(NULL, 64 * 1024 * 1024, MEM_RESERVE, PAGE_READWRITE); - s_sbrkEnd = s_sbrkBase; - s_sbrkMax = (LPVOID) ((INT_PTR) s_sbrkBase + 64 * 1024 * 1024); - } - - if (s_sbrkEnd) - { - if (size > 0) - { - INT_PTR end = (INT_PTR) s_sbrkEnd; - INT_PTR newEnd = end + size; - - if (newEnd <= (INT_PTR) s_sbrkMax) - { - ret = VirtualAlloc(s_sbrkEnd, size, MEM_COMMIT, PAGE_READWRITE); - if (ret) - { - s_sbrkEnd = (LPVOID) newEnd; - CryInterlockedAdd(&dlmallocmapped, (LONG) size); - } - } - } - else if (size < 0) - { - INT_PTR end = (INT_PTR) s_sbrkEnd; - INT_PTR newEnd = end + size; - - if (newEnd >= (INT_PTR) s_sbrkBase) - { - VirtualFree((LPVOID) newEnd, -size, MEM_DECOMMIT); - CryInterlockedAdd(&dlmallocmapped, (LONG) size); - } - } - else - { - ret = s_sbrkEnd; - } - } - - if (!ret) - { - ret = (void*) -1; - errno = ENOMEM; - } - - return ret; -} -#endif - -#if defined(AZ_RESTRICTED_PLATFORM) -#elif defined(_WIN32) - -#define HAVE_MMAP 1 -#define HAVE_MORECORE (!HAVE_MMAP) -#define USE_LOCKS 0 -#define FOOTERS 0 -#define ONLY_MSPACES 1 -#define DEFAULT_MMAP_THRESHOLD (1024 * 1024) -#define DEFAULT_TRIM_THRESHOLD (256 * 1024) - -#define PROT_READ 0 -#define PROT_WRITE 0 -#define MAP_PRIVATE 0 -#define MAP_ANONYMOUS 1 - -#define MALLOC_ALIGNMENT 16 - -#define malloc_getpagesize (64 * 1024) - -#include -#include - -#elif defined(LINUX) || defined(APPLE) -#include -#define HAVE_MMAP 1 -#define HAVE_MORECORE (!HAVE_MMAP) -#define USE_LOCKS 0 -#define FOOTERS 0 -#define ONLY_MSPACES 1 -#define DEFAULT_MMAP_THRESHOLD (16 * 1024 * 1024) -#define DEFAULT_TRIM_THRESHOLD (16 * 1024 * 1024) - -#if !defined(ANDROID) && !defined(LINUX_CROSS_COMPILE) -#define PROT_READ 0 -#define PROT_WRITE 0 -#define MAP_PRIVATE 0 -#define MAP_ANONYMOUS 1 -#endif - -#define MALLOC_ALIGNMENT 16 - -#define malloc_getpagesize (64 * 1024) - -#include - -// ( || ) is always a non-zero constant. -#pragma warning(disable:6285) - -// Potential comparison of a constant with another constant -#pragma warning(disable:6326) - -// Dereferencing NULL pointer -#pragma warning(disable:6011) - -#endif - -#ifndef WIN32 -#ifdef _WIN32 -#define WIN32 1 -#endif /* _WIN32 */ -#ifdef _WIN32_WCE -#define LACKS_FCNTL_H -#define WIN32 1 -#endif /* _WIN32_WCE */ -#endif /* WIN32 */ - -#ifdef WIN32 -#include -#define HAVE_MMAP 1 -#ifndef HAVE_MORECORE -#define HAVE_MORECORE 0 -#endif -#define LACKS_UNISTD_H -#define LACKS_SYS_PARAM_H -#define LACKS_SYS_MMAN_H -#define LACKS_STRING_H -#define LACKS_STRINGS_H -#define LACKS_SYS_TYPES_H -#define LACKS_ERRNO_H -#ifndef MALLOC_FAILURE_ACTION -#define MALLOC_FAILURE_ACTION -#endif /* MALLOC_FAILURE_ACTION */ -#ifdef _WIN32_WCE /* WINCE reportedly does not clear */ -#define MMAP_CLEARS 0 -#else -#define MMAP_CLEARS 1 -#endif /* _WIN32_WCE */ -#endif /* WIN32 */ - -#if defined(DARWIN) || defined(_DARWIN) -/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ -#ifndef HAVE_MORECORE -#define HAVE_MORECORE 0 -#define HAVE_MMAP 1 -/* OSX allocators provide 16 byte alignment */ -#ifndef MALLOC_ALIGNMENT -#define MALLOC_ALIGNMENT ((size_t)16U) -#endif -#endif /* HAVE_MORECORE */ -#endif /* DARWIN */ - -#ifndef LACKS_SYS_TYPES_H -#include /* For size_t */ -#endif /* LACKS_SYS_TYPES_H */ - -#if (defined(__GNUC__) && ((defined(__i386__) || defined(__x86_64__)))) || (defined(_MSC_VER)) -#define SPIN_LOCKS_AVAILABLE 1 -#else -#define SPIN_LOCKS_AVAILABLE 0 -#endif - -/* The maximum possible size_t value has all bits set */ -#define MAX_SIZE_T (~(size_t)0) - -#ifndef ONLY_MSPACES -#define ONLY_MSPACES 0 /* define to a value */ -#else -#define ONLY_MSPACES 1 -#endif /* ONLY_MSPACES */ -#ifndef MSPACES -#if ONLY_MSPACES -#define MSPACES 1 -#else /* ONLY_MSPACES */ -#define MSPACES 0 -#endif /* ONLY_MSPACES */ -#endif /* MSPACES */ -#ifndef MALLOC_ALIGNMENT -#define MALLOC_ALIGNMENT ((size_t)8U) -#endif /* MALLOC_ALIGNMENT */ -#ifndef FOOTERS -#define FOOTERS 0 -#endif /* FOOTERS */ -#ifndef ABORT -#define ABORT abort() -#endif /* ABORT */ -#ifndef ABORT_ON_ASSERT_FAILURE -#define ABORT_ON_ASSERT_FAILURE 1 -#endif /* ABORT_ON_ASSERT_FAILURE */ -#ifndef PROCEED_ON_ERROR -#define PROCEED_ON_ERROR 0 -#endif /* PROCEED_ON_ERROR */ -#ifndef USE_LOCKS -#define USE_LOCKS 0 -#endif /* USE_LOCKS */ -#ifndef USE_SPIN_LOCKS -#if USE_LOCKS && SPIN_LOCKS_AVAILABLE -#define USE_SPIN_LOCKS 1 -#else -#define USE_SPIN_LOCKS 0 -#endif /* USE_LOCKS && SPIN_LOCKS_AVAILABLE. */ -#endif /* USE_SPIN_LOCKS */ -#ifndef INSECURE -#define INSECURE 0 -#endif /* INSECURE */ -#ifndef HAVE_MMAP -#define HAVE_MMAP 1 -#endif /* HAVE_MMAP */ -#ifndef MMAP_CLEARS -#define MMAP_CLEARS 1 -#endif /* MMAP_CLEARS */ -#ifndef HAVE_MREMAP -#ifdef linux -#define HAVE_MREMAP 1 -#else /* linux */ -#define HAVE_MREMAP 0 -#endif /* linux */ -#endif /* HAVE_MREMAP */ -#ifndef MALLOC_FAILURE_ACTION -#define MALLOC_FAILURE_ACTION errno = ENOMEM; -#endif /* MALLOC_FAILURE_ACTION */ -#ifndef HAVE_MORECORE -#if ONLY_MSPACES -#define HAVE_MORECORE 0 -#else /* ONLY_MSPACES */ -#define HAVE_MORECORE 1 -#endif /* ONLY_MSPACES */ -#endif /* HAVE_MORECORE */ -#if !HAVE_MORECORE -#define MORECORE_CONTIGUOUS 0 -#else /* !HAVE_MORECORE */ -#define MORECORE_DEFAULT sbrk -#ifndef MORECORE_CONTIGUOUS -#define MORECORE_CONTIGUOUS 1 -#endif /* MORECORE_CONTIGUOUS */ -#endif /* HAVE_MORECORE */ -#ifndef DEFAULT_GRANULARITY -#if (MORECORE_CONTIGUOUS || defined(WIN32)) -#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ -#else /* MORECORE_CONTIGUOUS */ -#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) -#endif /* MORECORE_CONTIGUOUS */ -#endif /* DEFAULT_GRANULARITY */ -#ifndef DEFAULT_TRIM_THRESHOLD -#ifndef MORECORE_CANNOT_TRIM -#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) -#else /* MORECORE_CANNOT_TRIM */ -#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T -#endif /* MORECORE_CANNOT_TRIM */ -#endif /* DEFAULT_TRIM_THRESHOLD */ -#ifndef DEFAULT_MMAP_THRESHOLD -#if HAVE_MMAP -#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) -#else /* HAVE_MMAP */ -#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T -#endif /* HAVE_MMAP */ -#endif /* DEFAULT_MMAP_THRESHOLD */ -#ifndef MAX_RELEASE_CHECK_RATE -#if HAVE_MMAP -#define MAX_RELEASE_CHECK_RATE 4095 -#else -#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T -#endif /* HAVE_MMAP */ -#endif /* MAX_RELEASE_CHECK_RATE */ -#ifndef USE_BUILTIN_FFS -#define USE_BUILTIN_FFS 0 -#endif /* USE_BUILTIN_FFS */ -#ifndef USE_DEV_RANDOM -#define USE_DEV_RANDOM 0 -#endif /* USE_DEV_RANDOM */ -#ifndef NO_MALLINFO -#define NO_MALLINFO 0 -#endif /* NO_MALLINFO */ -#ifndef MALLINFO_FIELD_TYPE -#define MALLINFO_FIELD_TYPE size_t -#endif /* MALLINFO_FIELD_TYPE */ -#ifndef NO_SEGMENT_TRAVERSAL -#define NO_SEGMENT_TRAVERSAL 0 -#endif /* NO_SEGMENT_TRAVERSAL */ - -/* - mallopt tuning options. SVID/XPG defines four standard parameter - numbers for mallopt, normally defined in malloc.h. None of these - are used in this malloc, so setting them has no effect. But this - malloc does support the following options. -*/ - -#define M_TRIM_THRESHOLD (-1) -#define M_GRANULARITY (-2) -#define M_MMAP_THRESHOLD (-3) - -// --------- Traits -------------- - -#if !defined(AZ_RESTRICTED_PLATFORM) - #if defined(_MSC_VER) - #define TRAIT_HAS_BITSCANFORWARD 1 - #define TRAIT_HAS_BITSCANREVERSE 1 - #endif - #if defined(WIN32) - #define TRAIT_HAS_WIN32_MMAP 1 - #endif - #if defined(WIN32) || defined(WIN64) - #define TRAIT_HAS_GETSYSTEMINFO 1 - #endif - #if defined(_WIN32) - #define TRAIT_USE_QUERYPERFORMANCECOUNTER 1 - #endif -#endif - -/* ------------------------ Mallinfo declarations ------------------------ */ - -#if !NO_MALLINFO -/* - This version of malloc supports the standard SVID/XPG mallinfo - routine that returns a struct containing usage properties and - statistics. It should work on any system that has a - /usr/include/malloc.h defining struct mallinfo. The main - declaration needed is the mallinfo struct that is returned (by-copy) - by mallinfo(). The malloinfo struct contains a bunch of fields that - are not even meaningful in this version of malloc. These fields are - are instead filled by mallinfo() with other numbers that might be of - interest. - - HAVE_USR_INCLUDE_MALLOC_H should be set if you have a - /usr/include/malloc.h file that includes a declaration of struct - mallinfo. If so, it is included; else a compliant version is - declared below. These must be precisely the same for mallinfo() to - work. The original SVID version of this struct, defined on most - systems with mallinfo, declares all fields as ints. But some others - define as unsigned long. If your system defines the fields using a - type of different width than listed here, you MUST #include your - system version and #define HAVE_USR_INCLUDE_MALLOC_H. -*/ - -/* #define HAVE_USR_INCLUDE_MALLOC_H */ - -#ifdef HAVE_USR_INCLUDE_MALLOC_H -#include "/usr/include/malloc.h" -#else /* HAVE_USR_INCLUDE_MALLOC_H */ -#ifndef STRUCT_MALLINFO_DECLARED -#define STRUCT_MALLINFO_DECLARED 1 -struct mallinfo -{ - MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ - MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ - MALLINFO_FIELD_TYPE smblks; /* always 0 */ - MALLINFO_FIELD_TYPE hblks; /* always 0 */ - MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ - MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ - MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ - MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ - MALLINFO_FIELD_TYPE fordblks; /* total free space */ - MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ -}; -#endif /* STRUCT_MALLINFO_DECLARED */ -#endif /* HAVE_USR_INCLUDE_MALLOC_H */ -#endif /* NO_MALLINFO */ - -/* - Try to persuade compilers to inline. The most critical functions for - inlining are defined as macros, so these aren't used for them. -*/ - -#ifndef FORCEINLINE - #if defined(__GNUC__) -#define FORCEINLINE __inline __attribute__ ((always_inline)) - #elif defined(_MSC_VER) - #define FORCEINLINE __forceinline - #endif -#endif -#ifndef NOINLINE - #if defined(__GNUC__) - #define NOINLINE __attribute__ ((noinline)) - #elif defined(_MSC_VER) - #define NOINLINE __declspec(noinline) - #else - #define NOINLINE - #endif -#endif - -#ifdef __cplusplus -extern "C" { -#ifndef FORCEINLINE - #define FORCEINLINE inline -#endif -#endif /* __cplusplus */ -#ifndef FORCEINLINE - #define FORCEINLINE -#endif - -typedef void* (* dlmmap_handler)(void*, size_t); -typedef int (* dlmunmap_handler)(void*, void*, size_t); - -#if !ONLY_MSPACES - -/* ------------------- Declarations of public routines ------------------- */ - -#ifndef USE_DL_PREFIX -#define dlcalloc calloc -#define dlfree free -#define dlmalloc malloc -#define dlmemalign memalign -#define dlrealloc realloc -#define dlvalloc valloc -#define dlpvalloc pvalloc -#define dlmallinfo mallinfo -#define dlmallopt mallopt -#define dlmalloc_trim malloc_trim -#define dlmalloc_stats malloc_stats -#define dlmalloc_usable_size malloc_usable_size -#define dlmalloc_footprint malloc_footprint -#define dlmalloc_max_footprint malloc_max_footprint -#define dlindependent_calloc independent_calloc -#define dlindependent_comalloc independent_comalloc -#endif /* USE_DL_PREFIX */ - - -/* - malloc(size_t n) - Returns a pointer to a newly allocated chunk of at least n bytes, or - null if no space is available, in which case errno is set to ENOMEM - on ANSI C systems. - - If n is zero, malloc returns a minimum-sized chunk. (The minimum - size is 16 bytes on most 32bit systems, and 32 bytes on 64bit - systems.) Note that size_t is an unsigned type, so calls with - arguments that would be negative if signed are interpreted as - requests for huge amounts of space, which will often fail. The - maximum supported value of n differs across systems, but is in all - cases less than the maximum representable value of a size_t. -*/ -void* dlmalloc(size_t); - -/* - free(void* p) - Releases the chunk of memory pointed to by p, that had been previously - allocated using malloc or a related routine such as realloc. - It has no effect if p is null. If p was not malloced or already - freed, free(p) will by default cause the current program to abort. -*/ -void dlfree(void*); - -/* - calloc(size_t n_elements, size_t element_size); - Returns a pointer to n_elements * element_size bytes, with all locations - set to zero. -*/ -void* dlcalloc(size_t, size_t); - -/* - realloc(void* p, size_t n) - Returns a pointer to a chunk of size n that contains the same data - as does chunk p up to the minimum of (n, p's size) bytes, or null - if no space is available. - - The returned pointer may or may not be the same as p. The algorithm - prefers extending p in most cases when possible, otherwise it - employs the equivalent of a malloc-copy-free sequence. - - If p is null, realloc is equivalent to malloc. - - If space is not available, realloc returns null, errno is set (if on - ANSI) and p is NOT freed. - - if n is for fewer bytes than already held by p, the newly unused - space is lopped off and freed if possible. realloc with a size - argument of zero (re)allocates a minimum-sized chunk. - - The old unix realloc convention of allowing the last-free'd chunk - to be used as an argument to realloc is not supported. -*/ - -void* dlrealloc(void*, size_t); - -/* - memalign(size_t alignment, size_t n); - Returns a pointer to a newly allocated chunk of n bytes, aligned - in accord with the alignment argument. - - The alignment argument should be a power of two. If the argument is - not a power of two, the nearest greater power is used. - 8-byte alignment is guaranteed by normal malloc calls, so don't - bother calling memalign with an argument of 8 or less. - - Overreliance on memalign is a sure way to fragment space. -*/ -void* dlmemalign(size_t, size_t); - -/* - valloc(size_t n); - Equivalent to memalign(pagesize, n), where pagesize is the page - size of the system. If the pagesize is unknown, 4096 is used. -*/ -void* dlvalloc(size_t); - -/* - mallopt(int parameter_number, int parameter_value) - Sets tunable parameters The format is to provide a - (parameter-number, parameter-value) pair. mallopt then sets the - corresponding parameter to the argument value if it can (i.e., so - long as the value is meaningful), and returns 1 if successful else - 0. To workaround the fact that mallopt is specified to use int, - not size_t parameters, the value -1 is specially treated as the - maximum unsigned size_t value. - - SVID/XPG/ANSI defines four standard param numbers for mallopt, - normally defined in malloc.h. None of these are use in this malloc, - so setting them has no effect. But this malloc also supports other - options in mallopt. See below for details. Briefly, supported - parameters are as follows (listed defaults are for "typical" - configurations). - - Symbol param # default allowed param values - M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables) - M_GRANULARITY -2 page size any power of 2 >= page size - M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) -*/ -int dlmallopt(int, int); - -/* - malloc_footprint(); - Returns the number of bytes obtained from the system. The total - number of bytes allocated by malloc, realloc etc., is less than this - value. Unlike mallinfo, this function returns only a precomputed - result, so can be called frequently to monitor memory consumption. - Even if locks are otherwise defined, this function does not use them, - so results might not be up to date. -*/ -size_t dlmalloc_footprint(void); - -/* - malloc_max_footprint(); - Returns the maximum number of bytes obtained from the system. This - value will be greater than current footprint if deallocated space - has been reclaimed by the system. The peak number of bytes allocated - by malloc, realloc etc., is less than this value. Unlike mallinfo, - this function returns only a precomputed result, so can be called - frequently to monitor memory consumption. Even if locks are - otherwise defined, this function does not use them, so results might - not be up to date. -*/ -size_t dlmalloc_max_footprint(void); - -#if !NO_MALLINFO -/* - mallinfo() - Returns (by copy) a struct containing various summary statistics: - - arena: current total non-mmapped bytes allocated from system - ordblks: the number of free chunks - smblks: always zero. - hblks: current number of mmapped regions - hblkhd: total bytes held in mmapped regions - usmblks: the maximum total allocated space. This will be greater - than current total if trimming has occurred. - fsmblks: always zero - uordblks: current total allocated space (normal or mmapped) - fordblks: total free space - keepcost: the maximum number of bytes that could ideally be released - back to system via malloc_trim. ("ideally" means that - it ignores page restrictions etc.) - - Because these fields are ints, but internal bookkeeping may - be kept as longs, the reported values may wrap around zero and - thus be inaccurate. -*/ -struct mallinfo dlmallinfo(void); -#endif /* NO_MALLINFO */ - -/* - independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); - - independent_calloc is similar to calloc, but instead of returning a - single cleared space, it returns an array of pointers to n_elements - independent elements that can hold contents of size elem_size, each - of which starts out cleared, and can be independently freed, - realloc'ed etc. The elements are guaranteed to be adjacently - allocated (this is not guaranteed to occur with multiple callocs or - mallocs), which may also improve cache locality in some - applications. - - The "chunks" argument is optional (i.e., may be null, which is - probably the most typical usage). If it is null, the returned array - is itself dynamically allocated and should also be freed when it is - no longer needed. Otherwise, the chunks array must be of at least - n_elements in length. It is filled in with the pointers to the - chunks. - - In either case, independent_calloc returns this pointer array, or - null if the allocation failed. If n_elements is zero and "chunks" - is null, it returns a chunk representing an array with zero elements - (which should be freed if not wanted). - - Each element must be individually freed when it is no longer - needed. If you'd like to instead be able to free all at once, you - should instead use regular calloc and assign pointers into this - space to represent elements. (In this case though, you cannot - independently free elements.) - - independent_calloc simplifies and speeds up implementations of many - kinds of pools. It may also be useful when constructing large data - structures that initially have a fixed number of fixed-sized nodes, - but the number is not known at compile time, and some of the nodes - may later need to be freed. For example: - - struct Node { int item; struct Node* next; }; - - struct Node* build_list() { - struct Node** pool; - int n = read_number_of_nodes_needed(); - if (n <= 0) return 0; - pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); - if (pool == 0) die(); - // organize into a linked list... - struct Node* first = pool[0]; - for (i = 0; i < n-1; ++i) - pool[i]->next = pool[i+1]; - free(pool); // Can now free the array (or not, if it is needed later) - return first; - } -*/ -void** dlindependent_calloc(size_t, size_t, void**); - -/* - independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); - - independent_comalloc allocates, all at once, a set of n_elements - chunks with sizes indicated in the "sizes" array. It returns - an array of pointers to these elements, each of which can be - independently freed, realloc'ed etc. The elements are guaranteed to - be adjacently allocated (this is not guaranteed to occur with - multiple callocs or mallocs), which may also improve cache locality - in some applications. - - The "chunks" argument is optional (i.e., may be null). If it is null - the returned array is itself dynamically allocated and should also - be freed when it is no longer needed. Otherwise, the chunks array - must be of at least n_elements in length. It is filled in with the - pointers to the chunks. - - In either case, independent_comalloc returns this pointer array, or - null if the allocation failed. If n_elements is zero and chunks is - null, it returns a chunk representing an array with zero elements - (which should be freed if not wanted). - - Each element must be individually freed when it is no longer - needed. If you'd like to instead be able to free all at once, you - should instead use a single regular malloc, and assign pointers at - particular offsets in the aggregate space. (In this case though, you - cannot independently free elements.) - - independent_comallac differs from independent_calloc in that each - element may have a different size, and also that it does not - automatically clear elements. - - independent_comalloc can be used to speed up allocation in cases - where several structs or objects must always be allocated at the - same time. For example: - - struct Head { ... } - struct Foot { ... } - - void send_message(char* msg) { - int msglen = strlen(msg); - size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; - void* chunks[3]; - if (independent_comalloc(3, sizes, chunks) == 0) - die(); - struct Head* head = (struct Head*)(chunks[0]); - char* body = (char*)(chunks[1]); - struct Foot* foot = (struct Foot*)(chunks[2]); - // ... - } - - In general though, independent_comalloc is worth using only for - larger values of n_elements. For small values, you probably won't - detect enough difference from series of malloc calls to bother. - - Overuse of independent_comalloc can increase overall memory usage, - since it cannot reuse existing noncontiguous small chunks that - might be available for some of the elements. -*/ -void** dlindependent_comalloc(size_t, size_t*, void**); - - -/* - pvalloc(size_t n); - Equivalent to valloc(minimum-page-that-holds(n)), that is, - round up n to nearest pagesize. - */ -void* dlpvalloc(size_t); - -/* - malloc_trim(size_t pad); - - If possible, gives memory back to the system (via negative arguments - to sbrk) if there is unused memory at the `high' end of the malloc - pool or in unused MMAP segments. You can call this after freeing - large blocks of memory to potentially reduce the system-level memory - requirements of a program. However, it cannot guarantee to reduce - memory. Under some allocation patterns, some large free blocks of - memory will be locked between two used chunks, so they cannot be - given back to the system. - - The `pad' argument to malloc_trim represents the amount of free - trailing space to leave untrimmed. If this argument is zero, only - the minimum amount of memory to maintain internal data structures - will be left. Non-zero arguments can be supplied to maintain enough - trailing space to service future expected allocations without having - to re-obtain memory from the system. - - Malloc_trim returns 1 if it actually released any memory, else 0. -*/ -int dlmalloc_trim(size_t); - -/* - malloc_stats(); - Prints on stderr the amount of space obtained from the system (both - via sbrk and mmap), the maximum amount (which may be more than - current if malloc_trim and/or munmap got called), and the current - number of bytes allocated via malloc (or realloc, etc) but not yet - freed. Note that this is the number of bytes allocated, not the - number requested. It will be larger than the number requested - because of alignment and bookkeeping overhead. Because it includes - alignment wastage as being in use, this figure may be greater than - zero even when no user-level chunks are allocated. - - The reported current and maximum system memory can be inaccurate if - a program makes other calls to system memory allocation functions - (normally sbrk) outside of malloc. - - malloc_stats prints only the most commonly interesting statistics. - More information can be obtained by calling mallinfo. -*/ -void dlmalloc_stats(void); -void dlmalloc_stats_ret(size_t* sys, size_t* maxSys, size_t* used); - -#endif /* ONLY_MSPACES */ - -/* - malloc_usable_size(void* p); - - Returns the number of bytes you can actually use in - an allocated chunk, which may be more than you requested (although - often not) due to alignment and minimum size constraints. - You can use this many bytes without worrying about - overwriting other allocated objects. This is not a particularly great - programming practice. malloc_usable_size can be more useful in - debugging and assertions, for example: - - p = malloc(n); - assert(malloc_usable_size(p) >= 256); -*/ -size_t dlmalloc_usable_size(void*); - - -#if MSPACES - -/* - mspace is an opaque type representing an independent - region of space that supports mspace_malloc, etc. -*/ -typedef void* mspace; - -/* - mspace_create_overhead returns the number of bytes used by an mspace for - internal tracking. Can be used with the capacity argument when creating - an mspace to allocate an exact amount of space upfront. -*/ -int mspace_create_overhead(void); - -/* - create_mspace creates and returns a new independent space with the - given initial capacity, or, if 0, the default granularity size. It - returns null if there is no system memory available to create the - space. If argument locked is non-zero, the space uses a separate - lock to control access. The capacity of the space will grow - dynamically as needed to service mspace_malloc requests. You can - control the sizes of incremental increases of this space by - compiling with a different DEFAULT_GRANULARITY or dynamically - setting with mallopt(M_GRANULARITY, value). -*/ -mspace create_mspace(size_t capacity, int locked, void* user, dlmmap_handler mmap, dlmunmap_handler munmap); - -/* - destroy_mspace destroys the given space, and attempts to return all - of its memory back to the system, returning the total number of - bytes freed. After destruction, the results of access to all memory - used by the space become undefined. -*/ -size_t destroy_mspace(mspace msp); - -/* - create_mspace_with_base uses the memory supplied as the initial base - of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this - space is used for bookkeeping, so the capacity must be at least this - large. (Otherwise 0 is returned.) When this initial space is - exhausted, additional memory will be obtained from the system. - Destroying this space will deallocate all additionally allocated - space (if possible) but not the initial base. -*/ -mspace create_mspace_with_base(void* base, size_t capacity, int locked); - -/* - mspace_track_large_chunks controls whether requests for large chunks - are allocated in their own untracked mmapped regions, separate from - others in this mspace. By default large chunks are not tracked, - which reduces fragmentation. However, such chunks are not - necessarily released to the system upon destroy_mspace. Enabling - tracking by setting to true may increase fragmentation, but avoids - leakage when relying on destroy_mspace to release all memory - allocated using this space. The function returns the previous - setting. -*/ -int mspace_track_large_chunks(mspace msp, int enable); - - -/* - mspace_malloc behaves as malloc, but operates within - the given space. -*/ -void* mspace_malloc(mspace msp, size_t bytes); - -/* - mspace_free behaves as free, but operates within - the given space. - - If compiled with FOOTERS==1, mspace_free is not actually needed. - free may be called instead of mspace_free because freed chunks from - any space are handled by their originating spaces. -*/ -void mspace_free(mspace msp, void* mem); - -/* - mspace_realloc behaves as realloc, but operates within - the given space. - - If compiled with FOOTERS==1, mspace_realloc is not actually - needed. realloc may be called instead of mspace_realloc because - realloced chunks from any space are handled by their originating - spaces. -*/ -void* mspace_realloc(mspace msp, void* mem, size_t newsize); - -/* - mspace_calloc behaves as calloc, but operates within - the given space. -*/ -void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); - -/* - mspace_memalign behaves as memalign, but operates within - the given space. -*/ -void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); - -/* - mspace_independent_calloc behaves as independent_calloc, but - operates within the given space. -*/ -void** mspace_independent_calloc(mspace msp, size_t n_elements, - size_t elem_size, void* chunks[]); - -/* - mspace_independent_comalloc behaves as independent_comalloc, but - operates within the given space. -*/ -void** mspace_independent_comalloc(mspace msp, size_t n_elements, - size_t sizes[], void* chunks[]); - -/* - mspace_footprint() returns the number of bytes obtained from the - system for this space. -*/ -size_t mspace_footprint(mspace msp); - -/* - mspace_max_footprint() returns the peak number of bytes obtained from the - system for this space. -*/ -size_t mspace_max_footprint(mspace msp); - - -#if !NO_MALLINFO -/* - mspace_mallinfo behaves as mallinfo, but reports properties of - the given space. -*/ -struct mallinfo mspace_mallinfo(mspace msp); -#endif /* NO_MALLINFO */ - -/* - malloc_usable_size(void* p) behaves the same as malloc_usable_size; -*/ -size_t mspace_usable_size(void* mem); - -/* - mspace_malloc_stats behaves as malloc_stats, but reports - properties of the given space. -*/ -void mspace_malloc_stats(mspace msp); - -/* - mspace_trim behaves as malloc_trim, but - operates within the given space. -*/ -int mspace_trim(mspace msp, size_t pad); - -/* - An alias for mallopt. -*/ -int mspace_mallopt(int, int); - -#endif /* MSPACES */ - -#ifdef __cplusplus -}; /* end of extern "C" */ -#endif /* __cplusplus */ - -/* - ======================================================================== - To make a fully customizable malloc.h header file, cut everything - above this line, put into file malloc.h, edit to suit, and #include it - on the next line, as well as in programs that use this malloc. - ======================================================================== -*/ - -/* #include "malloc.h" */ - -/*------------------------------ internal #includes ---------------------- */ - -#ifdef WIN32 -#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ -#endif /* WIN32 */ - -#include /* for printing in malloc_stats */ - -#ifndef LACKS_ERRNO_H -#include /* for MALLOC_FAILURE_ACTION */ -#endif /* LACKS_ERRNO_H */ -#if FOOTERS || DEBUG -#include /* for magic initialization */ -#endif /* FOOTERS */ -#ifndef LACKS_STDLIB_H -#include /* for abort() */ -#endif /* LACKS_STDLIB_H */ -#ifdef DEBUG -#if ABORT_ON_ASSERT_FAILURE -#undef assert -#define assert(x) if (!(x)) ABORT -#else /* ABORT_ON_ASSERT_FAILURE */ -#include -#endif /* ABORT_ON_ASSERT_FAILURE */ -#else /* DEBUG */ -#ifndef assert -#define assert(x) -#endif -#define DEBUG 0 -#endif /* DEBUG */ -#ifndef LACKS_STRING_H -#include /* for memset etc */ -#endif /* LACKS_STRING_H */ -#if USE_BUILTIN_FFS -#ifndef LACKS_STRINGS_H -#include /* for ffs */ -#endif /* LACKS_STRINGS_H */ -#endif /* USE_BUILTIN_FFS */ -#if HAVE_MMAP -#ifndef LACKS_SYS_MMAN_H -/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */ -#if (defined(linux) && !defined(__USE_GNU)) -#define __USE_GNU 1 -#include /* for mmap */ -#undef __USE_GNU -#else -#include /* for mmap */ -#endif /* linux */ -#endif /* LACKS_SYS_MMAN_H */ -#ifndef LACKS_FCNTL_H -#include -#endif /* LACKS_FCNTL_H */ -#endif /* HAVE_MMAP */ -#ifndef LACKS_UNISTD_H -#include /* for sbrk, sysconf */ -#else /* LACKS_UNISTD_H */ -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(_WIN32) -extern void* sbrk(ptrdiff_t); -#endif /* FreeBSD etc */ -#endif /* LACKS_UNISTD_H */ - -/* Declarations for locking */ -#if USE_LOCKS -#ifndef WIN32 -#if defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION CRYDLMALLOC_C_SECTION_2 -#include AZ_RESTRICTED_FILE(CryDLMalloc_c) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else -#include -#endif -#if defined (__SVR4) && defined (__sun) /* solaris */ -#include -#endif /* solaris */ -#else -#ifndef _M_AMD64 -/* These are already defined on AMD64 builds */ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ -LONG __cdecl _InterlockedCompareExchange(LONG volatile* Dest, LONG Exchange, LONG Comp); -LONG __cdecl _InterlockedExchange(LONG volatile* Target, LONG Value); -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* _M_AMD64 */ -#pragma intrinsic (_InterlockedCompareExchange) -#pragma intrinsic (_InterlockedExchange) -#define interlockedcompareexchange _InterlockedCompareExchange -#define interlockedexchange _InterlockedExchange -#endif /* Win32 */ -#endif /* USE_LOCKS */ - -/* Declarations for bit scanning on win32 */ -#if defined(_MSC_VER) && _MSC_VER >= 1300 -#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ -unsigned char _BitScanForward(unsigned long* index, unsigned long mask); -unsigned char _BitScanReverse(unsigned long* index, unsigned long mask); -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#define BitScanForward _BitScanForward -#define BitScanReverse _BitScanReverse -#pragma intrinsic(_BitScanForward) -#pragma intrinsic(_BitScanReverse) -#endif /* BitScanForward */ -#endif /* defined(_MSC_VER) */ - -#ifndef WIN32 -#ifndef malloc_getpagesize -# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ -# ifndef _SC_PAGE_SIZE -# define _SC_PAGE_SIZE _SC_PAGESIZE -# endif -# endif -# ifdef _SC_PAGE_SIZE -# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) -# else -# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) -extern size_t getpagesize(); -# define malloc_getpagesize getpagesize() -# else -# ifdef WIN32 /* use supplied emulation of getpagesize */ -# define malloc_getpagesize getpagesize() -# else -# ifndef LACKS_SYS_PARAM_H -# include -# endif -# ifdef EXEC_PAGESIZE -# define malloc_getpagesize EXEC_PAGESIZE -# else -# ifdef NBPG -# ifndef CLSIZE -# define malloc_getpagesize NBPG -# else -# define malloc_getpagesize (NBPG * CLSIZE) -# endif -# else -# ifdef NBPC -# define malloc_getpagesize NBPC -# else -# ifdef PAGESIZE -# define malloc_getpagesize PAGESIZE -# else /* just guess */ -# define malloc_getpagesize ((size_t)4096U) -# endif -# endif -# endif -# endif -# endif -# endif -# endif -#endif -#endif - - - -/* ------------------- size_t and alignment properties -------------------- */ - -/* The byte and bit size of a size_t */ -#define SIZE_T_SIZE (sizeof(size_t)) -#define SIZE_T_BITSIZE (sizeof(size_t) << 3) - -/* Some constants coerced to size_t */ -/* Annoying but necessary to avoid errors on some platforms */ -#define SIZE_T_ZERO ((size_t)0) -#define SIZE_T_ONE ((size_t)1) -#define SIZE_T_TWO ((size_t)2) -#define SIZE_T_FOUR ((size_t)4) -#define TWO_SIZE_T_SIZES (SIZE_T_SIZE << 1) -#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE << 2) -#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES + TWO_SIZE_T_SIZES) -#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) - -/* The bit mask value corresponding to MALLOC_ALIGNMENT */ -#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) - -/* True if address a has acceptable alignment */ -#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) - -/* the number of bytes to offset an address to align it */ -#define align_offset(A) \ - ((((size_t)(A) &CHUNK_ALIGN_MASK) == 0) ? 0 : \ - ((MALLOC_ALIGNMENT - ((size_t)(A) &CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) - -/* -------------------------- MMAP preliminaries ------------------------- */ - -/* - If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and - checks to fail so compiler optimizer can delete code rather than - using so many "#if"s. -*/ - - -/* MORECORE and MMAP must return MFAIL on failure */ -#define MFAIL ((void*)(MAX_SIZE_T)) -#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ - -#if HAVE_MMAP - -#if !TRAIT_HAS_WIN32_MMAP -#define MUNMAP_DEFAULT(a, s) munmap((a), (s)) -#define MMAP_PROT (PROT_READ | PROT_WRITE) -#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) -#define MAP_ANONYMOUS MAP_ANON -#endif /* MAP_ANON */ -#ifdef MAP_ANONYMOUS -#define MMAP_FLAGS (MAP_PRIVATE | MAP_ANONYMOUS) -#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) -#else /* MAP_ANONYMOUS */ -/* - Nearly all versions of mmap support MAP_ANONYMOUS, so the following - is unlikely to be needed, but is supplied just in case. -*/ -#define MMAP_FLAGS (MAP_PRIVATE) -static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ -#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \ - (dev_zero_fd = open("/dev/zero", O_RDWR), \ - mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ - mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) -#endif /* MAP_ANONYMOUS */ - -#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s) - -#else /* TRAIT_HAS_WIN32_MMAP */ - -/* Win32 MMAP via VirtualAlloc */ -static FORCEINLINE void* win32mmap(size_t size) -{ - void* ptr = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - return (ptr != 0) ? ptr : MFAIL; -} - -/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ -static FORCEINLINE void* win32direct_mmap(size_t size) -{ - void* ptr = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, - PAGE_READWRITE); - return (ptr != 0) ? ptr : MFAIL; -} - -/* This function supports releasing coalesed segments */ -static FORCEINLINE int win32munmap(void* ptr, size_t size) -{ - MEMORY_BASIC_INFORMATION minfo; - char* cptr = (char*)ptr; - while (size) - { - if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) - { - return -1; - } - if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || - minfo.State != MEM_COMMIT || minfo.RegionSize > size) - { - return -1; - } - if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) - { - return -1; - } - cptr += minfo.RegionSize; - size -= minfo.RegionSize; - } - return 0; -} - -#define MMAP_DEFAULT(s) win32mmap(s) -#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s)) -#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s) -#endif /* TRAIT_HAS_WIN32_MMAP */ -#endif /* HAVE_MMAP */ - -#if HAVE_MREMAP -#ifndef WIN32 -#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) -#endif /* WIN32 */ -#endif /* HAVE_MREMAP */ - - -/** - * Define CALL_MORECORE - */ -#if HAVE_MORECORE - #ifdef MORECORE - #define CALL_MORECORE(S) MORECORE(S) - #else /* MORECORE */ - #define CALL_MORECORE(S) MORECORE_DEFAULT(S) - #endif /* MORECORE */ -#else /* HAVE_MORECORE */ - #define CALL_MORECORE(S) MFAIL -#endif /* HAVE_MORECORE */ - -/** - * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP - */ -#if HAVE_MMAP - #define USE_MMAP_BIT (SIZE_T_ONE) - - #ifdef MMAP - #define CALL_MMAP(s) MMAP(s) - #else /* MMAP */ - #define CALL_MMAP(s) MMAP_DEFAULT(s) - #endif /* MMAP */ - #ifdef MUNMAP - #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) - #else /* MUNMAP */ - #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s)) - #endif /* MUNMAP */ - #ifdef DIRECT_MMAP - #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) - #else /* DIRECT_MMAP */ - #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s) - #endif /* DIRECT_MMAP */ -#else /* HAVE_MMAP */ - #define USE_MMAP_BIT (SIZE_T_ZERO) - - #define MMAP(s) MFAIL - #define MUNMAP(a, s) (-1) - #define DIRECT_MMAP(s) MFAIL - #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) - #define CALL_MMAP(s) MMAP(s) - #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) -#endif /* HAVE_MMAP */ - -/** - * Define CALL_MREMAP - */ -#if HAVE_MMAP && HAVE_MREMAP - #ifdef MREMAP - #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv)) - #else /* MREMAP */ - #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv)) - #endif /* MREMAP */ -#else /* HAVE_MMAP && HAVE_MREMAP */ - #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL -#endif /* HAVE_MMAP && HAVE_MREMAP */ - -/* mstate bit set if continguous morecore disabled or failed */ -#define USE_NONCONTIGUOUS_BIT (4U) - -/* segment bit set in create_mspace_with_base */ -#define EXTERN_BIT (8U) - - -/* --------------------------- Lock preliminaries ------------------------ */ - -/* - When locks are defined, there is one global lock, plus - one per-mspace lock. - - The global lock_ensures that mparams.magic and other unique - mparams values are initialized only once. It also protects - sequences of calls to MORECORE. In many cases sys_alloc requires - two calls, that should not be interleaved with calls by other - threads. This does not protect against direct calls to MORECORE - by other threads not using this lock, so there is still code to - cope the best we can on interference. - - Per-mspace locks surround calls to malloc, free, etc. To enable use - in layered extensions, per-mspace locks are reentrant. - - Because lock-protected regions generally have bounded times, it is - OK to use the supplied simple spinlocks in the custom versions for - x86. Spinlocks are likely to improve performance for lightly - contended applications, but worsen performance under heavy - contention. - - If USE_LOCKS is > 1, the definitions of lock routines here are - bypassed, in which case you will need to define the type MLOCK_T, - and at least INITIAL_LOCK, ACQUIRE_LOCK, RELEASE_LOCK and possibly - TRY_LOCK (which is not used in this malloc, but commonly needed in - extensions.) You must also declare a - static MLOCK_T malloc_global_mutex = { initialization values };. - -*/ - -#if USE_LOCKS == 1 - -#if USE_SPIN_LOCKS && SPIN_LOCKS_AVAILABLE -#ifndef WIN32 - -/* Custom pthread-style spin locks on x86 and x64 for gcc */ -struct pthread_mlock_t -{ - volatile unsigned int l; - unsigned int c; - pthread_t threadid; -}; -#define MLOCK_T struct pthread_mlock_t -#define CURRENT_THREAD pthread_self() -#define INITIAL_LOCK(sl) ((sl)->threadid = 0, (sl)->l = (sl)->c = 0, 0) -#define ACQUIRE_LOCK(sl) pthread_acquire_lock(sl) -#define RELEASE_LOCK(sl) pthread_release_lock(sl) -#define TRY_LOCK(sl) pthread_try_lock(sl) -#define SPINS_PER_YIELD 63 - -static MLOCK_T malloc_global_mutex = { 0, 0, 0}; - -static FORCEINLINE int pthread_acquire_lock (MLOCK_T* sl) -{ - int spins = 0; - volatile unsigned int* lp = &sl->l; - for (;; ) - { - if (*lp != 0) - { - if (sl->threadid == CURRENT_THREAD) - { - ++sl->c; - return 0; - } - } - else - { - /* place args to cmpxchgl in locals to evade oddities in some gccs */ - int cmp = 0; - int val = 1; - int ret; - __asm__ __volatile__ ("lock; cmpxchgl %1, %2" - : "=a" (ret) - : "r" (val), "m" (*(lp)), "0" (cmp) - : "memory", "cc"); - if (!ret) - { - assert(!sl->threadid); - sl->threadid = CURRENT_THREAD; - sl->c = 1; - return 0; - } - } - if ((++spins & SPINS_PER_YIELD) == 0) - { -#if defined (__SVR4) && defined (__sun) /* solaris */ - thr_yield(); -#else -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) - sched_yield(); -#else /* no-op yield on unknown systems */ - ; -#endif /* __linux__ || __FreeBSD__ || __APPLE__ */ -#endif /* solaris */ - } - } -} - -static FORCEINLINE void pthread_release_lock (MLOCK_T* sl) -{ - volatile unsigned int* lp = &sl->l; - assert(*lp != 0); - assert(sl->threadid == CURRENT_THREAD); - if (--sl->c == 0) - { - sl->threadid = 0; - int prev = 0; - int ret; - __asm__ __volatile__ ("lock; xchgl %0, %1" - : "=r" (ret) - : "m" (*(lp)), "0" (prev) - : "memory"); - } -} - -static FORCEINLINE int pthread_try_lock (MLOCK_T* sl) -{ - volatile unsigned int* lp = &sl->l; - if (*lp != 0) - { - if (sl->threadid == CURRENT_THREAD) - { - ++sl->c; - return 1; - } - } - else - { - int cmp = 0; - int val = 1; - int ret; - __asm__ __volatile__ ("lock; cmpxchgl %1, %2" - : "=a" (ret) - : "r" (val), "m" (*(lp)), "0" (cmp) - : "memory", "cc"); - if (!ret) - { - assert(!sl->threadid); - sl->threadid = CURRENT_THREAD; - sl->c = 1; - return 1; - } - } - return 0; -} - - -#else /* WIN32 */ -/* Custom win32-style spin locks on x86 and x64 for MSC */ -struct win32_mlock_t -{ - volatile long l; - unsigned int c; - long threadid; -}; - -#define MLOCK_T struct win32_mlock_t -#define CURRENT_THREAD GetCurrentThreadId() -#define INITIAL_LOCK(sl) ((sl)->threadid = 0, (sl)->l = (sl)->c = 0, 0) -#define ACQUIRE_LOCK(sl) win32_acquire_lock(sl) -#define RELEASE_LOCK(sl) win32_release_lock(sl) -#define TRY_LOCK(sl) win32_try_lock(sl) -#define SPINS_PER_YIELD 63 - -static MLOCK_T malloc_global_mutex = { 0, 0, 0}; - -static FORCEINLINE int win32_acquire_lock (MLOCK_T* sl) -{ - int spins = 0; - for (;; ) - { - if (sl->l != 0) - { - if (sl->threadid == CURRENT_THREAD) - { - ++sl->c; - return 0; - } - } - else - { - if (!interlockedexchange(&sl->l, 1)) - { - assert(!sl->threadid); - sl->threadid = CURRENT_THREAD; - sl->c = 1; - return 0; - } - } - if ((++spins & SPINS_PER_YIELD) == 0) - { - SleepEx(0, FALSE); - } - } -} - -static FORCEINLINE void win32_release_lock (MLOCK_T* sl) -{ - assert(sl->threadid == CURRENT_THREAD); - assert(sl->l != 0); - if (--sl->c == 0) - { - sl->threadid = 0; - interlockedexchange (&sl->l, 0); - } -} - -static FORCEINLINE int win32_try_lock (MLOCK_T* sl) -{ - if (sl->l != 0) - { - if (sl->threadid == CURRENT_THREAD) - { - ++sl->c; - return 1; - } - } - else - { - if (!interlockedexchange(&sl->l, 1)) - { - assert(!sl->threadid); - sl->threadid = CURRENT_THREAD; - sl->c = 1; - return 1; - } - } - return 0; -} - -#endif /* WIN32 */ -#else /* USE_SPIN_LOCKS */ - -#ifndef WIN32 -/* pthreads-based locks */ - -#define MLOCK_T pthread_mutex_t -#define CURRENT_THREAD pthread_self() -#define INITIAL_LOCK(sl) pthread_init_lock(sl) -#define ACQUIRE_LOCK(sl) pthread_mutex_lock(sl) -#define RELEASE_LOCK(sl) pthread_mutex_unlock(sl) -#define TRY_LOCK(sl) (!pthread_mutex_trylock(sl)) - -static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* Cope with old-style linux recursive lock initialization by adding */ -/* skipped internal declaration from pthread.h */ -#ifdef linux -#ifndef PTHREAD_MUTEX_RECURSIVE -extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t * __attr, - int __kind)); -#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP -#define pthread_mutexattr_settype(x, y) pthread_mutexattr_setkind_np(x, y) -#endif -#endif - -static int pthread_init_lock (MLOCK_T* sl) -{ - pthread_mutexattr_t attr; - if (pthread_mutexattr_init(&attr)) - { - return 1; - } - if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) - { - return 1; - } - if (pthread_mutex_init(sl, &attr)) - { - return 1; - } - if (pthread_mutexattr_destroy(&attr)) - { - return 1; - } - return 0; -} - -#else /* WIN32 */ -/* Win32 critical sections */ -#define MLOCK_T CRITICAL_SECTION -#define CURRENT_THREAD GetCurrentThreadId() -#define INITIAL_LOCK(s) (!InitializeCriticalSectionAndSpinCount((s), 0x80000000 | 4000)) -#define ACQUIRE_LOCK(s) (EnterCriticalSection(sl), 0) -#define RELEASE_LOCK(s) LeaveCriticalSection(sl) -#define TRY_LOCK(s) TryEnterCriticalSection(sl) -#define NEED_GLOBAL_LOCK_INIT - -static MLOCK_T malloc_global_mutex; -static volatile long malloc_global_mutex_status; - -/* Use spin loop to initialize global lock */ -static void init_malloc_global_mutex() -{ - for (;; ) - { - long stat = malloc_global_mutex_status; - if (stat > 0) - { - return; - } - /* transition to < 0 while initializing, then to > 0) */ - if (stat == 0 && - interlockedcompareexchange(&malloc_global_mutex_status, -1, 0) == 0) - { - InitializeCriticalSection(&malloc_global_mutex); - interlockedexchange(&malloc_global_mutex_status, 1); - return; - } - SleepEx(0, FALSE); - } -} - -#endif /* WIN32 */ -#endif /* USE_SPIN_LOCKS */ -#endif /* USE_LOCKS == 1 */ - -/* ----------------------- User-defined locks ------------------------ */ - -#if USE_LOCKS > 1 -/* Define your own lock implementation here */ -/* #define INITIAL_LOCK(sl) ... */ -/* #define ACQUIRE_LOCK(sl) ... */ -/* #define RELEASE_LOCK(sl) ... */ -/* #define TRY_LOCK(sl) ... */ -/* static MLOCK_T malloc_global_mutex = ... */ -#endif /* USE_LOCKS > 1 */ - -/* ----------------------- Lock-based state ------------------------ */ - -#if USE_LOCKS -#define USE_LOCK_BIT (2U) -#else /* USE_LOCKS */ -#define USE_LOCK_BIT (0U) -#define INITIAL_LOCK(l) -#endif /* USE_LOCKS */ - -#if USE_LOCKS -#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK -#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex); -#endif -#ifndef RELEASE_MALLOC_GLOBAL_LOCK -#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex); -#endif -#else /* USE_LOCKS */ -#define ACQUIRE_MALLOC_GLOBAL_LOCK() -#define RELEASE_MALLOC_GLOBAL_LOCK() -#endif /* USE_LOCKS */ - - -/* ----------------------- Chunk representations ------------------------ */ - -/* - (The following includes lightly edited explanations by Colin Plumb.) - - The malloc_chunk declaration below is misleading (but accurate and - necessary). It declares a "view" into memory allowing access to - necessary fields at known offsets from a given base. - - Chunks of memory are maintained using a `boundary tag' method as - originally described by Knuth. (See the paper by Paul Wilson - ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such - techniques.) Sizes of free chunks are stored both in the front of - each chunk and at the end. This makes consolidating fragmented - chunks into bigger chunks fast. The head fields also hold bits - representing whether chunks are free or in use. - - Here are some pictures to make it clearer. They are "exploded" to - show that the state of a chunk can be thought of as extending from - the high 31 bits of the head field of its header through the - prev_foot and PINUSE_BIT bit of the following chunk header. - - A chunk that's in use looks like: - - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of previous chunk (if P = 0) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| - | Size of this chunk 1| +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - +- -+ - | | - +- -+ - | : - +- size - sizeof(size_t) available payload bytes -+ - : | - chunk-> +- -+ - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| - | Size of next chunk (may or may not be in use) | +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - And if it's free, it looks like this: - - chunk-> +- -+ - | User payload (must be in use, or we would have merged!) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| - | Size of this chunk 0| +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Next pointer | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Prev pointer | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | : - +- size - sizeof(struct chunk) unused bytes -+ - : | - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of this chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| - | Size of next chunk (must be in use, or we would have merged)| +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | : - +- User payload -+ - : | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |0| - +-+ - Note that since we always merge adjacent free chunks, the chunks - adjacent to a free chunk must be in use. - - Given a pointer to a chunk (which can be derived trivially from the - payload pointer) we can, in O(1) time, find out whether the adjacent - chunks are free, and if so, unlink them from the lists that they - are on and merge them with the current chunk. - - Chunks always begin on even word boundaries, so the mem portion - (which is returned to the user) is also on an even word boundary, and - thus at least double-word aligned. - - The P (PINUSE_BIT) bit, stored in the unused low-order bit of the - chunk size (which is always a multiple of two words), is an in-use - bit for the *previous* chunk. If that bit is *clear*, then the - word before the current chunk size contains the previous chunk - size, and can be used to find the front of the previous chunk. - The very first chunk allocated always has this bit set, preventing - access to non-existent (or non-owned) memory. If pinuse is set for - any given chunk, then you CANNOT determine the size of the - previous chunk, and might even get a memory addressing fault when - trying to do so. - - The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of - the chunk size redundantly records whether the current chunk is - inuse (unless the chunk is mmapped). This redundancy enables usage - checks within free and realloc, and reduces indirection when freeing - and consolidating chunks. - - Each freshly allocated chunk must have both cinuse and pinuse set. - That is, each allocated chunk borders either a previously allocated - and still in-use chunk, or the base of its memory arena. This is - ensured by making all allocations from the the `lowest' part of any - found chunk. Further, no free chunk physically borders another one, - so each free chunk is known to be preceded and followed by either - inuse chunks or the ends of memory. - - Note that the `foot' of the current chunk is actually represented - as the prev_foot of the NEXT chunk. This makes it easier to - deal with alignments etc but can be very confusing when trying - to extend or adapt this code. - - The exceptions to all this are - - 1. The special chunk `top' is the top-most available chunk (i.e., - the one bordering the end of available memory). It is treated - specially. Top is never included in any bin, is used only if - no other chunk is available, and is released back to the - system if it is very large (see M_TRIM_THRESHOLD). In effect, - the top chunk is treated as larger (and thus less well - fitting) than any other available chunk. The top chunk - doesn't update its trailing size field since there is no next - contiguous chunk that would have to index off it. However, - space is still allocated for it (TOP_FOOT_SIZE) to enable - separation or merging when space is extended. - - 3. Chunks allocated via mmap, have both cinuse and pinuse bits - cleared in their head fields. Because they are allocated - one-by-one, each must carry its own prev_foot field, which is - also used to hold the offset this chunk has within its mmapped - region, which is needed to preserve alignment. Each mmapped - chunk is trailed by the first two fields of a fake next-chunk - for sake of usage checks. - -*/ - -struct malloc_chunk -{ - size_t prev_foot;/* Size of previous chunk (if free). */ - size_t head; /* Size and inuse bits. */ - struct malloc_chunk* fd; /* double links -- used only if free. */ - struct malloc_chunk* bk; -}; - -typedef struct malloc_chunk mchunk; -typedef struct malloc_chunk* mchunkptr; -typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ -typedef unsigned int bindex_t; /* Described below */ -typedef unsigned int binmap_t; /* Described below */ -typedef unsigned int flag_t; /* The type of various bit flag sets */ - -/* ------------------- Chunks sizes and alignments ----------------------- */ - -#define MCHUNK_SIZE (sizeof(mchunk)) - -#if FOOTERS -#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) -#else /* FOOTERS */ -#define CHUNK_OVERHEAD (SIZE_T_SIZE) -#endif /* FOOTERS */ - -/* MMapped chunks need a second word of overhead ... */ -#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) -/* ... and additional padding for fake next-chunk at foot */ -#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) - -/* The smallest size we can malloc is an aligned minimal chunk */ -#define MIN_CHUNK_SIZE \ - ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) - -/* conversion from malloc headers to user pointers, and back */ -#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) -#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) -/* chunk associated with aligned address A */ -#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) - -/* Bounds on request (not chunk) sizes. */ -#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) -#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) - -/* pad request bytes into a usable size */ -#define pad_request(req) \ - (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) - -/* pad request, checking for minimum (but not maximum) */ -#define request2size(req) \ - (((req) < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(req)) - - -/* ------------------ Operations on head and foot fields ----------------- */ - -/* - The head field of a chunk is or'ed with PINUSE_BIT when previous - adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in - use, unless mmapped, in which case both bits are cleared. - - FLAG4_BIT is not used by this malloc, but might be useful in extensions. -*/ - -#define PINUSE_BIT (SIZE_T_ONE) -#define CINUSE_BIT (SIZE_T_TWO) -#define FLAG4_BIT (SIZE_T_FOUR) -#define INUSE_BITS (PINUSE_BIT | CINUSE_BIT) -#define FLAG_BITS (PINUSE_BIT | CINUSE_BIT | FLAG4_BIT) - -/* Head value for fenceposts */ -#define FENCEPOST_HEAD (INUSE_BITS | SIZE_T_SIZE) - -/* extraction of fields from head words */ -#define cinuse(p) ((p)->head & CINUSE_BIT) -#define pinuse(p) ((p)->head & PINUSE_BIT) -#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT) -#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0) - -#define chunksize(p) ((p)->head & ~(FLAG_BITS)) - -#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) - -/* Treat space at ptr +/- offset as a chunk */ -#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) -#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) - -/* Ptr to next or previous physical malloc_chunk. */ -#define next_chunk(p) ((mchunkptr)(((char*)(p)) + ((p)->head & ~FLAG_BITS))) -#define prev_chunk(p) ((mchunkptr)(((char*)(p)) - ((p)->prev_foot))) - -/* extract next chunk's pinuse bit */ -#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) - -/* Get/set size at footer */ -#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) -#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) - -/* Set size, pinuse bit, and foot */ -#define set_size_and_pinuse_of_free_chunk(p, s) \ - ((p)->head = (s | PINUSE_BIT), set_foot(p, s)) - -/* Set size, pinuse bit, foot, and clear next pinuse */ -#define set_free_with_pinuse(p, s, n) \ - (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) - -/* Get the internal overhead associated with chunk p */ -#define overhead_for(p) \ - (is_mmapped(p) ? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) - -/* Return true if malloced space is not necessarily cleared */ -#if MMAP_CLEARS -#define calloc_must_clear(p) (!is_mmapped(p)) -#else /* MMAP_CLEARS */ -#define calloc_must_clear(p) (1) -#endif /* MMAP_CLEARS */ - -/* ---------------------- Overlaid data structures ----------------------- */ - -/* - When chunks are not in use, they are treated as nodes of either - lists or trees. - - "Small" chunks are stored in circular doubly-linked lists, and look - like this: - - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of previous chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `head:' | Size of chunk, in bytes |P| - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Forward pointer to next chunk in list | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Back pointer to previous chunk in list | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Unused space (may be 0 bytes long) . - . . - . | -nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `foot:' | Size of chunk, in bytes | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Larger chunks are kept in a form of bitwise digital trees (aka - tries) keyed on chunksizes. Because malloc_tree_chunks are only for - free chunks greater than 256 bytes, their size doesn't impose any - constraints on user chunk sizes. Each node looks like: - - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of previous chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `head:' | Size of chunk, in bytes |P| - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Forward pointer to next chunk of same size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Back pointer to previous chunk of same size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Pointer to left child (child[0]) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Pointer to right child (child[1]) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Pointer to parent | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | bin index of this chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Unused space . - . | -nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `foot:' | Size of chunk, in bytes | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Each tree holding treenodes is a tree of unique chunk sizes. Chunks - of the same size are arranged in a circularly-linked list, with only - the oldest chunk (the next to be used, in our FIFO ordering) - actually in the tree. (Tree members are distinguished by a non-null - parent pointer.) If a chunk with the same size an an existing node - is inserted, it is linked off the existing node using pointers that - work in the same way as fd/bk pointers of small chunks. - - Each tree contains a power of 2 sized range of chunk sizes (the - smallest is 0x100 <= x < 0x180), which is is divided in half at each - tree level, with the chunks in the smaller half of the range (0x100 - <= x < 0x140 for the top nose) in the left subtree and the larger - half (0x140 <= x < 0x180) in the right subtree. This is, of course, - done by inspecting individual bits. - - Using these rules, each node's left subtree contains all smaller - sizes than its right subtree. However, the node at the root of each - subtree has no particular ordering relationship to either. (The - dividing line between the subtree sizes is based on trie relation.) - If we remove the last chunk of a given size from the interior of the - tree, we need to replace it with a leaf node. The tree ordering - rules permit a node to be replaced by any leaf below it. - - The smallest chunk in a tree (a common operation in a best-fit - allocator) can be found by walking a path to the leftmost leaf in - the tree. Unlike a usual binary tree, where we follow left child - pointers until we reach a null, here we follow the right child - pointer any time the left one is null, until we reach a leaf with - both child pointers null. The smallest chunk in the tree will be - somewhere along that path. - - The worst case number of steps to add, find, or remove a node is - bounded by the number of bits differentiating chunks within - bins. Under current bin calculations, this ranges from 6 up to 21 - (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case - is of course much better. -*/ - -struct malloc_tree_chunk -{ - /* The first four fields must be compatible with malloc_chunk */ - size_t prev_foot; - size_t head; - struct malloc_tree_chunk* fd; - struct malloc_tree_chunk* bk; - - struct malloc_tree_chunk* child[2]; - struct malloc_tree_chunk* parent; - bindex_t index; -}; - -typedef struct malloc_tree_chunk tchunk; -typedef struct malloc_tree_chunk* tchunkptr; -typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ - -/* A little helper macro for trees */ -#define leftmost_child(t) ((t)->child[0] != 0 ? (t)->child[0] : (t)->child[1]) - -/* ----------------------------- Segments -------------------------------- */ - -/* - Each malloc space may include non-contiguous segments, held in a - list headed by an embedded malloc_segment record representing the - top-most space. Segments also include flags holding properties of - the space. Large chunks that are directly allocated by mmap are not - included in this list. They are instead independently created and - destroyed without otherwise keeping track of them. - - Segment management mainly comes into play for spaces allocated by - MMAP. Any call to MMAP might or might not return memory that is - adjacent to an existing segment. MORECORE normally contiguously - extends the current space, so this space is almost always adjacent, - which is simpler and faster to deal with. (This is why MORECORE is - used preferentially to MMAP when both are available -- see - sys_alloc.) When allocating using MMAP, we don't use any of the - hinting mechanisms (inconsistently) supported in various - implementations of unix mmap, or distinguish reserving from - committing memory. Instead, we just ask for space, and exploit - contiguity when we get it. It is probably possible to do - better than this on some systems, but no general scheme seems - to be significantly better. - - Management entails a simpler variant of the consolidation scheme - used for chunks to reduce fragmentation -- new adjacent memory is - normally prepended or appended to an existing segment. However, - there are limitations compared to chunk consolidation that mostly - reflect the fact that segment processing is relatively infrequent - (occurring only when getting memory from system) and that we - don't expect to have huge numbers of segments: - - * Segments are not indexed, so traversal requires linear scans. (It - would be possible to index these, but is not worth the extra - overhead and complexity for most programs on most platforms.) - * New segments are only appended to old ones when holding top-most - memory; if they cannot be prepended to others, they are held in - different segments. - - Except for the top-most segment of an mstate, each segment record - is kept at the tail of its segment. Segments are added by pushing - segment records onto the list headed by &mstate.seg for the - containing mstate. - - Segment flags control allocation/merge/deallocation policies: - * If EXTERN_BIT set, then we did not allocate this segment, - and so should not try to deallocate or merge with others. - (This currently holds only for the initial segment passed - into create_mspace_with_base.) - * If USE_MMAP_BIT set, the segment may be merged with - other surrounding mmapped segments and trimmed/de-allocated - using munmap. - * If neither bit is set, then the segment was obtained using - MORECORE so can be merged with surrounding MORECORE'd segments - and deallocated/trimmed using MORECORE with negative arguments. -*/ - -struct malloc_segment -{ - char* base; /* base address */ - size_t size; /* allocated size */ - struct malloc_segment* next; /* ptr to next segment */ - flag_t sflags; /* mmap and extern flag */ -}; - -#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT) -#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) - -typedef struct malloc_segment msegment; -typedef struct malloc_segment* msegmentptr; - -/* ---------------------------- malloc_state ----------------------------- */ - -/* - A malloc_state holds all of the bookkeeping for a space. - The main fields are: - - Top - The topmost chunk of the currently active segment. Its size is - cached in topsize. The actual size of topmost space is - topsize+TOP_FOOT_SIZE, which includes space reserved for adding - fenceposts and segment records if necessary when getting more - space from the system. The size at which to autotrim top is - cached from mparams in trim_check, except that it is disabled if - an autotrim fails. - - Designated victim (dv) - This is the preferred chunk for servicing small requests that - don't have exact fits. It is normally the chunk split off most - recently to service another small request. Its size is cached in - dvsize. The link fields of this chunk are not maintained since it - is not kept in a bin. - - SmallBins - An array of bin headers for free chunks. These bins hold chunks - with sizes less than MIN_LARGE_SIZE bytes. Each bin contains - chunks of all the same size, spaced 8 bytes apart. To simplify - use in double-linked lists, each bin header acts as a malloc_chunk - pointing to the real first node, if it exists (else pointing to - itself). This avoids special-casing for headers. But to avoid - waste, we allocate only the fd/bk pointers of bins, and then use - repositioning tricks to treat these as the fields of a chunk. - - TreeBins - Treebins are pointers to the roots of trees holding a range of - sizes. There are 2 equally spaced treebins for each power of two - from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything - larger. - - Bin maps - There is one bit map for small bins ("smallmap") and one for - treebins ("treemap). Each bin sets its bit when non-empty, and - clears the bit when empty. Bit operations are then used to avoid - bin-by-bin searching -- nearly all "search" is done without ever - looking at bins that won't be selected. The bit maps - conservatively use 32 bits per map word, even if on 64bit system. - For a good description of some of the bit-based techniques used - here, see Henry S. Warren Jr's book "Hacker's Delight" (and - supplement at http://hackersdelight.org/). Many of these are - intended to reduce the branchiness of paths through malloc etc, as - well as to reduce the number of memory locations read or written. - - Segments - A list of segments headed by an embedded malloc_segment record - representing the initial space. - - Address check support - The least_addr field is the least address ever obtained from - MORECORE or MMAP. Attempted frees and reallocs of any address less - than this are trapped (unless INSECURE is defined). - - Magic tag - A cross-check field that should always hold same value as mparams.magic. - - Flags - Bits recording whether to use MMAP, locks, or contiguous MORECORE - - Statistics - Each space keeps track of current and maximum system memory - obtained via MORECORE or MMAP. - - Trim support - Fields holding the amount of unused topmost memory that should trigger - timming, and a counter to force periodic scanning to release unused - non-topmost segments. - - Locking - If USE_LOCKS is defined, the "mutex" lock is acquired and released - around every public call using this mspace. - - Extension support - A void* pointer and a size_t field that can be used to help implement - extensions to this malloc. -*/ - -/* Bin types, widths and sizes */ -#define NSMALLBINS (32U) -#define NTREEBINS (32U) -#define SMALLBIN_SHIFT (3U) -#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) -#define TREEBIN_SHIFT (8U) -#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) -#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) -#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) - -struct malloc_state -{ - binmap_t smallmap; - binmap_t treemap; - size_t dvsize; - size_t topsize; - char* least_addr; - mchunkptr dv; - mchunkptr top; - size_t trim_check; - size_t release_checks; - size_t magic; - mchunkptr smallbins[(NSMALLBINS + 1) * 2]; - tbinptr treebins[NTREEBINS]; - size_t footprint; - size_t max_footprint; - flag_t mflags; -#if USE_LOCKS - MLOCK_T mutex; /* locate lock among fields that rarely change */ -#endif /* USE_LOCKS */ - msegment seg; - void* extp; /* Unused but available for extensions */ - size_t exts; - dlmmap_handler mmap; - dlmunmap_handler munmap; -}; - -typedef struct malloc_state* mstate; - -/* ------------- Global malloc_state and malloc_params ------------------- */ - -/* - malloc_params holds global properties, including those that can be - dynamically set using mallopt. There is a single instance, mparams, - initialized in init_mparams. Note that the non-zeroness of "magic" - also serves as an initialization flag. -*/ - -struct malloc_params -{ - volatile size_t magic; - size_t page_size; - size_t granularity; - size_t mmap_threshold; - size_t trim_threshold; - flag_t default_mflags; -}; - -static struct malloc_params mparams; - -/* Ensure mparams initialized */ -#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams()) - -#if !ONLY_MSPACES - -/* The global malloc_state used for all non-"mspace" calls */ -static struct malloc_state _gm_; -#define gm (&_gm_) -#define is_global(M) ((M) == &_gm_) - -#endif /* !ONLY_MSPACES */ - -#define is_initialized(M) ((M)->top != 0) - -/* -------------------------- system alloc setup ------------------------- */ - -/* Operations on mflags */ - -#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) -#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) -#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) - -#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) -#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) -#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) - -#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) -#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) - -#define set_lock(M, L) \ - ((M)->mflags = (L) ? \ - ((M)->mflags | USE_LOCK_BIT) : \ - ((M)->mflags & ~USE_LOCK_BIT)) - -/* page-align a size */ -#define page_align(S) \ - (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE)) - -/* granularity-align a size */ -#define granularity_align(S) \ - (((S) + (mparams.granularity - SIZE_T_ONE)) \ - & ~(mparams.granularity - SIZE_T_ONE)) - - -/* For mmap, use granularity alignment on windows, else page-align */ -#ifdef WIN32 -#define mmap_align(S) granularity_align(S) -#else -#define mmap_align(S) page_align(S) -#endif - -/* For sys_alloc, enough padding to ensure can malloc request on success */ -#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT) - -#define is_page_aligned(S) \ - (((size_t)(S) &(mparams.page_size - SIZE_T_ONE)) == 0) -#define is_granularity_aligned(S) \ - (((size_t)(S) &(mparams.granularity - SIZE_T_ONE)) == 0) - -/* True if segment S holds address A */ -#define segment_holds(S, A) \ - ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) - -/* Return segment holding given address */ -static msegmentptr segment_holding(mstate m, char* addr) -{ - msegmentptr sp = &m->seg; - for (;; ) - { - if (addr >= sp->base && addr < sp->base + sp->size) - { - return sp; - } - if ((sp = sp->next) == 0) - { - return 0; - } - } -} - -/* Return true if segment contains a segment link */ -static int has_segment_link(mstate m, msegmentptr ss) -{ - msegmentptr sp = &m->seg; - for (;; ) - { - if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) - { - return 1; - } - if ((sp = sp->next) == 0) - { - return 0; - } - } -} - -#ifndef MORECORE_CANNOT_TRIM -#define should_trim(M, s) ((s) > (M)->trim_check) -#else /* MORECORE_CANNOT_TRIM */ -#define should_trim(M, s) (0) -#endif /* MORECORE_CANNOT_TRIM */ - -/* - TOP_FOOT_SIZE is padding at the end of a segment, including space - that may be needed to place segment records and fenceposts when new - noncontiguous segments are added. -*/ -#define TOP_FOOT_SIZE \ - (align_offset(chunk2mem(0)) + pad_request(sizeof(struct malloc_segment)) + MIN_CHUNK_SIZE) - - -/* ------------------------------- Hooks -------------------------------- */ - -/* - PREACTION should be defined to return 0 on success, and nonzero on - failure. If you are not using locking, you can redefine these to do - anything you like. -*/ - -#if USE_LOCKS - -#define PREACTION(M) ((use_lock(M)) ? ACQUIRE_LOCK(&(M)->mutex) : 0) -#define POSTACTION(M) { if (use_lock(M)) {RELEASE_LOCK(&(M)->mutex); } \ -} -#else /* USE_LOCKS */ - -#ifndef PREACTION -#define PREACTION(M) (0) -#endif /* PREACTION */ - -#ifndef POSTACTION -#define POSTACTION(M) -#endif /* POSTACTION */ - -#endif /* USE_LOCKS */ - -/* - CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. - USAGE_ERROR_ACTION is triggered on detected bad frees and - reallocs. The argument p is an address that might have triggered the - fault. It is ignored by the two predefined actions, but might be - useful in custom actions that try to help diagnose errors. -*/ - -#if PROCEED_ON_ERROR - -/* A count of the number of corruption errors causing resets */ -int malloc_corruption_error_count; - -/* default corruption action */ -static void reset_on_error(mstate m); - -#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) -#define USAGE_ERROR_ACTION(m, p) - -#else /* PROCEED_ON_ERROR */ - -#ifndef CORRUPTION_ERROR_ACTION -#define CORRUPTION_ERROR_ACTION(m) ABORT -#endif /* CORRUPTION_ERROR_ACTION */ - -#ifndef USAGE_ERROR_ACTION -#define USAGE_ERROR_ACTION(m, p) ABORT -#endif /* USAGE_ERROR_ACTION */ - -#endif /* PROCEED_ON_ERROR */ - -/* -------------------------- Debugging setup ---------------------------- */ - -#if !DEBUG - -#define check_free_chunk(M, P) -#define check_inuse_chunk(M, P) -#define check_malloced_chunk(M, P, N) -#define check_mmapped_chunk(M, P) -#define check_malloc_state(M) -#define check_top_chunk(M, P) - -#else /* DEBUG */ -#define check_free_chunk(M, P) do_check_free_chunk(M, P) -#define check_inuse_chunk(M, P) do_check_inuse_chunk(M, P) -#define check_top_chunk(M, P) do_check_top_chunk(M, P) -#define check_malloced_chunk(M, P, N) do_check_malloced_chunk(M, P, N) -#define check_mmapped_chunk(M, P) do_check_mmapped_chunk(M, P) -#define check_malloc_state(M) do_check_malloc_state(M) - -static void do_check_any_chunk(mstate m, mchunkptr p); -static void do_check_top_chunk(mstate m, mchunkptr p); -static void do_check_mmapped_chunk(mstate m, mchunkptr p); -static void do_check_inuse_chunk(mstate m, mchunkptr p); -static void do_check_free_chunk(mstate m, mchunkptr p); -static void do_check_malloced_chunk(mstate m, void* mem, size_t s); -static void do_check_tree(mstate m, tchunkptr t); -static void do_check_treebin(mstate m, bindex_t i); -static void do_check_smallbin(mstate m, bindex_t i); -static void do_check_malloc_state(mstate m); -static int bin_find(mstate m, mchunkptr x); -static size_t traverse_and_check(mstate m); -#endif /* DEBUG */ - -/* ---------------------------- Indexing Bins ---------------------------- */ - -#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) -#define small_index(s) ((s) >> SMALLBIN_SHIFT) -#define small_index2size(i) ((i) << SMALLBIN_SHIFT) -#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) - -/* addressing by index. See above about smallbin repositioning */ -#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i) << 1]))) -#define treebin_at(M, i) (&((M)->treebins[i])) - -/* assign tree index for size S to variable I. Use x86 asm if possible */ -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -#define compute_tree_index(S, I) \ - { \ - unsigned int X = S >> TREEBIN_SHIFT; \ - if (X == 0) { \ - I = 0; } \ - else if (X > 0xFFFF) { \ - I = NTREEBINS - 1; } \ - else { \ - unsigned int K; \ - __asm__("bsrl\t%1, %0\n\t" : "=r" (K) : "g" (X)); \ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT - 1)) & 1))); \ - } \ - } - -#elif defined (__INTEL_COMPILER) -#define compute_tree_index(S, I) \ - { \ - size_t X = S >> TREEBIN_SHIFT; \ - if (X == 0) { \ - I = 0; } \ - else if (X > 0xFFFF) { \ - I = NTREEBINS - 1; } \ - else { \ - unsigned int K = _bit_scan_reverse (X); \ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT - 1)) & 1))); \ - } \ - } - -#elif TRAIT_HAS_BITSCANREVERSE -#define compute_tree_index(S, I) \ - { \ - size_t X = S >> TREEBIN_SHIFT; \ - if (X == 0) { \ - I = 0; } \ - else if (X > 0xFFFF) { \ - I = NTREEBINS - 1; } \ - else { \ - unsigned int K; \ - _BitScanReverse((DWORD*) &K, X); \ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT - 1)) & 1))); \ - } \ - } - -#else /* GNUC */ -#define compute_tree_index(S, I) \ - { \ - size_t X = S >> TREEBIN_SHIFT; \ - if (X == 0) { \ - I = 0; } \ - else if (X > 0xFFFF) { \ - I = NTREEBINS - 1; } \ - else { \ - unsigned int Y = (unsigned int)X; \ - unsigned int N = ((Y - 0x100) >> 16) & 8; \ - unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4; \ - N += K; \ - N += K = (((Y <<= K) - 0x4000) >> 16) & 2; \ - K = 14 - N + ((Y <<= K) >> 15); \ - I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT - 1)) & 1)); \ - } \ - } -#endif /* GNUC */ - -/* Bit representing maximum resolved size in a treebin at i */ -#define bit_for_tree_index(i) \ - (i == NTREEBINS - 1) ? (SIZE_T_BITSIZE - 1) : (((i) >> 1) + TREEBIN_SHIFT - 2) - -/* Shift placing maximum resolved bit in a treebin at i as sign bit */ -#define leftshift_for_tree_index(i) \ - ((i == NTREEBINS - 1) ? 0 : \ - ((SIZE_T_BITSIZE - SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) - -/* The size of the smallest chunk held in bin with index i */ -#define minsize_for_tree_index(i) \ - ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ - (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) - - -/* ------------------------ Operations on bin maps ----------------------- */ - -/* bit corresponding to given index */ -#define idx2bit(i) ((binmap_t)(1) << (i)) - -/* Mark/Clear bits with given index */ -#define mark_smallmap(M, i) ((M)->smallmap |= idx2bit(i)) -#define clear_smallmap(M, i) ((M)->smallmap &= ~idx2bit(i)) -#define smallmap_is_marked(M, i) ((M)->smallmap & idx2bit(i)) - -#define mark_treemap(M, i) ((M)->treemap |= idx2bit(i)) -#define clear_treemap(M, i) ((M)->treemap &= ~idx2bit(i)) -#define treemap_is_marked(M, i) ((M)->treemap & idx2bit(i)) - -/* isolate the least set bit of a bitmap */ -#define least_bit(x) ((x) & - (x)) - -/* mask with all bits to left of least bit of x on */ -#define left_bits(x) ((x << 1) | -(x << 1)) - -/* mask with all bits to left of or equal to least bit of x on */ -#define same_or_left_bits(x) ((x) | -(x)) - -/* index corresponding to given bit. Use x86 asm if possible */ - -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -#define compute_bit2idx(X, I) \ - { \ - unsigned int J; \ - __asm__("bsfl\t%1, %0\n\t" : "=r" (J) : "g" (X)); \ - I = (bindex_t)J; \ - } - -#elif defined (__INTEL_COMPILER) -#define compute_bit2idx(X, I) \ - { \ - unsigned int J; \ - J = _bit_scan_forward (X); \ - I = (bindex_t)J; \ - } - -#elif TRAIT_HAS_BITSCANFORWARD -#define compute_bit2idx(X, I) \ - { \ - unsigned int J; \ - _BitScanForward((DWORD*) &J, X); \ - I = (bindex_t)J; \ - } - -#elif USE_BUILTIN_FFS -#define compute_bit2idx(X, I) I = ffs(X) - 1 - -#else -#define compute_bit2idx(X, I) \ - { \ - unsigned int Y = X - 1; \ - unsigned int K = Y >> (16 - 4) & 16; \ - unsigned int N = K; Y >>= K; \ - N += K = Y >> (8 - 3) & 8; Y >>= K; \ - N += K = Y >> (4 - 2) & 4; Y >>= K; \ - N += K = Y >> (2 - 1) & 2; Y >>= K; \ - N += K = Y >> (1 - 0) & 1; Y >>= K; \ - I = (bindex_t)(N + Y); \ - } -#endif /* GNUC */ - - -/* ----------------------- Runtime Check Support ------------------------- */ - -/* - For security, the main invariant is that malloc/free/etc never - writes to a static address other than malloc_state, unless static - malloc_state itself has been corrupted, which cannot occur via - malloc (because of these checks). In essence this means that we - believe all pointers, sizes, maps etc held in malloc_state, but - check all of those linked or offsetted from other embedded data - structures. These checks are interspersed with main code in a way - that tends to minimize their run-time cost. - - When FOOTERS is defined, in addition to range checking, we also - verify footer fields of inuse chunks, which can be used guarantee - that the mstate controlling malloc/free is intact. This is a - streamlined version of the approach described by William Robertson - et al in "Run-time Detection of Heap-based Overflows" LISA'03 - http://www.usenix.org/events/lisa03/tech/robertson.html The footer - of an inuse chunk holds the xor of its mstate and a random seed, - that is checked upon calls to free() and realloc(). This is - (probablistically) unguessable from outside the program, but can be - computed by any code successfully malloc'ing any chunk, so does not - itself provide protection against code that has already broken - security through some other means. Unlike Robertson et al, we - always dynamically check addresses of all offset chunks (previous, - next, etc). This turns out to be cheaper than relying on hashes. -*/ - -#if !INSECURE -/* Check if address a is at least as high as any from MORECORE or MMAP */ -#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) -/* Check if address of next chunk n is higher than base chunk p */ -#define ok_next(p, n) ((char*)(p) < (char*)(n)) -/* Check if p has inuse status */ -#define ok_inuse(p) is_inuse(p) -/* Check if p has its pinuse bit on */ -#define ok_pinuse(p) pinuse(p) - -#else /* !INSECURE */ -#define ok_address(M, a) (1) -#define ok_next(b, n) (1) -#define ok_inuse(p) (1) -#define ok_pinuse(p) (1) -#endif /* !INSECURE */ - -#if (FOOTERS && !INSECURE) -/* Check if (alleged) mstate m has expected magic field */ -#define ok_magic(M) ((M)->magic == mparams.magic) -#else /* (FOOTERS && !INSECURE) */ -#define ok_magic(M) (1) -#endif /* (FOOTERS && !INSECURE) */ - - -/* In gcc, use __builtin_expect to minimize impact of checks */ -#if !INSECURE -#if defined(__GNUC__) && __GNUC__ >= 3 -#define RTCHECK(e) __builtin_expect(e, 1) -#else /* GNUC */ -#define RTCHECK(e) (e) -#endif /* GNUC */ -#else /* !INSECURE */ -#define RTCHECK(e) (1) -#endif /* !INSECURE */ - -/* macros to set up inuse chunks with or without footers */ - -#if !FOOTERS - -#define mark_inuse_foot(M, p, s) - -/* Macros for setting head/foot of non-mmapped chunks */ - -/* Set cinuse bit and pinuse bit of next chunk */ -#define set_inuse(M, p, s) \ - ((p)->head = (((p)->head & PINUSE_BIT) | s | CINUSE_BIT), \ - ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) - -/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ -#define set_inuse_and_pinuse(M, p, s) \ - ((p)->head = (s | PINUSE_BIT | CINUSE_BIT), \ - ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) - -/* Set size, cinuse and pinuse bit of this chunk */ -#define set_size_and_pinuse_of_inuse_chunk(M, p, s) \ - ((p)->head = (s | PINUSE_BIT | CINUSE_BIT)) - -#else /* FOOTERS */ - -/* Set foot of inuse chunk to be xor of mstate and seed */ -#define mark_inuse_foot(M, p, s) \ - (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) - -#define get_mstate_for(p) \ - ((mstate)(((mchunkptr)((char*)(p) + \ - (chunksize(p))))->prev_foot ^ mparams.magic)) - -#define set_inuse(M, p, s) \ - ((p)->head = (((p)->head & PINUSE_BIT) | s | CINUSE_BIT), \ - (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ - mark_inuse_foot(M, p, s)) - -#define set_inuse_and_pinuse(M, p, s) \ - ((p)->head = (s | PINUSE_BIT | CINUSE_BIT), \ - (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ - mark_inuse_foot(M, p, s)) - -#define set_size_and_pinuse_of_inuse_chunk(M, p, s) \ - ((p)->head = (s | PINUSE_BIT | CINUSE_BIT), \ - mark_inuse_foot(M, p, s)) - -#endif /* !FOOTERS */ - -/* ---------------------------- setting mparams -------------------------- */ - -/* Initialize mparams */ -int init_mparams(void) -{ -#ifdef NEED_GLOBAL_LOCK_INIT - if (malloc_global_mutex_status <= 0) - { - init_malloc_global_mutex(); - } -#endif - - ACQUIRE_MALLOC_GLOBAL_LOCK(); - if (mparams.magic == 0) - { - size_t magic; - size_t psize; - size_t gsize; - -#if TRAIT_HAS_GETSYSTEMINFO - { - SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - psize = system_info.dwPageSize; - gsize = ((DEFAULT_GRANULARITY != 0) ? - DEFAULT_GRANULARITY : system_info.dwAllocationGranularity); - } -#else - psize = malloc_getpagesize; - gsize = ((DEFAULT_GRANULARITY != 0) ? DEFAULT_GRANULARITY : psize); -#endif //#if TRAIT_HAS_GETSYSTEMINFO - - /* Sanity-check configuration: - size_t must be unsigned and as wide as pointer type. - ints must be at least 4 bytes. - alignment must be at least 8. - Alignment, min chunk size, and page size must all be powers of 2. - */ - if ((sizeof(size_t) != sizeof(char*)) || - (MAX_SIZE_T < MIN_CHUNK_SIZE) || - (sizeof(int) < 4) || - (MALLOC_ALIGNMENT < (size_t)8U) || - ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT - SIZE_T_ONE)) != 0) || - ((MCHUNK_SIZE & (MCHUNK_SIZE - SIZE_T_ONE)) != 0) || - ((gsize & (gsize - SIZE_T_ONE)) != 0) || - ((psize & (psize - SIZE_T_ONE)) != 0)) - { - ABORT; - } - - mparams.granularity = gsize; - mparams.page_size = psize; - mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; - mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; -#if MORECORE_CONTIGUOUS - mparams.default_mflags = USE_LOCK_BIT | USE_MMAP_BIT; -#else /* MORECORE_CONTIGUOUS */ - mparams.default_mflags = USE_LOCK_BIT | USE_MMAP_BIT | USE_NONCONTIGUOUS_BIT; -#endif /* MORECORE_CONTIGUOUS */ - -#if !ONLY_MSPACES - /* Set up lock for main malloc area */ - gm->mflags = mparams.default_mflags; - INITIAL_LOCK(&gm->mutex); -#endif - - { -#if USE_DEV_RANDOM - int fd; - unsigned char buf[sizeof(size_t)]; - /* Try to use /dev/urandom, else fall back on using time */ - if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && - read(fd, buf, sizeof(buf)) == sizeof(buf)) - { - magic = *((size_t*) buf); - close(fd); - } - else -#endif /* USE_DEV_RANDOM */ -#if TRAIT_USE_QUERYPERFORMANCECOUNTER - { - // GetTickCount not available on Metro style apps - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - magic = (size_t)(li.QuadPart ^ (size_t)0x55555555U); - } -#elif defined(WIN32) - magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U); -#else - magic = (size_t)(time(0) ^ (size_t)0x55555555U); -#endif - magic |= (size_t)8U; /* ensure nonzero */ - magic &= ~(size_t)7U; /* improve chances of fault for bad values */ - mparams.magic = magic; - } - } - - RELEASE_MALLOC_GLOBAL_LOCK(); - return 1; -} - -/* support for mallopt */ -static int change_mparam(int param_number, int value) -{ - size_t val; - ensure_initialization(); - val = (value == -1) ? MAX_SIZE_T : (size_t)value; - switch (param_number) - { - case M_TRIM_THRESHOLD: - mparams.trim_threshold = val; - return 1; - case M_GRANULARITY: - if (val >= mparams.page_size && ((val & (val - 1)) == 0)) - { - mparams.granularity = val; - return 1; - } - else - { - return 0; - } - case M_MMAP_THRESHOLD: - mparams.mmap_threshold = val; - return 1; - default: - return 0; - } -} - -#if DEBUG -/* ------------------------- Debugging Support --------------------------- */ - -/* Check properties of any chunk, whether free, inuse, mmapped etc */ -static void do_check_any_chunk(mstate m, mchunkptr p) -{ - assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); - assert(ok_address(m, p)); -} - -/* Check properties of top chunk */ -static void do_check_top_chunk(mstate m, mchunkptr p) -{ - msegmentptr sp = segment_holding(m, (char*)p); - size_t sz = p->head & ~INUSE_BITS;/* third-lowest bit can be set! */ - assert(sp != 0); - assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); - assert(ok_address(m, p)); - assert(sz == m->topsize); - assert(sz > 0); - assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); - assert(pinuse(p)); - assert(!pinuse(chunk_plus_offset(p, sz))); -} - -/* Check properties of (inuse) mmapped chunks */ -static void do_check_mmapped_chunk(mstate m, mchunkptr p) -{ - size_t sz = chunksize(p); - size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD); - assert(is_mmapped(p)); - assert(use_mmap(m)); - assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); - assert(ok_address(m, p)); - assert(!is_small(sz)); - assert((len & (mparams.page_size - SIZE_T_ONE)) == 0); - assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); - assert(chunk_plus_offset(p, sz + SIZE_T_SIZE)->head == 0); -} - -/* Check properties of inuse chunks */ -static void do_check_inuse_chunk(mstate m, mchunkptr p) -{ - do_check_any_chunk(m, p); - assert(is_inuse(p)); - assert(next_pinuse(p)); - /* If not pinuse and not mmapped, previous chunk has OK offset */ - assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); - if (is_mmapped(p)) - { - do_check_mmapped_chunk(m, p); - } -} - -/* Check properties of free chunks */ -static void do_check_free_chunk(mstate m, mchunkptr p) -{ - size_t sz = chunksize(p); - mchunkptr next = chunk_plus_offset(p, sz); - do_check_any_chunk(m, p); - assert(!is_inuse(p)); - assert(!next_pinuse(p)); - assert (!is_mmapped(p)); - if (p != m->dv && p != m->top) - { - if (sz >= MIN_CHUNK_SIZE) - { - assert((sz & CHUNK_ALIGN_MASK) == 0); - assert(is_aligned(chunk2mem(p))); - assert(next->prev_foot == sz); - assert(pinuse(p)); - assert (next == m->top || is_inuse(next)); - assert(p->fd->bk == p); - assert(p->bk->fd == p); - } - else /* markers are always of size SIZE_T_SIZE */ - { - assert(sz == SIZE_T_SIZE); - } - } -} - -/* Check properties of malloced chunks at the point they are malloced */ -static void do_check_malloced_chunk(mstate m, void* mem, size_t s) -{ - if (mem != 0) - { - mchunkptr p = mem2chunk(mem); - size_t sz = p->head & ~INUSE_BITS; - do_check_inuse_chunk(m, p); - assert((sz & CHUNK_ALIGN_MASK) == 0); - assert(sz >= MIN_CHUNK_SIZE); - assert(sz >= s); - /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ - assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); - } -} - -/* Check a tree and its subtrees. */ -static void do_check_tree(mstate m, tchunkptr t) -{ - tchunkptr head = 0; - tchunkptr u = t; - bindex_t tindex = t->index; - size_t tsize = chunksize(t); - bindex_t idx; - compute_tree_index(tsize, idx); - assert(tindex == idx); - assert(tsize >= MIN_LARGE_SIZE); - assert(tsize >= minsize_for_tree_index(idx)); - assert((idx == NTREEBINS - 1) || (tsize < minsize_for_tree_index((idx + 1)))); - - do /* traverse through chain of same-sized nodes */ - { - do_check_any_chunk(m, ((mchunkptr)u)); - assert(u->index == tindex); - assert(chunksize(u) == tsize); - assert(!is_inuse(u)); - assert(!next_pinuse(u)); - assert(u->fd->bk == u); - assert(u->bk->fd == u); - if (u->parent == 0) - { - assert(u->child[0] == 0); - assert(u->child[1] == 0); - } - else - { - assert(head == 0); /* only one node on chain has parent */ - head = u; - assert(u->parent != u); - assert (u->parent->child[0] == u || - u->parent->child[1] == u || - *((tbinptr*)(u->parent)) == u); - if (u->child[0] != 0) - { - assert(u->child[0]->parent == u); - assert(u->child[0] != u); - do_check_tree(m, u->child[0]); - } - if (u->child[1] != 0) - { - assert(u->child[1]->parent == u); - assert(u->child[1] != u); - do_check_tree(m, u->child[1]); - } - if (u->child[0] != 0 && u->child[1] != 0) - { - assert(chunksize(u->child[0]) < chunksize(u->child[1])); - } - } - u = u->fd; - } while (u != t); - assert(head != 0); -} - -/* Check all the chunks in a treebin. */ -static void do_check_treebin(mstate m, bindex_t i) -{ - tbinptr* tb = treebin_at(m, i); - tchunkptr t = *tb; - int empty = (m->treemap & (1U << i)) == 0; - if (t == 0) - { - assert(empty); - } - if (!empty) - { - do_check_tree(m, t); - } -} - -/* Check all the chunks in a smallbin. */ -static void do_check_smallbin(mstate m, bindex_t i) -{ - sbinptr b = smallbin_at(m, i); - mchunkptr p = b->bk; - unsigned int empty = (m->smallmap & (1U << i)) == 0; - if (p == b) - { - assert(empty); - } - if (!empty) - { - for (; p != b; p = p->bk) - { - size_t size = chunksize(p); - mchunkptr q; - /* each chunk claims to be free */ - do_check_free_chunk(m, p); - /* chunk belongs in bin */ - assert(small_index(size) == i); - assert(p->bk == b || chunksize(p->bk) == chunksize(p)); - /* chunk is followed by an inuse chunk */ - q = next_chunk(p); - if (q->head != FENCEPOST_HEAD) - { - do_check_inuse_chunk(m, q); - } - } - } -} - -/* Find x in a bin. Used in other check functions. */ -static int bin_find(mstate m, mchunkptr x) -{ - size_t size = chunksize(x); - if (is_small(size)) - { - bindex_t sidx = small_index(size); - sbinptr b = smallbin_at(m, sidx); - if (smallmap_is_marked(m, sidx)) - { - mchunkptr p = b; - do - { - if (p == x) - { - return 1; - } - } while ((p = p->fd) != b); - } - } - else - { - bindex_t tidx; - compute_tree_index(size, tidx); - if (treemap_is_marked(m, tidx)) - { - tchunkptr t = *treebin_at(m, tidx); - size_t sizebits = size << leftshift_for_tree_index(tidx); - while (t != 0 && chunksize(t) != size) - { - t = t->child[(sizebits >> (SIZE_T_BITSIZE - SIZE_T_ONE)) & 1]; - sizebits <<= 1; - } - if (t != 0) - { - tchunkptr u = t; - do - { - if (u == (tchunkptr)x) - { - return 1; - } - } while ((u = u->fd) != t); - } - } - } - return 0; -} - -/* Traverse each chunk and check it; return total */ -static size_t traverse_and_check(mstate m) -{ - size_t sum = 0; - if (is_initialized(m)) - { - msegmentptr s = &m->seg; - sum += m->topsize + TOP_FOOT_SIZE; - while (s != 0) - { - mchunkptr q = align_as_chunk(s->base); - mchunkptr lastq = 0; - assert(pinuse(q)); - while (segment_holds(s, q) && - q != m->top && q->head != FENCEPOST_HEAD) - { - sum += chunksize(q); - if (is_inuse(q)) - { - assert(!bin_find(m, q)); - do_check_inuse_chunk(m, q); - } - else - { - assert(q == m->dv || bin_find(m, q)); - assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */ - do_check_free_chunk(m, q); - } - lastq = q; - q = next_chunk(q); - } - s = s->next; - } - } - return sum; -} - -/* Check all properties of malloc_state. */ -static void do_check_malloc_state(mstate m) -{ - bindex_t i; - size_t total; - /* check bins */ - for (i = 0; i < NSMALLBINS; ++i) - { - do_check_smallbin(m, i); - } - for (i = 0; i < NTREEBINS; ++i) - { - do_check_treebin(m, i); - } - - if (m->dvsize != 0) /* check dv chunk */ - { - do_check_any_chunk(m, m->dv); - assert(m->dvsize == chunksize(m->dv)); - assert(m->dvsize >= MIN_CHUNK_SIZE); - assert(bin_find(m, m->dv) == 0); - } - - if (m->top != 0) /* check top chunk */ - { - do_check_top_chunk(m, m->top); - /*assert(m->topsize == chunksize(m->top)); redundant */ - assert(m->topsize > 0); - assert(bin_find(m, m->top) == 0); - } - - total = traverse_and_check(m); - assert(total <= m->footprint); - assert(m->footprint <= m->max_footprint); -} -#endif /* DEBUG */ - -/* ----------------------------- statistics ------------------------------ */ - -#if !NO_MALLINFO -static struct mallinfo internal_mallinfo(mstate m) -{ - struct mallinfo nm = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - ensure_initialization(); - if (!PREACTION(m)) - { - check_malloc_state(m); - if (is_initialized(m)) - { - size_t nfree = SIZE_T_ONE; /* top always free */ - size_t mfree = m->topsize + TOP_FOOT_SIZE; - size_t sum = mfree; - msegmentptr s = &m->seg; - while (s != 0) - { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && - q != m->top && q->head != FENCEPOST_HEAD) - { - size_t sz = chunksize(q); - sum += sz; - if (!is_inuse(q)) - { - mfree += sz; - ++nfree; - } - q = next_chunk(q); - } - s = s->next; - } - - nm.arena = sum; - nm.ordblks = nfree; - nm.hblkhd = m->footprint - sum; - nm.usmblks = m->max_footprint; - nm.uordblks = m->footprint - mfree; - nm.fordblks = mfree; - nm.keepcost = m->topsize; - } - - POSTACTION(m); - } - return nm; -} -#endif /* !NO_MALLINFO */ - -static void internal_malloc_stats(mstate m) -{ - ensure_initialization(); - if (!PREACTION(m)) - { - size_t maxfp = 0; - size_t fp = 0; - size_t used = 0; - check_malloc_state(m); - if (is_initialized(m)) - { - msegmentptr s = &m->seg; - maxfp = m->max_footprint; - fp = m->footprint; - used = fp - (m->topsize + TOP_FOOT_SIZE); - - while (s != 0) - { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && - q != m->top && q->head != FENCEPOST_HEAD) - { - if (!is_inuse(q)) - { - used -= chunksize(q); - } - q = next_chunk(q); - } - s = s->next; - } - } - - fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); - fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); - fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); - - POSTACTION(m); - } -} - -static void internal_malloc_stats_ret(mstate m, size_t* sysOut, size_t* maxSysOut, size_t* usedOut) -{ - ensure_initialization(); - if (!PREACTION(m)) - { - size_t maxfp = 0; - size_t fp = 0; - size_t used = 0; - check_malloc_state(m); - if (is_initialized(m)) - { - msegmentptr s = &m->seg; - maxfp = m->max_footprint; - fp = m->footprint; - used = fp - (m->topsize + TOP_FOOT_SIZE); - - while (s != 0) - { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && - q != m->top && q->head != FENCEPOST_HEAD) - { - if (!is_inuse(q)) - { - used -= chunksize(q); - } - q = next_chunk(q); - } - s = s->next; - } - } - - (*sysOut) = fp; - (*maxSysOut) = maxfp; - (*usedOut) = used; - - POSTACTION(m); - } -} - -/* ----------------------- Operations on smallbins ----------------------- */ - -/* - Various forms of linking and unlinking are defined as macros. Even - the ones for trees, which are very long but have very short typical - paths. This is ugly but reduces reliance on inlining support of - compilers. -*/ - -/* Link a free chunk into a smallbin */ -#define insert_small_chunk(M, P, S) { \ - bindex_t I = small_index(S); \ - mchunkptr B = smallbin_at(M, I); \ - mchunkptr F = B; \ - assert(S >= MIN_CHUNK_SIZE); \ - if (!smallmap_is_marked(M, I)) { \ - mark_smallmap(M, I); } \ - else if (RTCHECK(ok_address(M, B->fd))) { \ - F = B->fd; } \ - else { \ - CORRUPTION_ERROR_ACTION(M); \ - } \ - B->fd = P; \ - F->bk = P; \ - P->fd = F; \ - P->bk = B; \ -} - -/* Unlink a chunk from a smallbin */ -#define unlink_small_chunk(M, P, S) { \ - mchunkptr F = P->fd; \ - mchunkptr B = P->bk; \ - bindex_t I = small_index(S); \ - assert(P != B); \ - assert(P != F); \ - assert(chunksize(P) == small_index2size(I)); \ - if (F == B) { \ - clear_smallmap(M, I); } \ - else if (RTCHECK((F == smallbin_at(M, I) || ok_address(M, F)) && \ - (B == smallbin_at(M, I) || ok_address(M, B)))) { \ - F->bk = B; \ - B->fd = F; \ - } \ - else { \ - CORRUPTION_ERROR_ACTION(M); \ - } \ -} - -/* Unlink the first chunk from a smallbin */ -#define unlink_first_small_chunk(M, B, P, I) { \ - mchunkptr F = P->fd; \ - assert(P != B); \ - assert(P != F); \ - assert(chunksize(P) == small_index2size(I)); \ - if (B == F) { \ - clear_smallmap(M, I); } \ - else if (RTCHECK(ok_address(M, F))) { \ - B->fd = F; \ - F->bk = B; \ - } \ - else { \ - CORRUPTION_ERROR_ACTION(M); \ - } \ -} - - - -/* Replace dv node, binning the old one */ -/* Used only when dvsize known to be small */ -#define replace_dv(M, P, S) { \ - size_t DVS = M->dvsize; \ - if (DVS != 0) { \ - mchunkptr DV = M->dv; \ - assert(is_small(DVS)); \ - insert_small_chunk(M, DV, DVS); \ - } \ - M->dvsize = S; \ - M->dv = P; \ -} - -/* ------------------------- Operations on trees ------------------------- */ - -/* Insert chunk into tree */ -#define insert_large_chunk(M, X, S) { \ - tbinptr* H; \ - bindex_t I; \ - compute_tree_index(S, I); \ - H = treebin_at(M, I); \ - X->index = I; \ - X->child[0] = X->child[1] = 0; \ - if (!treemap_is_marked(M, I)) { \ - mark_treemap(M, I); \ - * H = X; \ - X->parent = (tchunkptr)H; \ - X->fd = X->bk = X; \ - } \ - else { \ - tchunkptr T = * H; \ - size_t K = S << leftshift_for_tree_index(I); \ - for (;; ) { \ - if (chunksize(T) != S) { \ - tchunkptr* C = & (T->child[(K >> (SIZE_T_BITSIZE - SIZE_T_ONE))& 1]); \ - K <<= 1; \ - if (* C != 0) { \ - T = * C; } \ - else if (RTCHECK(ok_address(M, C))) { \ - * C = X; \ - X->parent = T; \ - X->fd = X->bk = X; \ - break; \ - } \ - else { \ - CORRUPTION_ERROR_ACTION(M); \ - break; \ - } \ - } \ - else { \ - tchunkptr F = T->fd; \ - if (RTCHECK(ok_address(M, T) && ok_address(M, F))) { \ - T->fd = F->bk = X; \ - X->fd = F; \ - X->bk = T; \ - X->parent = 0; \ - break; \ - } \ - else { \ - CORRUPTION_ERROR_ACTION(M); \ - break; \ - } \ - } \ - } \ - } \ -} - -/* - Unlink steps: - - 1. If x is a chained node, unlink it from its same-sized fd/bk links - and choose its bk node as its replacement. - 2. If x was the last node of its size, but not a leaf node, it must - be replaced with a leaf node (not merely one with an open left or - right), to make sure that lefts and rights of descendents - correspond properly to bit masks. We use the rightmost descendent - of x. We could use any other leaf, but this is easy to locate and - tends to counteract removal of leftmosts elsewhere, and so keeps - paths shorter than minimally guaranteed. This doesn't loop much - because on average a node in a tree is near the bottom. - 3. If x is the base of a chain (i.e., has parent links) relink - x's parent and children to x's replacement (or null if none). -*/ - -#define unlink_large_chunk(M, X) { \ - tchunkptr XP = X->parent; \ - tchunkptr R; \ - if (X->bk != X) { \ - tchunkptr F = X->fd; \ - R = X->bk; \ - if (RTCHECK(ok_address(M, F))) { \ - F->bk = R; \ - R->fd = F; \ - } \ - else { \ - CORRUPTION_ERROR_ACTION(M); \ - } \ - } \ - else { \ - tchunkptr* RP; \ - if (((R = *(RP = & (X->child[1]))) != 0) || \ - ((R = *(RP = & (X->child[0]))) != 0)) { \ - tchunkptr* CP; \ - while ((*(CP = & (R->child[1])) != 0) || \ - (*(CP = & (R->child[0])) != 0)) { \ - R = *(RP = CP); \ - } \ - if (RTCHECK(ok_address(M, RP))) { \ - * RP = 0; } \ - else { \ - CORRUPTION_ERROR_ACTION(M); \ - } \ - } \ - } \ - if (XP != 0) { \ - tbinptr* H = treebin_at(M, X->index); \ - if (X == * H) { \ - if ((* H = R) == 0) { \ - clear_treemap(M, X->index); } \ - } \ - else if (RTCHECK(ok_address(M, XP))) { \ - if (XP->child[0] == X) { \ - XP->child[0] = R; } \ - else{ \ - XP->child[1] = R; } \ - } \ - else{ \ - CORRUPTION_ERROR_ACTION(M); } \ - if (R != 0) { \ - if (RTCHECK(ok_address(M, R))) { \ - tchunkptr C0, C1; \ - R->parent = XP; \ - if ((C0 = X->child[0]) != 0) { \ - if (RTCHECK(ok_address(M, C0))) { \ - R->child[0] = C0; \ - C0->parent = R; \ - } \ - else{ \ - CORRUPTION_ERROR_ACTION(M); } \ - } \ - if ((C1 = X->child[1]) != 0) { \ - if (RTCHECK(ok_address(M, C1))) { \ - R->child[1] = C1; \ - C1->parent = R; \ - } \ - else{ \ - CORRUPTION_ERROR_ACTION(M); } \ - } \ - } \ - else{ \ - CORRUPTION_ERROR_ACTION(M); } \ - } \ - } \ -} - -/* Relays to large vs small bin operations */ - -#define insert_chunk(M, P, S) \ - if (is_small(S)) { insert_small_chunk(M, P, S) } \ - else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } - -#define unlink_chunk(M, P, S) \ - if (is_small(S)) { unlink_small_chunk(M, P, S) } \ - else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } - - -/* Relays to internal calls to malloc/free from realloc, memalign etc */ - -#if ONLY_MSPACES -#define internal_malloc(m, b) mspace_malloc(m, b) -#define internal_free(m, mem) mspace_free(m, mem); -#else /* ONLY_MSPACES */ -#if MSPACES -#define internal_malloc(m, b) \ - (m == gm) ? dlmalloc(b) : mspace_malloc(m, b) -#define internal_free(m, mem) \ - if (m == gm) { dlfree(mem); } else{ mspace_free(m, mem); } -#else /* MSPACES */ -#define internal_malloc(m, b) dlmalloc(b) -#define internal_free(m, mem) dlfree(mem) -#endif /* MSPACES */ -#endif /* ONLY_MSPACES */ - -/* ----------------------- Direct-mmapping chunks ----------------------- */ - -/* - Directly mmapped chunks are set up with an offset to the start of - the mmapped region stored in the prev_foot field of the chunk. This - allows reconstruction of the required argument to MUNMAP when freed, - and also allows adjustment of the returned chunk to meet alignment - requirements (especially in memalign). -*/ - -/* Malloc using mmap */ -static void* mmap_alloc(mstate m, size_t nb) -{ - size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - if (mmsize > nb) /* Check for wrap around 0 */ - { - char* mm = (char*)((*m->mmap)(m->extp, mmsize)); - if (mm != CMFAIL) - { - size_t offset = align_offset(chunk2mem(mm)); - size_t psize = mmsize - offset - MMAP_FOOT_PAD; - mchunkptr p = (mchunkptr)(mm + offset); - p->prev_foot = offset; - p->head = psize; - mark_inuse_foot(m, p, psize); - chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(p, psize + SIZE_T_SIZE)->head = 0; - - if (m->least_addr == 0 || mm < m->least_addr) - { - m->least_addr = mm; - } - if ((m->footprint += mmsize) > m->max_footprint) - { - m->max_footprint = m->footprint; - } - assert(is_aligned(chunk2mem(p))); - check_mmapped_chunk(m, p); - return chunk2mem(p); - } - } - return 0; -} - -/* Realloc using mmap */ -static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) -{ - size_t oldsize = chunksize(oldp); - if (is_small(nb)) /* Can't shrink mmap regions below small size */ - { - return 0; - } - /* Keep old chunk if big enough but not too big */ - if (oldsize >= nb + SIZE_T_SIZE && - (oldsize - nb) <= (mparams.granularity << 1)) - { - return oldp; - } - else - { - size_t offset = oldp->prev_foot; - size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; - size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - char* cp = (char*)CALL_MREMAP((char*)oldp - offset, - oldmmsize, newmmsize, 1); - if (cp != CMFAIL) - { - mchunkptr newp = (mchunkptr)(cp + offset); - size_t psize = newmmsize - offset - MMAP_FOOT_PAD; - newp->head = psize; - mark_inuse_foot(m, newp, psize); - chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(newp, psize + SIZE_T_SIZE)->head = 0; - - if (cp < m->least_addr) - { - m->least_addr = cp; - } - if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) - { - m->max_footprint = m->footprint; - } - check_mmapped_chunk(m, newp); - return newp; - } - } - return 0; -} - -/* -------------------------- mspace management -------------------------- */ - -/* Initialize top chunk and its size */ -static void init_top(mstate m, mchunkptr p, size_t psize) -{ - /* Ensure alignment */ - size_t offset = align_offset(chunk2mem(p)); - p = (mchunkptr)((char*)p + offset); - psize -= offset; - - m->top = p; - m->topsize = psize; - p->head = psize | PINUSE_BIT; - /* set size of fake trailing chunk holding overhead space only once */ - chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; - m->trim_check = mparams.trim_threshold; /* reset on each update */ -} - -/* Initialize bins for a new mstate that is otherwise zeroed out */ -static void init_bins(mstate m) -{ - /* Establish circular links for smallbins */ - bindex_t i; - for (i = 0; i < NSMALLBINS; ++i) - { - sbinptr bin = smallbin_at(m, i); - bin->fd = bin->bk = bin; - } -} - -#if PROCEED_ON_ERROR - -/* default corruption action */ -static void reset_on_error(mstate m) -{ - int i; - ++malloc_corruption_error_count; - /* Reinitialize fields to forget about all memory */ - m->smallbins = m->treebins = 0; - m->dvsize = m->topsize = 0; - m->seg.base = 0; - m->seg.size = 0; - m->seg.next = 0; - m->top = m->dv = 0; - for (i = 0; i < NTREEBINS; ++i) - { - *treebin_at(m, i) = 0; - } - init_bins(m); -} -#endif /* PROCEED_ON_ERROR */ - -/* Allocate chunk and prepend remainder with chunk in successor base. */ -static void* prepend_alloc(mstate m, char* newbase, char* oldbase, - size_t nb) -{ - mchunkptr p = align_as_chunk(newbase); - mchunkptr oldfirst = align_as_chunk(oldbase); - size_t psize = (char*)oldfirst - (char*)p; - mchunkptr q = chunk_plus_offset(p, nb); - size_t qsize = psize - nb; - set_size_and_pinuse_of_inuse_chunk(m, p, nb); - - assert((char*)oldfirst > (char*)q); - assert(pinuse(oldfirst)); - assert(qsize >= MIN_CHUNK_SIZE); - - /* consolidate remainder with first chunk of old base */ - if (oldfirst == m->top) - { - size_t tsize = m->topsize += qsize; - m->top = q; - q->head = tsize | PINUSE_BIT; - check_top_chunk(m, q); - } - else if (oldfirst == m->dv) - { - size_t dsize = m->dvsize += qsize; - m->dv = q; - set_size_and_pinuse_of_free_chunk(q, dsize); - } - else - { - if (!is_inuse(oldfirst)) - { - size_t nsize = chunksize(oldfirst); - unlink_chunk(m, oldfirst, nsize); - oldfirst = chunk_plus_offset(oldfirst, nsize); - qsize += nsize; - } - set_free_with_pinuse(q, qsize, oldfirst); - insert_chunk(m, q, qsize); - check_free_chunk(m, q); - } - - check_malloced_chunk(m, chunk2mem(p), nb); - return chunk2mem(p); -} - -/* Add a segment to hold a new noncontiguous region */ -static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) -{ - /* Determine locations and sizes of segment, fenceposts, old top */ - char* old_top = (char*)m->top; - msegmentptr oldsp = segment_holding(m, old_top); - char* old_end = oldsp->base + oldsp->size; - size_t ssize = pad_request(sizeof(struct malloc_segment)); - char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - size_t offset = align_offset(chunk2mem(rawsp)); - char* asp = rawsp + offset; - char* csp = (asp < (old_top + MIN_CHUNK_SIZE)) ? old_top : asp; - mchunkptr sp = (mchunkptr)csp; - msegmentptr ss = (msegmentptr)(chunk2mem(sp)); - mchunkptr tnext = chunk_plus_offset(sp, ssize); - mchunkptr p = tnext; - int nfences = 0; - - /* reset top to new space */ - init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); - - /* Set up segment record */ - assert(is_aligned(ss)); - set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); - *ss = m->seg; /* Push current record */ - m->seg.base = tbase; - m->seg.size = tsize; - m->seg.sflags = mmapped; - m->seg.next = ss; - - /* Insert trailing fenceposts */ - for (;; ) - { - mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); - p->head = FENCEPOST_HEAD; - ++nfences; - if ((char*)(&(nextp->head)) < old_end) - { - p = nextp; - } - else - { - break; - } - } - assert(nfences >= 2); - - /* Insert the rest of old top into a bin as an ordinary free chunk */ - if (csp != old_top) - { - mchunkptr q = (mchunkptr)old_top; - size_t psize = csp - old_top; - mchunkptr tn = chunk_plus_offset(q, psize); - set_free_with_pinuse(q, psize, tn); - insert_chunk(m, q, psize); - } - - check_top_chunk(m, m->top); -} - -/* -------------------------- System allocation -------------------------- */ - -/* Get memory from system using MORECORE or MMAP */ -static void* sys_alloc(mstate m, size_t nb) -{ - char* tbase = CMFAIL; - size_t tsize = 0; - flag_t mmap_flag = 0; - - ensure_initialization(); - - /* Directly map large chunks, but only if already initialized */ - if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) - { - void* mem = mmap_alloc(m, nb); - if (mem != 0) - { - return mem; - } - } - - /* - Try getting memory in any of three ways (in most-preferred to - least-preferred order): - 1. A call to MORECORE that can normally contiguously extend memory. - (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or - or main space is mmapped or a previous contiguous call failed) - 2. A call to MMAP new space (disabled if not HAVE_MMAP). - Note that under the default settings, if MORECORE is unable to - fulfill a request, and HAVE_MMAP is true, then mmap is - used as a noncontiguous system allocator. This is a useful backup - strategy for systems with holes in address spaces -- in this case - sbrk cannot contiguously expand the heap, but mmap may be able to - find space. - 3. A call to MORECORE that cannot usually contiguously extend memory. - (disabled if not HAVE_MORECORE) - - In all cases, we need to request enough bytes from system to ensure - we can malloc nb bytes upon success, so pad with enough space for - top_foot, plus alignment-pad to make sure we don't lose bytes if - not on boundary, and round this up to a granularity unit. - */ - - if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) - { - char* br = CMFAIL; - msegmentptr ss = (m->top == 0) ? 0 : segment_holding(m, (char*)m->top); - size_t asize = 0; - ACQUIRE_MALLOC_GLOBAL_LOCK(); - - if (ss == 0) /* First time through or recovery */ - { - char* base = (char*)CALL_MORECORE(0); - if (base != CMFAIL) - { - asize = granularity_align(nb + SYS_ALLOC_PADDING); - /* Adjust to end on a page boundary */ - if (!is_page_aligned(base)) - { - asize += (page_align((size_t)base) - (size_t)base); - } - /* Can't call MORECORE if size is negative when treated as signed */ - if (asize < HALF_MAX_SIZE_T && - (br = (char*)(CALL_MORECORE(asize))) == base) - { - tbase = base; - tsize = asize; - } - } - } - else - { - /* Subtract out existing available top space from MORECORE request. */ - asize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING); - /* Use mem here only if it did continuously extend old space */ - if (asize < HALF_MAX_SIZE_T && - (br = (char*)(CALL_MORECORE(asize))) == ss->base + ss->size) - { - tbase = br; - tsize = asize; - } - } - - if (tbase == CMFAIL) /* Cope with partial failure */ - { - if (br != CMFAIL) /* Try to use/extend the space we did get */ - { - if (asize < HALF_MAX_SIZE_T && - asize < nb + SYS_ALLOC_PADDING) - { - size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - asize); - if (esize < HALF_MAX_SIZE_T) - { - char* end = (char*)CALL_MORECORE(esize); - if (end != CMFAIL) - { - asize += esize; - } - else /* Can't use; try to release */ - { - (void) CALL_MORECORE(-asize); - br = CMFAIL; - } - } - } - } - if (br != CMFAIL) /* Use the space we did get */ - { - tbase = br; - tsize = asize; - } - else - { - disable_contiguous(m); /* Don't try contiguous path in the future */ - } - } - - RELEASE_MALLOC_GLOBAL_LOCK(); - } - - if (HAVE_MMAP && tbase == CMFAIL) /* Try MMAP */ - { - size_t rsize = granularity_align(nb + SYS_ALLOC_PADDING); - if (rsize > nb) /* Fail if wraps around zero */ - { - char* mp = (char*)((*m->mmap)(m->extp, rsize)); - if (mp != CMFAIL) - { - tbase = mp; - tsize = rsize; - mmap_flag = USE_MMAP_BIT; - } - } - } - - if (HAVE_MORECORE && tbase == CMFAIL) /* Try noncontiguous MORECORE */ - { - size_t asize = granularity_align(nb + SYS_ALLOC_PADDING); - if (asize < HALF_MAX_SIZE_T) - { - char* br = CMFAIL; - char* end = CMFAIL; - ACQUIRE_MALLOC_GLOBAL_LOCK(); - br = (char*)(CALL_MORECORE(asize)); - end = (char*)(CALL_MORECORE(0)); - RELEASE_MALLOC_GLOBAL_LOCK(); - if (br != CMFAIL && end != CMFAIL && br < end) - { - size_t ssize = end - br; - if (ssize > nb + TOP_FOOT_SIZE) - { - tbase = br; - tsize = ssize; - } - } - } - } - - if (tbase != CMFAIL) - { - if ((m->footprint += tsize) > m->max_footprint) - { - m->max_footprint = m->footprint; - } - - if (!is_initialized(m)) /* first-time initialization */ - { - if (m->least_addr == 0 || tbase < m->least_addr) - { - m->least_addr = tbase; - } - m->seg.base = tbase; - m->seg.size = tsize; - m->seg.sflags = mmap_flag; - m->magic = mparams.magic; - m->release_checks = MAX_RELEASE_CHECK_RATE; - init_bins(m); -#if !ONLY_MSPACES - if (is_global(m)) - { - init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); - } - else -#endif - { - /* Offset top by embedded malloc_state */ - mchunkptr mn = next_chunk(mem2chunk(m)); - init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); - } - } - - else - { - /* Try to merge with an existing segment */ - msegmentptr sp = &m->seg; - /* Only consider most recent segment if traversal suppressed */ - while (sp != 0 && tbase != sp->base + sp->size) - { - sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; - } - if (sp != 0 && - !is_extern_segment(sp) && - (sp->sflags & USE_MMAP_BIT) == mmap_flag && - segment_holds(sp, m->top)) /* append */ - { - sp->size += tsize; - init_top(m, m->top, m->topsize + tsize); - } - else - { - if (tbase < m->least_addr) - { - m->least_addr = tbase; - } - sp = &m->seg; - while (sp != 0 && sp->base != tbase + tsize) - { - sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; - } - if (sp != 0 && - !is_extern_segment(sp) && - (sp->sflags & USE_MMAP_BIT) == mmap_flag) - { - char* oldbase = sp->base; - sp->base = tbase; - sp->size += tsize; - return prepend_alloc(m, tbase, oldbase, nb); - } - else - { - add_segment(m, tbase, tsize, mmap_flag); - } - } - } - - if (nb < m->topsize) /* Allocate from new or extended top space */ - { - size_t rsize = m->topsize -= nb; - mchunkptr p = m->top; - mchunkptr r = m->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(m, p, nb); - check_top_chunk(m, m->top); - check_malloced_chunk(m, chunk2mem(p), nb); - return chunk2mem(p); - } - } - - MALLOC_FAILURE_ACTION; - return 0; -} - -/* ----------------------- system deallocation -------------------------- */ - -/* Unmap and unlink any mmapped segments that don't contain used chunks */ -static size_t release_unused_segments(mstate m) -{ - size_t released = 0; - int nsegs = 0; - msegmentptr pred = &m->seg; - msegmentptr sp = pred->next; - while (sp != 0) - { - char* base = sp->base; - size_t size = sp->size; - msegmentptr next = sp->next; - ++nsegs; - if (is_mmapped_segment(sp) && !is_extern_segment(sp)) - { - mchunkptr p = align_as_chunk(base); - size_t psize = chunksize(p); - /* Can unmap if first chunk holds entire segment and not pinned */ - if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) - { - tchunkptr tp = (tchunkptr)p; - assert(segment_holds(sp, (char*)sp)); - if (p == m->dv) - { - m->dv = 0; - m->dvsize = 0; - } - else - { - unlink_large_chunk(m, tp); - } - if ((*m->munmap)(m->extp, base, size) == 0) - { - released += size; - m->footprint -= size; - /* unlink obsoleted record */ - sp = pred; - sp->next = next; - } - else /* back out if cannot unmap */ - { - insert_large_chunk(m, tp, psize); - } - } - } - if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */ - { - break; - } - pred = sp; - sp = next; - } - /* Reset check counter */ - m->release_checks = ((nsegs > MAX_RELEASE_CHECK_RATE) ? - nsegs : MAX_RELEASE_CHECK_RATE); - return released; -} - -static int sys_trim(mstate m, size_t pad) -{ - size_t released = 0; - ensure_initialization(); - if (pad < MAX_REQUEST && is_initialized(m)) - { - pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ - - if (m->topsize > pad) - { - /* Shrink top space in granularity-size units, keeping at least one */ - size_t unit = mparams.granularity; - size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - - SIZE_T_ONE) * unit; - msegmentptr sp = segment_holding(m, (char*)m->top); - - if (!is_extern_segment(sp)) - { - if (is_mmapped_segment(sp)) - { - if (HAVE_MMAP && - sp->size >= extra && - 1 /*!has_segment_link(m, sp)*/) /* can't shrink if pinned */ - { - size_t newsize = sp->size - extra; - /* Prefer mremap, fall back to munmap */ - if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || - ((*m->munmap)(m->extp, sp->base + newsize, extra) == 0)) - { - released = extra; - } - } - } - else if (HAVE_MORECORE) - { - if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ - { - extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; - } - ACQUIRE_MALLOC_GLOBAL_LOCK(); - { - /* Make sure end of memory is where we last set it. */ - char* old_br = (char*)(CALL_MORECORE(0)); - if (old_br == sp->base + sp->size) - { - char* rel_br = (char*)(CALL_MORECORE(-extra)); - char* new_br = (char*)(CALL_MORECORE(0)); - if (rel_br != CMFAIL && new_br < old_br) - { - released = old_br - new_br; - } - } - } - RELEASE_MALLOC_GLOBAL_LOCK(); - } - } - - if (released != 0) - { - sp->size -= released; - m->footprint -= released; - init_top(m, m->top, m->topsize - released); - check_top_chunk(m, m->top); - } - } - - /* Unmap any unused mmapped segments */ - if (HAVE_MMAP) - { - released += release_unused_segments(m); - } - - /* On failure, disable autotrim to avoid repeated failed future calls */ - if (released == 0 && m->topsize > m->trim_check) - { - m->trim_check = MAX_SIZE_T; - } - } - - return (released != 0) ? 1 : 0; -} - - -/* ---------------------------- malloc support --------------------------- */ - -/* allocate a large request from the best fitting chunk in a treebin */ -static void* tmalloc_large(mstate m, size_t nb) -{ - tchunkptr v = 0; - size_t rsize = -nb; /* Unsigned negation */ - tchunkptr t; - bindex_t idx; - compute_tree_index(nb, idx); - if ((t = *treebin_at(m, idx)) != 0) - { - /* Traverse tree for this bin looking for node with size == nb */ - size_t sizebits = nb << leftshift_for_tree_index(idx); - tchunkptr rst = 0; /* The deepest untaken right subtree */ - for (;; ) - { - tchunkptr rt; - size_t trem = chunksize(t) - nb; - if (trem < rsize) - { - v = t; - if ((rsize = trem) == 0) - { - break; - } - } - rt = t->child[1]; - t = t->child[(sizebits >> (SIZE_T_BITSIZE - SIZE_T_ONE)) & 1]; - if (rt != 0 && rt != t) - { - rst = rt; - } - if (t == 0) - { - t = rst; /* set t to least subtree holding sizes > nb */ - break; - } - sizebits <<= 1; - } - } - if (t == 0 && v == 0) /* set t to root of next non-empty treebin */ - { - binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; - if (leftbits != 0) - { - bindex_t i; - binmap_t leastbit = least_bit(leftbits); - compute_bit2idx(leastbit, i); - t = *treebin_at(m, i); - } - } - - while (t != 0) /* find smallest of tree or subtree */ - { - size_t trem = chunksize(t) - nb; - if (trem < rsize) - { - rsize = trem; - v = t; - } - t = leftmost_child(t); - } - - /* If dv is a better fit, return 0 so malloc will use it */ - if (v != 0 && rsize < (size_t)(m->dvsize - nb)) - { - if (RTCHECK(ok_address(m, v))) /* split */ - { - mchunkptr r = chunk_plus_offset(v, nb); - assert(chunksize(v) == rsize + nb); - if (RTCHECK(ok_next(v, r))) - { - unlink_large_chunk(m, v); - if (rsize < MIN_CHUNK_SIZE) - { - set_inuse_and_pinuse(m, v, (rsize + nb)); - } - else - { - set_size_and_pinuse_of_inuse_chunk(m, v, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - insert_chunk(m, r, rsize); - } - return chunk2mem(v); - } - } - CORRUPTION_ERROR_ACTION(m); - } - return 0; -} - -/* allocate a small request from the best fitting chunk in a treebin */ -static void* tmalloc_small(mstate m, size_t nb) -{ - tchunkptr t, v; - size_t rsize; - bindex_t i; - binmap_t leastbit = least_bit(m->treemap); - compute_bit2idx(leastbit, i); - v = t = *treebin_at(m, i); - rsize = chunksize(t) - nb; - - while ((t = leftmost_child(t)) != 0) - { - size_t trem = chunksize(t) - nb; - if (trem < rsize) - { - rsize = trem; - v = t; - } - } - - if (RTCHECK(ok_address(m, v))) - { - mchunkptr r = chunk_plus_offset(v, nb); - assert(chunksize(v) == rsize + nb); - if (RTCHECK(ok_next(v, r))) - { - unlink_large_chunk(m, v); - if (rsize < MIN_CHUNK_SIZE) - { - set_inuse_and_pinuse(m, v, (rsize + nb)); - } - else - { - set_size_and_pinuse_of_inuse_chunk(m, v, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(m, r, rsize); - } - return chunk2mem(v); - } - } - - CORRUPTION_ERROR_ACTION(m); -#if PROCEED_ON_ERROR - return 0; -#endif -} - -/* --------------------------- realloc support --------------------------- */ - -static void* internal_realloc(mstate m, void* oldmem, size_t bytes) -{ - if (bytes >= MAX_REQUEST) - { - MALLOC_FAILURE_ACTION; - return 0; - } - if (!PREACTION(m)) - { - mchunkptr oldp = mem2chunk(oldmem); - size_t oldsize = chunksize(oldp); - mchunkptr next = chunk_plus_offset(oldp, oldsize); - mchunkptr newp = 0; - void* extra = 0; - - /* Try to either shrink or extend into top. Else malloc-copy-free */ - - if (RTCHECK(ok_address(m, oldp) && ok_inuse(oldp) && - ok_next(oldp, next) && ok_pinuse(next))) - { - size_t nb = request2size(bytes); - if (is_mmapped(oldp)) - { - newp = mmap_resize(m, oldp, nb); - } - else if (oldsize >= nb) /* already big enough */ - { - size_t rsize = oldsize - nb; - newp = oldp; - if (rsize >= MIN_CHUNK_SIZE) - { - mchunkptr remainder = chunk_plus_offset(newp, nb); - set_inuse(m, newp, nb); - set_inuse_and_pinuse(m, remainder, rsize); - extra = chunk2mem(remainder); - } - } - else if (next == m->top && oldsize + m->topsize > nb) - { - /* Expand into top */ - size_t newsize = oldsize + m->topsize; - size_t newtopsize = newsize - nb; - mchunkptr newtop = chunk_plus_offset(oldp, nb); - set_inuse(m, oldp, nb); - newtop->head = newtopsize | PINUSE_BIT; - m->top = newtop; - m->topsize = newtopsize; - newp = oldp; - } - } - else - { - USAGE_ERROR_ACTION(m, oldmem); - POSTACTION(m); -#if PROCEED_ON_ERROR - return 0; -#endif - } -#if DEBUG - if (newp != 0) - { - check_inuse_chunk(m, newp); /* Check requires lock */ - } -#endif - - POSTACTION(m); - - if (newp != 0) - { - if (extra != 0) - { - internal_free(m, extra); - } - return chunk2mem(newp); - } - else - { - void* newmem = internal_malloc(m, bytes); - if (newmem != 0) - { - size_t oc = oldsize - overhead_for(oldp); - memcpy(newmem, oldmem, (oc < bytes) ? oc : bytes); - internal_free(m, oldmem); - } - return newmem; - } - } - return 0; -} - -/* --------------------------- memalign support -------------------------- */ - -static void* internal_memalign(mstate m, size_t alignment, size_t bytes) -{ - if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */ - { - return internal_malloc(m, bytes); - } - if (alignment < MIN_CHUNK_SIZE)/* must be at least a minimum chunk size */ - { - alignment = MIN_CHUNK_SIZE; - } - if ((alignment & (alignment - SIZE_T_ONE)) != 0)/* Ensure a power of 2 */ - { - size_t a = MALLOC_ALIGNMENT << 1; - while (a < alignment) - { - a <<= 1; - } - alignment = a; - } - - if (bytes >= MAX_REQUEST - alignment) - { - if (m != 0) /* Test isn't needed but avoids compiler warning */ - { - MALLOC_FAILURE_ACTION; - } - } - else - { - size_t nb = request2size(bytes); - size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; - char* mem = (char*)internal_malloc(m, req); - if (mem != 0) - { - void* leader = 0; - void* trailer = 0; - mchunkptr p = mem2chunk(mem); - - if (PREACTION(m)) - { - return 0; - } - if ((((size_t)(mem)) % alignment) != 0) /* misaligned */ - { - /* - Find an aligned spot inside chunk. Since we need to give - back leading space in a chunk of at least MIN_CHUNK_SIZE, if - the first calculation places us at a spot with less than - MIN_CHUNK_SIZE leader, we can move to the next aligned spot. - We've allocated enough total room so that this is always - possible. - */ - char* br = (char*)mem2chunk((size_t)(((size_t)(mem + - alignment - - SIZE_T_ONE)) & - - alignment)); - char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE) ? - br : br + alignment; - mchunkptr newp = (mchunkptr)pos; - size_t leadsize = pos - (char*)(p); - size_t newsize = chunksize(p) - leadsize; - - if (is_mmapped(p)) /* For mmapped chunks, just adjust offset */ - { - newp->prev_foot = p->prev_foot + leadsize; - newp->head = newsize; - } - else /* Otherwise, give back leader, use the rest */ - { - set_inuse(m, newp, newsize); - set_inuse(m, p, leadsize); - leader = chunk2mem(p); - } - p = newp; - } - - /* Give back spare room at the end */ - if (!is_mmapped(p)) - { - size_t size = chunksize(p); - if (size > nb + MIN_CHUNK_SIZE) - { - size_t remainder_size = size - nb; - mchunkptr remainder = chunk_plus_offset(p, nb); - set_inuse(m, p, nb); - set_inuse(m, remainder, remainder_size); - trailer = chunk2mem(remainder); - } - } - - assert (chunksize(p) >= nb); - assert((((size_t)(chunk2mem(p))) % alignment) == 0); - check_inuse_chunk(m, p); - POSTACTION(m); - if (leader != 0) - { - internal_free(m, leader); - } - if (trailer != 0) - { - internal_free(m, trailer); - } - return chunk2mem(p); - } - } - return 0; -} - -/* ------------------------ comalloc/coalloc support --------------------- */ - -static void** ialloc(mstate m, - size_t n_elements, - size_t* sizes, - int opts, - void* chunks[]) -{ - /* - This provides common support for independent_X routines, handling - all of the combinations that can result. - - The opts arg has: - bit 0 set if all elements are same size (using sizes[0]) - bit 1 set if elements should be zeroed - */ - - size_t element_size; /* chunksize of each element, if all same */ - size_t contents_size;/* total size of elements */ - size_t array_size; /* request size of pointer array */ - void* mem; /* malloced aggregate space */ - mchunkptr p; /* corresponding chunk */ - size_t remainder_size;/* remaining bytes while splitting */ - void** marray; /* either "chunks" or malloced ptr array */ - mchunkptr array_chunk; /* chunk for malloced ptr array */ - flag_t was_enabled; /* to disable mmap */ - size_t size; - size_t i; - - ensure_initialization(); - /* compute array length, if needed */ - if (chunks != 0) - { - if (n_elements == 0) - { - return chunks; /* nothing to do */ - } - marray = chunks; - array_size = 0; - } - else - { - /* if empty req, must still return chunk representing empty array */ - if (n_elements == 0) - { - return (void**)internal_malloc(m, 0); - } - marray = 0; - array_size = request2size(n_elements * (sizeof(void*))); - } - - /* compute total element size */ - if (opts & 0x1) /* all-same-size */ - { - element_size = request2size(*sizes); - contents_size = n_elements * element_size; - } - else /* add up all the sizes */ - { - element_size = 0; - contents_size = 0; - for (i = 0; i != n_elements; ++i) - { - contents_size += request2size(sizes[i]); - } - } - - size = contents_size + array_size; - - /* - Allocate the aggregate chunk. First disable direct-mmapping so - malloc won't use it, since we would not be able to later - free/realloc space internal to a segregated mmap region. - */ - was_enabled = use_mmap(m); - disable_mmap(m); - mem = internal_malloc(m, size - CHUNK_OVERHEAD); - if (was_enabled) - { - enable_mmap(m); - } - if (mem == 0) - { - return 0; - } - - if (PREACTION(m)) - { - return 0; - } - p = mem2chunk(mem); - remainder_size = chunksize(p); - - assert(!is_mmapped(p)); - - if (opts & 0x2) /* optionally clear the elements */ - { - memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); - } - - /* If not provided, allocate the pointer array as final part of chunk */ - if (marray == 0) - { - size_t array_chunk_size; - array_chunk = chunk_plus_offset(p, contents_size); - array_chunk_size = remainder_size - contents_size; - marray = (void**) (chunk2mem(array_chunk)); - set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); - remainder_size = contents_size; - } - - /* split out elements */ - for (i = 0;; ++i) - { - marray[i] = chunk2mem(p); - if (i != n_elements - 1) - { - if (element_size != 0) - { - size = element_size; - } - else - { - size = request2size(sizes[i]); - } - remainder_size -= size; - set_size_and_pinuse_of_inuse_chunk(m, p, size); - p = chunk_plus_offset(p, size); - } - else /* the final element absorbs any overallocation slop */ - { - set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); - break; - } - } - -#if DEBUG - if (marray != chunks) - { - /* final element must have exactly exhausted chunk */ - if (element_size != 0) - { - assert(remainder_size == element_size); - } - else - { - assert(remainder_size == request2size(sizes[i])); - } - check_inuse_chunk(m, mem2chunk(marray)); - } - for (i = 0; i != n_elements; ++i) - { - check_inuse_chunk(m, mem2chunk(marray[i])); - } - -#endif /* DEBUG */ - - POSTACTION(m); - return marray; -} - - -/* -------------------------- public routines ---------------------------- */ - -#if !ONLY_MSPACES - -void* dlmalloc(size_t bytes) -{ - /* - Basic algorithm: - If a small request (< 256 bytes minus per-chunk overhead): - 1. If one exists, use a remainderless chunk in associated smallbin. - (Remainderless means that there are too few excess bytes to - represent as a chunk.) - 2. If it is big enough, use the dv chunk, which is normally the - chunk adjacent to the one used for the most recent small request. - 3. If one exists, split the smallest available chunk in a bin, - saving remainder in dv. - 4. If it is big enough, use the top chunk. - 5. If available, get memory from system and use it - Otherwise, for a large request: - 1. Find the smallest available binned chunk that fits, and use it - if it is better fitting than dv chunk, splitting if necessary. - 2. If better fitting than any binned chunk, use the dv chunk. - 3. If it is big enough, use the top chunk. - 4. If request size >= mmap threshold, try to directly mmap this chunk. - 5. If available, get memory from system and use it - - The ugly goto's here ensure that postaction occurs along all paths. - */ - -#if USE_LOCKS - ensure_initialization(); /* initialize in sys_alloc if not using locks */ -#endif - - if (!PREACTION(gm)) - { - void* mem; - size_t nb; - if (bytes <= MAX_SMALL_REQUEST) - { - bindex_t idx; - binmap_t smallbits; - nb = (bytes < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(bytes); - idx = small_index(nb); - smallbits = gm->smallmap >> idx; - - if ((smallbits & 0x3U) != 0) /* Remainderless fit to a smallbin. */ - { - mchunkptr b, p; - idx += ~smallbits & 1; /* Uses next bin if idx empty */ - b = smallbin_at(gm, idx); - p = b->fd; - assert(chunksize(p) == small_index2size(idx)); - unlink_first_small_chunk(gm, b, p, idx); - set_inuse_and_pinuse(gm, p, small_index2size(idx)); - mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - else if (nb > gm->dvsize) - { - if (smallbits != 0) /* Use chunk in next nonempty smallbin */ - { - mchunkptr b, p, r; - size_t rsize; - bindex_t i; - binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); - binmap_t leastbit = least_bit(leftbits); - compute_bit2idx(leastbit, i); - b = smallbin_at(gm, i); - p = b->fd; - assert(chunksize(p) == small_index2size(i)); - unlink_first_small_chunk(gm, b, p, i); - rsize = small_index2size(i) - nb; - /* Fit here cannot be remainderless if 4byte sizes */ - if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) - { - set_inuse_and_pinuse(gm, p, small_index2size(i)); - } - else - { - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); - r = chunk_plus_offset(p, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(gm, r, rsize); - } - mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) - { - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - } - } - else if (bytes >= MAX_REQUEST) - { - nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ - } - else - { - nb = pad_request(bytes); - if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) - { - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - } - - if (nb <= gm->dvsize) - { - size_t rsize = gm->dvsize - nb; - mchunkptr p = gm->dv; - if (rsize >= MIN_CHUNK_SIZE) /* split dv */ - { - mchunkptr r = gm->dv = chunk_plus_offset(p, nb); - gm->dvsize = rsize; - set_size_and_pinuse_of_free_chunk(r, rsize); - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); - } - else /* exhaust dv */ - { - size_t dvs = gm->dvsize; - gm->dvsize = 0; - gm->dv = 0; - set_inuse_and_pinuse(gm, p, dvs); - } - mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - else if (nb < gm->topsize) /* Split top */ - { - size_t rsize = gm->topsize -= nb; - mchunkptr p = gm->top; - mchunkptr r = gm->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); - mem = chunk2mem(p); - check_top_chunk(gm, gm->top); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - mem = sys_alloc(gm, nb); - -postaction: - POSTACTION(gm); - return mem; - } - - return 0; -} - -void dlfree(void* mem) -{ - /* - Consolidate freed chunks with preceeding or succeeding bordering - free chunks, if they exist, and then place in a bin. Intermixed - with special cases for top, dv, mmapped chunks, and usage errors. - */ - - if (mem != 0) - { - mchunkptr p = mem2chunk(mem); -#if FOOTERS - mstate fm = get_mstate_for(p); - if (!ok_magic(fm)) - { - USAGE_ERROR_ACTION(fm, p); - return; - } -#else /* FOOTERS */ -#define fm gm -#endif /* FOOTERS */ - if (!PREACTION(fm)) - { - check_inuse_chunk(fm, p); - if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) - { - size_t psize = chunksize(p); - mchunkptr next = chunk_plus_offset(p, psize); - if (!pinuse(p)) - { - size_t prevsize = p->prev_foot; - if (is_mmapped(p)) - { - psize += prevsize + MMAP_FOOT_PAD; - if ((*fm->munmap)(fm->extp, (char*)p - prevsize, psize) == 0) - { - fm->footprint -= psize; - } - goto postaction; - } - else - { - mchunkptr prev = chunk_minus_offset(p, prevsize); - psize += prevsize; - p = prev; - if (RTCHECK(ok_address(fm, prev))) /* consolidate backward */ - { - if (p != fm->dv) - { - unlink_chunk(fm, p, prevsize); - } - else if ((next->head & INUSE_BITS) == INUSE_BITS) - { - fm->dvsize = psize; - set_free_with_pinuse(p, psize, next); - goto postaction; - } - } - else - { - goto erroraction; - } - } - } - - if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) - { - if (!cinuse(next)) /* consolidate forward */ - { - if (next == fm->top) - { - size_t tsize = fm->topsize += psize; - fm->top = p; - p->head = tsize | PINUSE_BIT; - if (p == fm->dv) - { - fm->dv = 0; - fm->dvsize = 0; - } - if (should_trim(fm, tsize)) - { - sys_trim(fm, 0); - } - goto postaction; - } - else if (next == fm->dv) - { - size_t dsize = fm->dvsize += psize; - fm->dv = p; - set_size_and_pinuse_of_free_chunk(p, dsize); - goto postaction; - } - else - { - size_t nsize = chunksize(next); - psize += nsize; - unlink_chunk(fm, next, nsize); - set_size_and_pinuse_of_free_chunk(p, psize); - if (p == fm->dv) - { - fm->dvsize = psize; - goto postaction; - } - } - } - else - { - set_free_with_pinuse(p, psize, next); - } - - if (is_small(psize)) - { - insert_small_chunk(fm, p, psize); - check_free_chunk(fm, p); - } - else - { - tchunkptr tp = (tchunkptr)p; - insert_large_chunk(fm, tp, psize); - check_free_chunk(fm, p); - if (--fm->release_checks == 0) - { - release_unused_segments(fm); - } - } - goto postaction; - } - } -erroraction: - USAGE_ERROR_ACTION(fm, p); -postaction: - POSTACTION(fm); - } - } -#if !FOOTERS -#undef fm -#endif /* FOOTERS */ -} - -void* dlcalloc(size_t n_elements, size_t elem_size) -{ - void* mem; - size_t req = 0; - if (n_elements != 0) - { - req = n_elements * elem_size; - if (((n_elements | elem_size) & ~(size_t)0xffff) && - (req / n_elements != elem_size)) - { - req = MAX_SIZE_T; /* force downstream failure on overflow */ - } - } - mem = dlmalloc(req); - if (mem != 0 && calloc_must_clear(mem2chunk(mem))) - { - memset(mem, 0, req); - } - return mem; -} - -void* dlrealloc(void* oldmem, size_t bytes) -{ - if (oldmem == 0) - { - return dlmalloc(bytes); - } -#ifdef REALLOC_ZERO_BYTES_FREES - if (bytes == 0) - { - dlfree(oldmem); - return 0; - } -#endif /* REALLOC_ZERO_BYTES_FREES */ - else - { -#if !FOOTERS - mstate m = gm; -#else /* FOOTERS */ - mstate m = get_mstate_for(mem2chunk(oldmem)); - if (!ok_magic(m)) - { - USAGE_ERROR_ACTION(m, oldmem); - return 0; - } -#endif /* FOOTERS */ - return internal_realloc(m, oldmem, bytes); - } -} - -void* dlmemalign(size_t alignment, size_t bytes) -{ - return internal_memalign(gm, alignment, bytes); -} - -void** dlindependent_calloc(size_t n_elements, size_t elem_size, - void* chunks[]) -{ - size_t sz = elem_size; /* serves as 1-element array */ - return ialloc(gm, n_elements, &sz, 3, chunks); -} - -void** dlindependent_comalloc(size_t n_elements, size_t sizes[], - void* chunks[]) -{ - return ialloc(gm, n_elements, sizes, 0, chunks); -} - -void* dlvalloc(size_t bytes) -{ - size_t pagesz; - ensure_initialization(); - pagesz = mparams.page_size; - return dlmemalign(pagesz, bytes); -} - -void* dlpvalloc(size_t bytes) -{ - size_t pagesz; - ensure_initialization(); - pagesz = mparams.page_size; - return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); -} - -int dlmalloc_trim(size_t pad) -{ - int result = 0; - ensure_initialization(); - if (!PREACTION(gm)) - { - result = sys_trim(gm, pad); - POSTACTION(gm); - } - return result; -} - -size_t dlmalloc_footprint(void) -{ - return gm->footprint; -} - -size_t dlmalloc_max_footprint(void) -{ - return gm->max_footprint; -} - -#if !NO_MALLINFO -struct mallinfo dlmallinfo(void) -{ - return internal_mallinfo(gm); -} -#endif /* NO_MALLINFO */ - -void dlmalloc_stats() -{ - internal_malloc_stats(gm); -} - -void dlmalloc_stats_ret(size_t* sys, size_t* maxSys, size_t* used) -{ - internal_malloc_stats_ret(gm, sys, maxSys, used); -} - -int dlmallopt(int param_number, int value) -{ - return change_mparam(param_number, value); -} - -void dlPrintStats(void) -{ - struct mallinfo info = dlmallinfo(); - fprintf(stdout, "Non-MMap:%d\nFreeChunks:%d\nMMap Space:%d\nTotal Space:%d\nAlloc Space:%d\nFree Space:%d\nReleasable:%d\n", - (int)info.arena, (int)info.ordblks, (int)info.hblkhd, (int)info.usmblks, (int)info.uordblks, (int)info.fordblks, (int)info.keepcost); - - ensure_initialization(); - if (!PREACTION(gm)) - { - check_malloc_state(gm); - if (is_initialized(gm)) - { - msegmentptr s = &gm->seg; - while (s != 0) - { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && - q != gm->top && q->head != FENCEPOST_HEAD) - { - size_t sz = chunksize(q); - if (!is_inuse(q)) - { - fprintf(stdout, "Free: %p %d\n", q, (int)sz); - } - else - { - fprintf(stdout, "InUse: %p %d\n", q, (int)sz); - } - q = next_chunk(q); - } - s = s->next; - } - } - } -} -#endif /* !ONLY_MSPACES */ - -size_t dlmalloc_usable_size(void* mem) -{ - if (mem != 0) - { - mchunkptr p = mem2chunk(mem); - if (is_inuse(p)) - { - return chunksize(p) - overhead_for(p); - } - } - return 0; -} - -/* ----------------------------- user mspaces ---------------------------- */ - -#if MSPACES - -static mstate init_user_mstate(char* tbase, size_t tsize, void* user, dlmmap_handler mmap, dlmunmap_handler munmap) -{ - size_t msize = pad_request(sizeof(struct malloc_state)); - mchunkptr mn; - mchunkptr msp = align_as_chunk(tbase); - mstate m = (mstate)(chunk2mem(msp)); - memset(m, 0, msize); - INITIAL_LOCK(&m->mutex); - msp->head = (msize | INUSE_BITS); - m->seg.base = m->least_addr = tbase; - m->seg.size = m->footprint = m->max_footprint = tsize; - m->magic = mparams.magic; - m->release_checks = MAX_RELEASE_CHECK_RATE; - m->mflags = mparams.default_mflags; - m->extp = user; - m->exts = 0; - m->mmap = mmap; - m->munmap = munmap; - disable_contiguous(m); - init_bins(m); - mn = next_chunk(mem2chunk(m)); - init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); - check_top_chunk(m, m->top); - return m; -} - -static void* mmap_default(void* u, size_t sz) -{ - (void)u; - return CALL_MMAP(sz); -} - -static int munmap_default(void* u, void* p, size_t s) -{ - (void)u; - return CALL_MUNMAP(p, s); -} - -static void* mmap_missing(void* u, size_t sz) -{ - (void)u; - (void)sz; - return (void*) -1; -} - -static int munmap_missing(void* u, void* p, size_t s) -{ - (void)u; - (void)p; - (void)s; - return -1; -} - -int mspace_create_overhead(void) -{ - size_t msize = pad_request(sizeof(struct malloc_state)); - return msize + TOP_FOOT_SIZE; -} - -mspace create_mspace(size_t capacity, int locked, void* user, dlmmap_handler mmap, dlmunmap_handler munmap) -{ - mstate m = 0; - size_t msize; - ensure_initialization(); - msize = pad_request(sizeof(struct malloc_state)); - - if (!mmap) - { - mmap = mmap_default; - } - if (!munmap) - { - munmap = munmap_default; - } - - if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) - { - size_t rs = ((capacity == 0) ? mparams.granularity : - (capacity + TOP_FOOT_SIZE + msize)); - size_t tsize = granularity_align(rs); - char* tbase = (char*)((*mmap)(user, tsize)); - if (tbase != CMFAIL) - { - m = init_user_mstate(tbase, tsize, user, mmap, munmap); - m->seg.sflags = USE_MMAP_BIT; - set_lock(m, locked); - } - } - return (mspace)m; -} - -mspace create_mspace_with_base(void* base, size_t capacity, int locked) -{ - mstate m = 0; - size_t msize; - ensure_initialization(); - msize = pad_request(sizeof(struct malloc_state)); - if (capacity > msize + TOP_FOOT_SIZE && - capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) - { - m = init_user_mstate((char*)base, capacity, NULL, mmap_missing, munmap_missing); - m->seg.sflags = EXTERN_BIT; - set_lock(m, locked); - } - return (mspace)m; -} - -int mspace_track_large_chunks(mspace msp, int enable) -{ - int ret = 0; - mstate ms = (mstate)msp; - if (!PREACTION(ms)) - { - if (!use_mmap(ms)) - { - ret = 1; - } - if (!enable) - { - enable_mmap(ms); - } - else - { - disable_mmap(ms); - } - POSTACTION(ms); - } - return ret; -} - -size_t destroy_mspace(mspace msp) -{ - size_t freed = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) - { - msegmentptr sp = &ms->seg; - while (sp != 0) - { - char* base = sp->base; - size_t size = sp->size; - flag_t flag = sp->sflags; - sp = sp->next; - if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) && - (*ms->munmap)(ms->extp, base, size) == 0) - { - freed += size; - } - } - } - else - { - USAGE_ERROR_ACTION(ms, ms); - } - return freed; -} - -/* - mspace versions of routines are near-clones of the global - versions. This is not so nice but better than the alternatives. -*/ - - -void* mspace_malloc(mspace msp, size_t bytes) -{ - mstate ms = (mstate)msp; - if (!ok_magic(ms)) - { - USAGE_ERROR_ACTION(ms, ms); -#if PROCEED_ON_ERROR - return 0; -#endif - } - if (!PREACTION(ms)) - { - void* mem; - size_t nb; - if (bytes <= MAX_SMALL_REQUEST) - { - bindex_t idx; - binmap_t smallbits; - nb = (bytes < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(bytes); - idx = small_index(nb); - smallbits = ms->smallmap >> idx; - - if ((smallbits & 0x3U) != 0) /* Remainderless fit to a smallbin. */ - { - mchunkptr b, p; - idx += ~smallbits & 1; /* Uses next bin if idx empty */ - b = smallbin_at(ms, idx); - p = b->fd; - assert(chunksize(p) == small_index2size(idx)); - unlink_first_small_chunk(ms, b, p, idx); - set_inuse_and_pinuse(ms, p, small_index2size(idx)); - mem = chunk2mem(p); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - else if (nb > ms->dvsize) - { - if (smallbits != 0) /* Use chunk in next nonempty smallbin */ - { - mchunkptr b, p, r; - size_t rsize; - bindex_t i; - binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); - binmap_t leastbit = least_bit(leftbits); - compute_bit2idx(leastbit, i); - b = smallbin_at(ms, i); - p = b->fd; - assert(chunksize(p) == small_index2size(i)); - unlink_first_small_chunk(ms, b, p, i); - rsize = small_index2size(i) - nb; - /* Fit here cannot be remainderless if 4byte sizes */ - if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) - { - set_inuse_and_pinuse(ms, p, small_index2size(i)); - } - else - { - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - r = chunk_plus_offset(p, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(ms, r, rsize); - } - mem = chunk2mem(p); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) - { - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - } - } - else if (bytes >= MAX_REQUEST) - { - nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ - } - else - { - nb = pad_request(bytes); - if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) - { - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - } - - if (nb <= ms->dvsize) - { - size_t rsize = ms->dvsize - nb; - mchunkptr p = ms->dv; - if (rsize >= MIN_CHUNK_SIZE) /* split dv */ - { - mchunkptr r = ms->dv = chunk_plus_offset(p, nb); - ms->dvsize = rsize; - set_size_and_pinuse_of_free_chunk(r, rsize); - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - } - else /* exhaust dv */ - { - size_t dvs = ms->dvsize; - ms->dvsize = 0; - ms->dv = 0; - set_inuse_and_pinuse(ms, p, dvs); - } - mem = chunk2mem(p); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - else if (nb < ms->topsize) /* Split top */ - { - size_t rsize = ms->topsize -= nb; - mchunkptr p = ms->top; - mchunkptr r = ms->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - mem = chunk2mem(p); - check_top_chunk(ms, ms->top); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - mem = sys_alloc(ms, nb); - -postaction: - POSTACTION(ms); - return mem; - } - - return 0; -} - -void mspace_free(mspace msp, void* mem) -{ - if (mem != 0) - { - mchunkptr p = mem2chunk(mem); -#if FOOTERS - mstate fm = get_mstate_for(p); - msp = msp; /* placate people compiling -Wunused */ -#else /* FOOTERS */ - mstate fm = (mstate)msp; -#endif /* FOOTERS */ - if (!ok_magic(fm)) - { - USAGE_ERROR_ACTION(fm, p); - return; - } - if (!PREACTION(fm)) - { - check_inuse_chunk(fm, p); - if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) - { - size_t psize = chunksize(p); - mchunkptr next = chunk_plus_offset(p, psize); - if (!pinuse(p)) - { - size_t prevsize = p->prev_foot; - if (is_mmapped(p)) - { - psize += prevsize + MMAP_FOOT_PAD; - if ((*fm->munmap)(fm->extp, (char*)p - prevsize, psize) == 0) - { - fm->footprint -= psize; - } - goto postaction; - } - else - { - mchunkptr prev = chunk_minus_offset(p, prevsize); - psize += prevsize; - p = prev; - if (RTCHECK(ok_address(fm, prev))) /* consolidate backward */ - { - if (p != fm->dv) - { - unlink_chunk(fm, p, prevsize); - } - else if ((next->head & INUSE_BITS) == INUSE_BITS) - { - fm->dvsize = psize; - set_free_with_pinuse(p, psize, next); - goto postaction; - } - } - else - { - goto erroraction; - } - } - } - - if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) - { - if (!cinuse(next)) /* consolidate forward */ - { - if (next == fm->top) - { - size_t tsize = fm->topsize += psize; - fm->top = p; - p->head = tsize | PINUSE_BIT; - if (p == fm->dv) - { - fm->dv = 0; - fm->dvsize = 0; - } - if (should_trim(fm, tsize)) - { - sys_trim(fm, 0); - } - goto postaction; - } - else if (next == fm->dv) - { - size_t dsize = fm->dvsize += psize; - fm->dv = p; - set_size_and_pinuse_of_free_chunk(p, dsize); - goto postaction; - } - else - { - size_t nsize = chunksize(next); - psize += nsize; - unlink_chunk(fm, next, nsize); - set_size_and_pinuse_of_free_chunk(p, psize); - if (p == fm->dv) - { - fm->dvsize = psize; - goto postaction; - } - } - } - else - { - set_free_with_pinuse(p, psize, next); - } - - if (is_small(psize)) - { - insert_small_chunk(fm, p, psize); - check_free_chunk(fm, p); - } - else - { - tchunkptr tp = (tchunkptr)p; - insert_large_chunk(fm, tp, psize); - check_free_chunk(fm, p); - if (--fm->release_checks == 0) - { - release_unused_segments(fm); - } - } - goto postaction; - } - } -erroraction: - USAGE_ERROR_ACTION(fm, p); -postaction: - POSTACTION(fm); - } - } -} - -void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) -{ - void* mem; - size_t req = 0; - mstate ms = (mstate)msp; - if (!ok_magic(ms)) - { - USAGE_ERROR_ACTION(ms, ms); -#if PROCEED_ON_ERROR - return 0; -#endif - } - if (n_elements != 0) - { - req = n_elements * elem_size; - if (((n_elements | elem_size) & ~(size_t)0xffff) && - (req / n_elements != elem_size)) - { - req = MAX_SIZE_T; /* force downstream failure on overflow */ - } - } - mem = internal_malloc(ms, req); - if (mem != 0 && calloc_must_clear(mem2chunk(mem))) - { - memset(mem, 0, req); - } - return mem; -} - -void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) -{ - if (oldmem == 0) - { - return mspace_malloc(msp, bytes); - } -#ifdef REALLOC_ZERO_BYTES_FREES - if (bytes == 0) - { - mspace_free(msp, oldmem); - return 0; - } -#endif /* REALLOC_ZERO_BYTES_FREES */ - else - { -#if FOOTERS - mchunkptr p = mem2chunk(oldmem); - mstate ms = get_mstate_for(p); -#else /* FOOTERS */ - mstate ms = (mstate)msp; -#endif /* FOOTERS */ - if (!ok_magic(ms)) - { - USAGE_ERROR_ACTION(ms, ms); -#if PROCEED_ON_ERROR - return 0; -#endif - } - return internal_realloc(ms, oldmem, bytes); - } -} - -void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) -{ - mstate ms = (mstate)msp; - if (!ok_magic(ms)) - { - USAGE_ERROR_ACTION(ms, ms); -#if PROCEED_ON_ERROR - return 0; -#endif - } - return internal_memalign(ms, alignment, bytes); -} - -void** mspace_independent_calloc(mspace msp, size_t n_elements, - size_t elem_size, void* chunks[]) -{ - size_t sz = elem_size; /* serves as 1-element array */ - mstate ms = (mstate)msp; - if (!ok_magic(ms)) - { - USAGE_ERROR_ACTION(ms, ms); -#if PROCEED_ON_ERROR - return 0; -#endif - } - return ialloc(ms, n_elements, &sz, 3, chunks); -} - -void** mspace_independent_comalloc(mspace msp, size_t n_elements, - size_t sizes[], void* chunks[]) -{ - mstate ms = (mstate)msp; - if (!ok_magic(ms)) - { - USAGE_ERROR_ACTION(ms, ms); -#if PROCEED_ON_ERROR - return 0; -#endif - } - return ialloc(ms, n_elements, sizes, 0, chunks); -} - -int mspace_trim(mspace msp, size_t pad) -{ - int result = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) - { - if (!PREACTION(ms)) - { - result = sys_trim(ms, pad); - POSTACTION(ms); - } - } - else - { - USAGE_ERROR_ACTION(ms, ms); - } - return result; -} - -void mspace_malloc_stats(mspace msp) -{ - mstate ms = (mstate)msp; - if (ok_magic(ms)) - { - internal_malloc_stats(ms); - } - else - { - USAGE_ERROR_ACTION(ms, ms); - } -} - -size_t mspace_footprint(mspace msp) -{ - size_t result = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) - { - result = ms->footprint; - } - else - { - USAGE_ERROR_ACTION(ms, ms); - } - return result; -} - - -size_t mspace_max_footprint(mspace msp) -{ - size_t result = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) - { - result = ms->max_footprint; - } - else - { - USAGE_ERROR_ACTION(ms, ms); - } - return result; -} - - -#if !NO_MALLINFO -struct mallinfo mspace_mallinfo(mspace msp) -{ - mstate ms = (mstate)msp; - if (!ok_magic(ms)) - { - USAGE_ERROR_ACTION(ms, ms); - } - return internal_mallinfo(ms); -} - -size_t mspace_get_used_space(mspace msp) -{ - struct mallinfo info = mspace_mallinfo(msp); - return info.uordblks; -} -#endif /* NO_MALLINFO */ - -size_t mspace_usable_size(void* mem) -{ - if (mem != 0) - { - mchunkptr p = mem2chunk(mem); - if (is_inuse(p)) - { - return chunksize(p) - overhead_for(p); - } - } - return 0; -} - -int mspace_mallopt(int param_number, int value) -{ - return change_mparam(param_number, value); -} - -#endif /* MSPACES */ - - -/* -------------------- Alternative MORECORE functions ------------------- */ - -/* - Guidelines for creating a custom version of MORECORE: - - * For best performance, MORECORE should allocate in multiples of pagesize. - * MORECORE may allocate more memory than requested. (Or even less, - but this will usually result in a malloc failure.) - * MORECORE must not allocate memory when given argument zero, but - instead return one past the end address of memory from previous - nonzero call. - * For best performance, consecutive calls to MORECORE with positive - arguments should return increasing addresses, indicating that - space has been contiguously extended. - * Even though consecutive calls to MORECORE need not return contiguous - addresses, it must be OK for malloc'ed chunks to span multiple - regions in those cases where they do happen to be contiguous. - * MORECORE need not handle negative arguments -- it may instead - just return MFAIL when given negative arguments. - Negative arguments are always multiples of pagesize. MORECORE - must not misinterpret negative args as large positive unsigned - args. You can suppress all such calls from even occurring by defining - MORECORE_CANNOT_TRIM, - - As an example alternative MORECORE, here is a custom allocator - kindly contributed for pre-OSX macOS. It uses virtually but not - necessarily physically contiguous non-paged memory (locked in, - present and won't get swapped out). You can use it by uncommenting - this section, adding some #includes, and setting up the appropriate - defines above: - - #define MORECORE osMoreCore - - There is also a shutdown routine that should somehow be called for - cleanup upon program exit. - - #define MAX_POOL_ENTRIES 100 - #define MINIMUM_MORECORE_SIZE (64 * 1024U) - static int next_os_pool; - void *our_os_pools[MAX_POOL_ENTRIES]; - - void *osMoreCore(int size) - { - void *ptr = 0; - static void *sbrk_top = 0; - - if (size > 0) - { - if (size < MINIMUM_MORECORE_SIZE) - size = MINIMUM_MORECORE_SIZE; - if (CurrentExecutionLevel() == kTaskLevel) - ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); - if (ptr == 0) - { - return (void *) MFAIL; - } - // save ptrs so they can be freed during cleanup - our_os_pools[next_os_pool] = ptr; - next_os_pool++; - ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); - sbrk_top = (char *) ptr + size; - return ptr; - } - else if (size < 0) - { - // we don't currently support shrink behavior - return (void *) MFAIL; - } - else - { - return sbrk_top; - } - } - - // cleanup any allocated memory pools - // called as last thing before shutting down driver - - void osCleanupMem(void) - { - void **ptr; - - for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) - if (*ptr) - { - PoolDeallocate(*ptr); - *ptr = 0; - } - } - -*/ - - -/* ----------------------------------------------------------------------- -History: - V2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee) - * Use zeros instead of prev foot for is_mmapped - * Add mspace_track_large_chunks; thanks to Jean Brouwers - * Fix set_inuse in internal_realloc; thanks to Jean Brouwers - * Fix insufficient sys_alloc padding when using 16byte alignment - * Fix bad error check in mspace_footprint - * Adaptations for ptmalloc; thanks to Wolfram Gloger. - * Reentrant spin locks; thanks to Earl Chew and others - * Win32 improvements; thanks to Niall Douglas and Earl Chew - * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options - * Extension hook in malloc_state - * Various small adjustments to reduce warnings on some compilers - * Various configuration extensions/changes for more platforms. Thanks - to all who contributed these. - - V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) - * Add max_footprint functions - * Ensure all appropriate literals are size_t - * Fix conditional compilation problem for some #define settings - * Avoid concatenating segments with the one provided - in create_mspace_with_base - * Rename some variables to avoid compiler shadowing warnings - * Use explicit lock initialization. - * Better handling of sbrk interference. - * Simplify and fix segment insertion, trimming and mspace_destroy - * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x - * Thanks especially to Dennis Flanagan for help on these. - - V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) - * Fix memalign brace error. - - V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) - * Fix improper #endif nesting in C++ - * Add explicit casts needed for C++ - - V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) - * Use trees for large bins - * Support mspaces - * Use segments to unify sbrk-based and mmap-based system allocation, - removing need for emulation on most platforms without sbrk. - * Default safety checks - * Optional footer checks. Thanks to William Robertson for the idea. - * Internal code refactoring - * Incorporate suggestions and platform-specific changes. - Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, - Aaron Bachmann, Emery Berger, and others. - * Speed up non-fastbin processing enough to remove fastbins. - * Remove useless cfree() to avoid conflicts with other apps. - * Remove internal memcpy, memset. Compilers handle builtins better. - * Remove some options that no one ever used and rename others. - - V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) - * Fix malloc_state bitmap array misdeclaration - - V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) - * Allow tuning of FIRST_SORTED_BIN_SIZE - * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. - * Better detection and support for non-contiguousness of MORECORE. - Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger - * Bypass most of malloc if no frees. Thanks To Emery Berger. - * Fix freeing of old top non-contiguous chunk im sysmalloc. - * Raised default trim and map thresholds to 256K. - * Fix mmap-related #defines. Thanks to Lubos Lunak. - * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. - * Branch-free bin calculation - * Default trim and mmap thresholds now 256K. - - V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) - * Introduce independent_comalloc and independent_calloc. - Thanks to Michael Pachos for motivation and help. - * Make optional .h file available - * Allow > 2GB requests on 32bit systems. - * new WIN32 sbrk, mmap, munmap, lock code from . - Thanks also to Andreas Mueller , - and Anonymous. - * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for - helping test this.) - * memalign: check alignment arg - * realloc: don't try to shift chunks backwards, since this - leads to more fragmentation in some programs and doesn't - seem to help in any others. - * Collect all cases in malloc requiring system memory into sysmalloc - * Use mmap as backup to sbrk - * Place all internal state in malloc_state - * Introduce fastbins (although similar to 2.5.1) - * Many minor tunings and cosmetic improvements - * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK - * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS - Thanks to Tony E. Bennett and others. - * Include errno.h to support default failure action. - - V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) - * return null for negative arguments - * Added Several WIN32 cleanups from Martin C. Fong - * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' - (e.g. WIN32 platforms) - * Cleanup header file inclusion for WIN32 platforms - * Cleanup code to avoid Microsoft Visual C++ compiler complaints - * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing - memory allocation routines - * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) - * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to - usage of 'assert' in non-WIN32 code - * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to - avoid infinite loop - * Always call 'fREe()' rather than 'free()' - - V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) - * Fixed ordering problem with boundary-stamping - - V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) - * Added pvalloc, as recommended by H.J. Liu - * Added 64bit pointer support mainly from Wolfram Gloger - * Added anonymously donated WIN32 sbrk emulation - * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen - * malloc_extend_top: fix mask error that caused wastage after - foreign sbrks - * Add linux mremap support code from HJ Liu - - V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) - * Integrated most documentation with the code. - * Add support for mmap, with help from - Wolfram Gloger (Gloger@lrz.uni-muenchen.de). - * Use last_remainder in more cases. - * Pack bins using idea from colin@nyx10.cs.du.edu - * Use ordered bins instead of best-fit threshhold - * Eliminate block-local decls to simplify tracing and debugging. - * Support another case of realloc via move into top - * Fix error occuring when initial sbrk_base not word-aligned. - * Rely on page size for units instead of SBRK_UNIT to - avoid surprises about sbrk alignment conventions. - * Add mallinfo, mallopt. Thanks to Raymond Nijssen - (raymond@es.ele.tue.nl) for the suggestion. - * Add `pad' argument to malloc_trim and top_pad mallopt parameter. - * More precautions for cases where other routines call sbrk, - courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). - * Added macros etc., allowing use in linux libc from - H.J. Lu (hjl@gnu.ai.mit.edu) - * Inverted this history list - - V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) - * Re-tuned and fixed to behave more nicely with V2.6.0 changes. - * Removed all preallocation code since under current scheme - the work required to undo bad preallocations exceeds - the work saved in good cases for most test programs. - * No longer use return list or unconsolidated bins since - no scheme using them consistently outperforms those that don't - given above changes. - * Use best fit for very large chunks to prevent some worst-cases. - * Added some support for debugging - - V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) - * Removed footers when chunks are in use. Thanks to - Paul Wilson (wilson@cs.texas.edu) for the suggestion. - - V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) - * Added malloc_trim, with help from Wolfram Gloger - (wmglo@Dent.MED.Uni-Muenchen.DE). - - V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) - - V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) - * realloc: try to expand in both directions - * malloc: swap order of clean-bin strategy; - * realloc: only conditionally expand backwards - * Try not to scavenge used bins - * Use bin counts as a guide to preallocation - * Occasionally bin return list chunks in first scan - * Add a few optimizations from colin@nyx10.cs.du.edu - - V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) - * faster bin computation & slightly different binning - * merged all consolidations to one part of malloc proper - (eliminating old malloc_find_space & malloc_clean_bin) - * Scan 2 returns chunks (not just 1) - * Propagate failure in realloc if malloc returns 0 - * Add stuff to allow compilation on non-ANSI compilers - from kpv@research.att.com - - V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) - * removed potential for odd address access in prev_chunk - * removed dependency on getpagesize.h - * misc cosmetics and a bit more internal documentation - * anticosmetics: mangled names in macros to evade debugger strangeness - * tested on sparc, hp-700, dec-mips, rs6000 - with gcc & native cc (hp, dec only) allowing - Detlefs & Zorn comparison study (in SIGPLAN Notices.) - - Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) - * Based loosely on libg++-1.2X malloc. (It retains some of the overall - structure of old version, but most details differ.) - -*/ - -#endif diff --git a/Code/CryEngine/CrySystem/CrySystem.rc b/Code/CryEngine/CrySystem/CrySystem.rc deleted file mode 100644 index f3412468f5..0000000000 --- a/Code/CryEngine/CrySystem/CrySystem.rc +++ /dev/null @@ -1,91 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// German (Germany) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) -LANGUAGE LANG_GERMAN, SUBLANG_GERMAN -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,1 - PRODUCTVERSION 1,0,0,1 - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "000904b0" - BEGIN - VALUE "CompanyName", "Amazon.com, Inc." - VALUE "FileVersion", "1, 0, 0, 1" - VALUE "LegalCopyright", "Portions of this file Copyright (c) Amazon.com, Inc. or its affiliates. All Rights Reserved. Original file Copyright (c) Crytek GMBH. Used under license by Amazon.com, Inc. and its affiliates." - VALUE "ProductName", "Lumberyard" - VALUE "ProductVersion", "1, 0, 0, 1" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x9, 1200 - END -END - -#endif // German (Germany) resources -///////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED -#endif // English (United States) resources diff --git a/Code/CryEngine/CrySystem/CryWaterMark.h b/Code/CryEngine/CrySystem/CryWaterMark.h deleted file mode 100644 index 4272b63aab..0000000000 --- a/Code/CryEngine/CrySystem/CryWaterMark.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Header for adding a watermark to an exe, which can then be set -// by the external CryWaterMark program. To use, simply write: -// -// WATERMARKDATA(__blah); -// -// anywhere in the global scope in the program - - -#ifndef CRYINCLUDE_CRYSYSTEM_CRYWATERMARK_H -#define CRYINCLUDE_CRYSYSTEM_CRYWATERMARK_H -#pragma once - - -#define NUMMARKWORDS 10 -#define WATERMARKDATA(name) unsigned int name[] = { 0xDEBEFECA, 0xFABECEDA, 0xADABAFBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -// (the name is such that you can have multiple watermarks in one exe, don't use -// names like "watermark" just incase you accidentally give out an exe with -// debug information). - -#endif // CRYINCLUDE_CRYSYSTEM_CRYWATERMARK_H diff --git a/Code/CryEngine/CrySystem/CustomMemoryHeap.cpp b/Code/CryEngine/CrySystem/CustomMemoryHeap.cpp deleted file mode 100644 index efc03779de..0000000000 --- a/Code/CryEngine/CrySystem/CustomMemoryHeap.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "CustomMemoryHeap.h" - - -#if defined(AZ_RESTRICTED_PLATFORM) -#undef AZ_RESTRICTED_SECTION -#define CUSTOMMEMORYHEAP_CPP_SECTION_1 1 -#define CUSTOMMEMORYHEAP_CPP_SECTION_2 2 -#define CUSTOMMEMORYHEAP_CPP_SECTION_3 3 -#endif - -#if defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION CUSTOMMEMORYHEAP_CPP_SECTION_1 -#include AZ_RESTRICTED_FILE(CustomMemoryHeap_cpp) -#endif - -////////////////////////////////////////////////////////////////////////// -CCustomMemoryHeapBlock::CCustomMemoryHeapBlock(CCustomMemoryHeap* pHeap) - : m_pHeap(pHeap) - , m_pData(0) - , m_nSize(0) - , m_nGPUHandle(0) -{ -} - -////////////////////////////////////////////////////////////////////////// -CCustomMemoryHeapBlock::~CCustomMemoryHeapBlock() -{ - m_pHeap->DeallocateBlock(this); -} - -////////////////////////////////////////////////////////////////////////// -void* CCustomMemoryHeapBlock::GetData() -{ - return m_pData; -} - -////////////////////////////////////////////////////////////////////////// -void CCustomMemoryHeapBlock::CopyMemoryRegion(void* pOutputBuffer, size_t nOffset, size_t nSize) -{ - assert(nOffset + nSize <= m_nSize); - if (nOffset + nSize <= m_nSize) - { - memcpy(pOutputBuffer, (uint8*)m_pData + nOffset, nSize); - } - else - { - CryFatalError("Bad CopyMemoryRegion range"); - } -} - -////////////////////////////////////////////////////////////////////////// -ICustomMemoryBlock* CCustomMemoryHeap::AllocateBlock(size_t const nAllocateSize, char const* const sUsage, size_t const nAlignment /* = 16 */) -{ - CCustomMemoryHeapBlock* pBlock = new CCustomMemoryHeapBlock(this); - pBlock->m_sUsage = sUsage; - pBlock->m_nSize = nAllocateSize; - - switch (m_eAllocPolicy) - { - case IMemoryManager::eapDefaultAllocator: - { - size_t allocated = 0; - pBlock->m_pData = CryMalloc(nAllocateSize, allocated, nAlignment); - break; - } - case IMemoryManager::eapPageMapped: - pBlock->m_pData = CryMemory::AllocPages(nAllocateSize); - break; - case IMemoryManager::eapCustomAlignment: -#if defined(DEBUG) - if (nAlignment == 0) - { - CryFatalError("CCustomMemoryHeap: trying to allocate memory via eapCustomAlignment with an alignment of zero!"); - } -#endif - pBlock->m_pData = CryModuleMemalign(nAllocateSize, nAlignment); - break; -#if defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION CUSTOMMEMORYHEAP_CPP_SECTION_2 -#include AZ_RESTRICTED_FILE(CustomMemoryHeap_cpp) -#endif - default: - CryFatalError("CCustomMemoryHeap: unknown allocation policy during AllocateBlock!"); - break; - } - - CryInterlockedAdd(&m_nAllocatedSize, nAllocateSize); - - return pBlock; -} - -void CCustomMemoryHeap::DeallocateBlock(CCustomMemoryHeapBlock* pBlock) -{ - switch (m_eAllocPolicy) - { - case IMemoryManager::eapDefaultAllocator: - CryFree(pBlock->m_pData, 0); - break; - case IMemoryManager::eapPageMapped: - CryMemory::FreePages(pBlock->m_pData, pBlock->GetSize()); - break; - case IMemoryManager::eapCustomAlignment: - CryModuleMemalignFree(pBlock->m_pData); - break; -#if defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION CUSTOMMEMORYHEAP_CPP_SECTION_3 -#include AZ_RESTRICTED_FILE(CustomMemoryHeap_cpp) -#endif - default: - CryFatalError("CCustomMemoryHeap: unknown allocation policy during DeallocateBlock!"); - break; - } - - int nAllocateSize = (int)pBlock->m_nSize; - CryInterlockedAdd(&m_nAllocatedSize, -nAllocateSize); -} - -////////////////////////////////////////////////////////////////////////// -void CCustomMemoryHeap::GetMemoryUsage(ICrySizer* pSizer) -{ - pSizer->AddObject(this, m_nAllocatedSize); -} - -////////////////////////////////////////////////////////////////////////// -size_t CCustomMemoryHeap::GetAllocated() -{ - return m_nAllocatedSize; -} - -////////////////////////////////////////////////////////////////////////// -CCustomMemoryHeap::CCustomMemoryHeap(IMemoryManager::EAllocPolicy const eAllocPolicy) -{ - m_nAllocatedSize = 0; - m_eAllocPolicy = eAllocPolicy; - m_nTraceHeapHandle = 0; -} - -////////////////////////////////////////////////////////////////////////// -CCustomMemoryHeap::~CCustomMemoryHeap() -{ -} diff --git a/Code/CryEngine/CrySystem/DllMain.cpp b/Code/CryEngine/CrySystem/DllMain.cpp index c3a15812ce..7fd620835b 100644 --- a/Code/CryEngine/CrySystem/DllMain.cpp +++ b/Code/CryEngine/CrySystem/DllMain.cpp @@ -62,46 +62,6 @@ AZ_POP_DISABLE_WARNING } #endif -////////////////////////////////////////////////////////////////////////// -struct CSystemEventListner_System - : public ISystemEventListener -{ -public: - virtual void OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam) - { - switch (event) - { - case ESYSTEM_EVENT_LEVEL_LOAD_START: - case ESYSTEM_EVENT_LEVEL_LOAD_END: - { - CryCleanup(); - break; - } - - case ESYSTEM_EVENT_LEVEL_POST_UNLOAD: - { - CryCleanup(); - STLALLOCATOR_CLEANUP; - break; - } - } - } -}; - -static CSystemEventListner_System g_system_event_listener_system; - -static AZ::EnvironmentVariable s_cryMemoryManager; - - -// Force the CryMemoryManager into the AZ::Environment for exposure to other DLLs -void ExportCryMemoryManager() -{ - IMemoryManager* cryMemoryManager = nullptr; - CryGetIMemoryManagerInterface((void**)&cryMemoryManager); - AZ_Assert(cryMemoryManager, "Unable to resolve CryMemoryManager"); - s_cryMemoryManager = AZ::Environment::CreateVariable("CryIMemoryManagerInterface", cryMemoryManager); -} - extern "C" { CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& startupParams) @@ -113,8 +73,6 @@ CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& startupPar // Environment should have been attached via InjectEnvironment AZ_Assert(AZ::Environment::IsReady(), "Environment is not attached, must be attached before CreateSystemInterface can be called"); - ExportCryMemoryManager(); - pSystem = new CSystem(startupParams.pSharedEnvironment); ModuleInitISystem(pSystem, "CrySystem"); @@ -146,8 +104,6 @@ CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& startupPar return 0; } - pSystem->GetISystemEventDispatcher()->RegisterListener(&g_system_event_listener_system); - return pSystem; } }; diff --git a/Code/CryEngine/CrySystem/GeneralMemoryHeap.cpp b/Code/CryEngine/CrySystem/GeneralMemoryHeap.cpp deleted file mode 100644 index 22a9fa1793..0000000000 --- a/Code/CryEngine/CrySystem/GeneralMemoryHeap.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" - -#include "GeneralMemoryHeap.h" - -#include -#include - -class GeneralMemoryHeapAllocator - : public AZ::SimpleSchemaAllocator -{ - using Base = AZ::SimpleSchemaAllocator; -public: - static const size_t DEFAULT_ALIGNMENT = sizeof(void*); - - GeneralMemoryHeapAllocator(const char* desc) - : Base("GeneralMemoryHeapAllocator", desc) - { - } - - void Reserve(size_t size) - { - // Allocate a block, then free it, forcing it into the page tree/cache - void* block = m_schema->Allocate(size, GeneralMemoryHeapAllocator::DEFAULT_ALIGNMENT, 0, "GeneralMemoryHeapAllocator Reserve", __FILE__, __LINE__); - m_schema->DeAllocate(block); - } -}; - -CGeneralMemoryHeap::CGeneralMemoryHeap([[maybe_unused]] UINT_PTR base, [[maybe_unused]] size_t upperLimit, size_t reserveSize, const char* sUsage) - : m_refCount(0) - , m_block(nullptr) - , m_blockSize(0) -{ - AZ::HphaSchema::Descriptor desc; - desc.m_subAllocator = &AZ::AllocatorInstance::Get(); - m_allocator.reset(new AZ::AllocatorWrapper); - m_allocator->Create(desc, sUsage); - if (reserveSize) - { - (*m_allocator)->Reserve(reserveSize); - } -} - -CGeneralMemoryHeap::CGeneralMemoryHeap(void* base, size_t size, const char* sUsage) - : m_refCount(0) - , m_block(base) - , m_blockSize(size) -{ - AZ::HphaSchema::Descriptor desc; - desc.m_fixedMemoryBlock = base; - desc.m_fixedMemoryBlockByteSize = size; - desc.m_fixedMemoryBlockAlignment = GeneralMemoryHeapAllocator::DEFAULT_ALIGNMENT; - m_allocator.reset(new AZ::AllocatorWrapper); - m_allocator->Create(desc, sUsage); -} - -CGeneralMemoryHeap::~CGeneralMemoryHeap() -{ -} - -bool CGeneralMemoryHeap::Cleanup() -{ - (*m_allocator)->GarbageCollect(); - return true; -} - -int CGeneralMemoryHeap::AddRef() -{ - return m_refCount.fetch_add(1); -} - -int CGeneralMemoryHeap::Release() -{ - int nRef = m_refCount.fetch_sub(1); - - if (nRef <= 1) - { - delete this; - } - - return nRef; -} - -void CGeneralMemoryHeap::RecordAlloc(void* ptr, size_t size) -{ - if (m_block == nullptr) - { - m_allocs.emplace(ptr, size); - } -} - -void CGeneralMemoryHeap::RecordFree(void* ptr, size_t size) -{ - if (m_block == nullptr) - { - m_allocs.erase(Alloc(ptr, size)); - } -} - -bool CGeneralMemoryHeap::IsInAddressRange(void* ptr) const -{ - if (m_block) - { - return (static_cast(ptr) - static_cast(m_block)) <= m_blockSize; - } - auto it = m_allocs.find(Alloc(ptr)); - return it != m_allocs.end(); -} - -void* CGeneralMemoryHeap::Calloc(size_t numElements, size_t size, const char* sUsage) -{ - void* ptr = (*m_allocator)->Allocate(numElements * size, GeneralMemoryHeapAllocator::DEFAULT_ALIGNMENT, 0, sUsage, __FILE__, __LINE__); - memset(ptr, 0, numElements * size); - RecordAlloc(ptr, numElements * size); - return ptr; -} - -void* CGeneralMemoryHeap::Malloc(size_t size, const char* sUsage) -{ - void* ptr = (*m_allocator)->Allocate(size, GeneralMemoryHeapAllocator::DEFAULT_ALIGNMENT, 0, sUsage, __FILE__, __LINE__); - RecordAlloc(ptr, size); - return ptr; -} - -size_t CGeneralMemoryHeap::Free(void* ptr) -{ - // The client code using these heaps tend to use a guesswork algorithm to freeing - // which involves handing the pointer to every known heap until it frees, so - // it's necessary to validate that the ptr belongs to this heap before attempting to free - if (IsInAddressRange(ptr)) - { - size_t size = (*m_allocator)->AllocationSize(ptr); - RecordFree(ptr, size); - (*m_allocator)->DeAllocate(ptr); - return size; - } - return 0; -} - -void* CGeneralMemoryHeap::Realloc(void* ptr, size_t size, const char* /*sUsage*/) -{ - RecordFree(ptr, (*m_allocator)->AllocationSize(ptr)); - void* newPtr = (*m_allocator)->ReAllocate(ptr, size, GeneralMemoryHeapAllocator::DEFAULT_ALIGNMENT); - RecordAlloc(newPtr, size); - return newPtr; -} - -void* CGeneralMemoryHeap::ReallocAlign(void* ptr, size_t size, size_t alignment, const char* /*sUsage*/) -{ - RecordFree(ptr, (*m_allocator)->AllocationSize(ptr)); - void* newPtr = (*m_allocator)->ReAllocate(ptr, size, alignment); - RecordAlloc(newPtr, size); - return newPtr; -} - -void* CGeneralMemoryHeap::Memalign(size_t boundary, size_t size, const char* sUsage) -{ - void* ptr = (*m_allocator)->Allocate(size, boundary, 0, sUsage, __FILE__, __LINE__); - RecordAlloc(ptr, size); - return ptr; -} - -size_t CGeneralMemoryHeap::UsableSize(void* ptr) const -{ - // The client code using these heaps tend to use a guesswork algorithm to determine - // which heap owns the pointer. Calls to UsableSize() are a part of this guesswork. - // The overrun detector doesn't play nicely on AllocationSize() lookups for pointers that - // don't belong to the heap, so validate that we're in the correct address range before trying - // to look up the size. - return IsInAddressRange(ptr) ? (*m_allocator)->AllocationSize(ptr) : 0; -} - -AZ::IAllocator* CGeneralMemoryHeap::GetAllocator() const -{ - return m_allocator->Get(); -} diff --git a/Code/CryEngine/CrySystem/GeneralMemoryHeap.h b/Code/CryEngine/CrySystem/GeneralMemoryHeap.h deleted file mode 100644 index a09556055d..0000000000 --- a/Code/CryEngine/CrySystem/GeneralMemoryHeap.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_GENERALMEMORYHEAP_H -#define CRYINCLUDE_CRYSYSTEM_GENERALMEMORYHEAP_H -#pragma once - - -#include "IMemory.h" -#include -#include -#include - -class GeneralMemoryHeapAllocator; - -class CGeneralMemoryHeap - : public IGeneralMemoryHeap -{ - struct Alloc - { - void* m_base; - size_t m_size; - - Alloc(void* base = nullptr, size_t size = 0) - : m_base(base) - , m_size(size) - {} - - bool operator==(const Alloc& rhs) const - { - // size doesn't matter - return m_base == rhs.m_base; - } - - bool operator<(const Alloc& rhs) const - { - // this will cause allocs to be sorted by address - return m_base < rhs.m_base; - } - }; - -public: - // Create a heap that will map/unmap pages in the range [baseAddress, baseAddress + upperLimit). - CGeneralMemoryHeap(UINT_PTR baseAddress, size_t upperLimit, size_t reserveSize, const char* sUsage); - - // Create a heap that will assumes all memory in the range [base, base + size) is already mapped. - CGeneralMemoryHeap(void* base, size_t size, const char* sUsage); - - ~CGeneralMemoryHeap(); - -public: // IGeneralMemoryHeap Members - bool Cleanup(); - - int AddRef(); - int Release(); - - bool IsInAddressRange(void* ptr) const; - - void* Calloc(size_t nmemb, size_t size, const char* sUsage = NULL); - void* Malloc(size_t sz, const char* sUsage = NULL); - size_t Free(void* ptr); - void* Realloc(void* ptr, size_t sz, const char* sUsage = NULL); - void* ReallocAlign(void* ptr, size_t size, size_t alignment, const char* sUsage = NULL); - void* Memalign(size_t boundary, size_t size, const char* sUsage = NULL); - size_t UsableSize(void* ptr) const; - - AZ::IAllocator* GetAllocator() const override; - -private: - CGeneralMemoryHeap(const CGeneralMemoryHeap&) = delete; - CGeneralMemoryHeap& operator = (const CGeneralMemoryHeap&) = delete; - - void RecordAlloc(void* ptr, size_t size); - void RecordFree(void* ptr, size_t size); - -private: - AZStd::unique_ptr> m_allocator; - AZStd::atomic_int m_refCount; - void* m_block; - size_t m_blockSize; - AZStd::set, AZ::AZStdAlloc> m_allocs; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_GENERALMEMORYHEAP_H diff --git a/Code/CryEngine/CrySystem/HandlerBase.cpp b/Code/CryEngine/CrySystem/HandlerBase.cpp deleted file mode 100644 index 6e1b7fdc77..0000000000 --- a/Code/CryEngine/CrySystem/HandlerBase.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" - -#include "ProjectDefines.h" -#if defined(MAP_LOADING_SLICING) - -#include "HandlerBase.h" - -const char* SERVER_LOCK_NAME = "SynchronizeGameServer"; -const char* CLIENT_LOCK_NAME = "SynchronizeGameClient"; - -HandlerBase::HandlerBase(const char* bucket, int affinity) -{ - m_serverLockName.Format("%s_%s", SERVER_LOCK_NAME, bucket); - m_clientLockName.Format("%s_%s", CLIENT_LOCK_NAME, bucket); - if (affinity != 0) - { - m_affinity = uint32(1) << (affinity - 1); - } - else - { - m_affinity = -1; - } - m_prevAffinity = 0; -} - -HandlerBase::~HandlerBase() -{ - if (m_prevAffinity) - { - if (SyncSetAffinity(m_prevAffinity)) - { - CryLogAlways("Restored affinity to %d", m_prevAffinity); - } - else - { - CryLogAlways("Failed to restore affinity to %d", m_prevAffinity); - } - } -} - -void HandlerBase::SetAffinity() -{ - if (m_prevAffinity) //already set - { - return; - } - if (uint32 p = SyncSetAffinity(m_affinity)) - { - CryLogAlways("Changed affinity to %d", m_affinity); - m_prevAffinity = p; - } - else - { - CryLogAlways("Failed to change affinity to %d", m_affinity); - } -} - -#if defined(LINUX) - -uint32 HandlerBase::SyncSetAffinity(uint32 cpuMask)//put -1 -{ - if (cpuMask != 0) - { - cpu_set_t cpuSet; - uint32 affinity = 0; - if (!sched_getaffinity(getpid(), sizeof cpuSet, &cpuSet)) - { - for (int cpu = 0; cpu < sizeof(cpuMask) * 8; ++cpu) - { - if (CPU_ISSET(cpu, &cpuSet)) - { - affinity |= 1 << cpu; - } - } - } - if (affinity) - { - CPU_ZERO(&cpuSet); - for (int cpu = 0; cpu < sizeof(cpuMask) * 8; ++cpu) - { - if (cpuMask & (1 << cpu)) - { - CPU_SET(cpu, &cpuSet); - } - } - - if (!sched_setaffinity(getpid(), sizeof(cpuSet), &cpuSet)) - { - return affinity; - } - } - } - return 0; -} - -#elif AZ_LEGACY_CRYSYSTEM_TRAIT_USE_HANDLER_SYNC_AFFINITY - -uint32 HandlerBase::SyncSetAffinity(uint32 cpuMask)//put -1 -{ - uint32 p = (uint32)SetThreadAffinityMask(GetCurrentThread(), cpuMask); - if (p == 0) - { - CryLogAlways("Error updating affinity mask to %d", cpuMask); - } - return p; -} - -#else - -uint32 HandlerBase::SyncSetAffinity(uint32 cpuMask)//put -1 -{ - CryLogAlways("Updating thread affinity not supported on this platform"); - return 0; -} - -#endif - -#endif // defined(MAP_LOADING_SLICING) diff --git a/Code/CryEngine/CrySystem/HandlerBase.h b/Code/CryEngine/CrySystem/HandlerBase.h deleted file mode 100644 index 67e7a828a6..0000000000 --- a/Code/CryEngine/CrySystem/HandlerBase.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_HANDLERBASE_H -#define CRYINCLUDE_CRYSYSTEM_HANDLERBASE_H - -#pragma once - -const int MAX_CLIENTS_NUM = 100; - -struct HandlerBase -{ - HandlerBase(const char* bucket, int affinity); - ~HandlerBase(); - - void SetAffinity(); - uint32 SyncSetAffinity(uint32 cpuMask); - - string m_serverLockName; - string m_clientLockName; - uint32 m_affinity; - uint32 m_prevAffinity; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_HANDLERBASE_H diff --git a/Code/CryEngine/CrySystem/IOSConsole.h b/Code/CryEngine/CrySystem/IOSConsole.h deleted file mode 100644 index 8bd2a8779e..0000000000 --- a/Code/CryEngine/CrySystem/IOSConsole.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Console implementation for iOS, reports back to the main interface - -#pragma once - -#include -#include - -class CIOSConsole - : public ISystemUserCallback - , public IOutputPrintSink - , public ITextModeConsole -{ - CIOSConsole(const CIOSConsole&); - CIOSConsole& operator = (const CIOSConsole&); - - bool m_isInitialized; -public: - static CryCriticalSectionNonRecursive s_lock; -public: - CIOSConsole(); - ~CIOSConsole(); - - // Interface IOutputPrintSink ///////////////////////////////////////////// - DLL_EXPORT virtual void Print(const char* line); - - // Interface ISystemUserCallback ////////////////////////////////////////// - virtual bool OnError(const char* errorString); - virtual bool OnSaveDocument() { return false; } - virtual void OnProcessSwitch() { } - virtual void OnInitProgress(const char* sProgressMsg); - virtual void OnInit(ISystem*); - virtual void OnShutdown(); - virtual void OnUpdate(); - virtual void GetMemoryUsage(ICrySizer* pSizer); - void SetRequireDedicatedServer(bool) {} - void SetHeader(const char*) {} - // Interface ITextModeConsole ///////////////////////////////////////////// - virtual Vec2_tpl BeginDraw(); - virtual void PutText(int x, int y, const char* msg); - virtual void EndDraw(); -}; diff --git a/Code/CryEngine/CrySystem/IOSConsole.mm b/Code/CryEngine/CrySystem/IOSConsole.mm deleted file mode 100644 index 6058ea8a44..0000000000 --- a/Code/CryEngine/CrySystem/IOSConsole.mm +++ /dev/null @@ -1,94 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#if defined(IOS) -#include "IOSConsole.h" - - - -CIOSConsole::CIOSConsole(): -m_isInitialized(false) -{ - -} - -CIOSConsole::~CIOSConsole() -{ - -} - -// Interface IOutputPrintSink ///////////////////////////////////////////// -void CIOSConsole::Print(const char *line) -{ - printf("MSG: %s\n", line); -} -// Interface ISystemUserCallback ////////////////////////////////////////// -bool CIOSConsole::OnError(const char *errorString) -{ - printf("ERR: %s\n", errorString); - return true; -} - -void CIOSConsole::OnInitProgress(const char *sProgressMsg) -{ - (void) sProgressMsg; - // Do Nothing -} -void CIOSConsole::OnInit(ISystem *pSystem) -{ - if (!m_isInitialized) - { - IConsole* pConsole = pSystem->GetIConsole(); - if (pConsole != 0) - { - pConsole->AddOutputPrintSink(this); - } - m_isInitialized = true; - } -} -void CIOSConsole::OnShutdown() -{ - if (m_isInitialized) - { - // remove outputprintsink - m_isInitialized = false; - } -} -void CIOSConsole::OnUpdate() -{ - // Do Nothing -} -void CIOSConsole::GetMemoryUsage(ICrySizer *pSizer) -{ - size_t size = sizeof(*this); - - - - pSizer->AddObject(this, size); -} - -// Interface ITextModeConsole ///////////////////////////////////////////// -Vec2_tpl CIOSConsole::BeginDraw() -{ - return Vec2_tpl(0,0); -} -void CIOSConsole::PutText( int x, int y, const char * msg ) -{ - printf("PUT: %s\n", msg); -} -void CIOSConsole::EndDraw() { - // Do Nothing -} -#endif // IOS diff --git a/Code/CryEngine/CrySystem/ImageHandler.cpp b/Code/CryEngine/CrySystem/ImageHandler.cpp deleted file mode 100644 index 7444aebdc0..0000000000 --- a/Code/CryEngine/CrySystem/ImageHandler.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "CrySystem_precompiled.h" -#include -#include "ImageHandler.h" -#include -#include "ScopeGuard.h" -#include "Algorithm.h" -#include "System.h" - -#if defined(AZ_RESTRICTED_PLATFORM) -#include AZ_RESTRICTED_FILE(ImageHandler_cpp) -#endif - -#if !(defined(ANDROID) || defined(IOS) || defined(LINUX)) && AZ_LEGACY_CRYSYSTEM_TRAIT_IMAGEHANDLER_TIFFIO // Rally US1050 - Compile libtiff for Android and IOS - #include - -static_assert(sizeof(thandle_t) >= sizeof(AZ::IO::HandleType), "Platform defines thandle_t to be smaller than required"); -#endif - -namespace -{ - class Image - : public IImageHandler::IImage - { - public: - Image(std::vector&& data, int width, int height) - { - CRY_ASSERT(data.size() == width * height * ImageHandler::c_BytesPerPixel); - m_data = std::move(data); - m_width = width; - m_height = height; - } - private: - virtual const std::vector& GetData() const override { return m_data; } - virtual int GetWidth() const override { return m_width; } - virtual int GetHeight() const override { return m_height; } - - unsigned int m_width; - unsigned int m_height; - std::vector m_data; - }; -#if AZ_LEGACY_CRYSYSTEM_TRAIT_IMAGEHANDLER_TIFFIO - struct TiffIO - { - static tsize_t Read(thandle_t handle, tdata_t buffer, tsize_t size) - { - AZ::u64 bytesRead = 0; - AZ::IO::FileIOBase::GetDirectInstance()->Read(static_cast(reinterpret_cast(handle)), buffer, size, false, &bytesRead); - return static_cast(bytesRead); - }; - - static tsize_t Write(thandle_t handle, tdata_t buffer, tsize_t size) - { - AZ::u64 sizeWritten; - if (AZ::IO::FileIOBase::GetDirectInstance()->Write(static_cast(reinterpret_cast(handle)), buffer, size, &sizeWritten)) - { - return static_cast(sizeWritten); - } - else - { - return 0; - } - }; - - static int Close(thandle_t handle) - { - AZ::IO::FileIOBase::GetDirectInstance()->Close(static_cast(reinterpret_cast(handle))); - return 0; - }; - - static toff_t Seek(thandle_t handle, toff_t pos, int mode) - { - if (AZ::IO::FileIOBase::GetDirectInstance()->Seek(static_cast(reinterpret_cast(handle)), static_cast(pos), AZ::IO::GetSeekTypeFromFSeekMode(mode))) - { - if (mode == SEEK_SET) - { - return pos; - } - else - { - AZ::u64 offsetFromBegin; - if (AZ::IO::FileIOBase::GetDirectInstance()->Tell(static_cast(reinterpret_cast(handle)), offsetFromBegin)) - { - return static_cast(offsetFromBegin); - } - else - { - return -1; - } - } - } - return -1; - }; - - static toff_t Size(thandle_t handle) - { - AZ::u64 fileSize = 0; - AZ::IO::FileIOBase::GetDirectInstance()->Size(static_cast(reinterpret_cast(handle)), fileSize); - return static_cast(fileSize); - }; - - static int Map(thandle_t, tdata_t*, toff_t*) - { - return 0; - }; - - static void Unmap(thandle_t, tdata_t, toff_t) - { - return; - }; - }; -#endif -} - -std::unique_ptr ImageHandler::CreateImage(std::vector&& data, int width, int height) const -{ - return std::make_unique(std::move(data), width, height); -} - -std::unique_ptr ImageHandler::LoadImage([[maybe_unused]] const char* filename) const -{ -#if AZ_LEGACY_CRYSYSTEM_TRAIT_IMAGEHANDLER_TIFFIO - - AZ::IO::HandleType fileHandle; - AZ::IO::FileIOBase::GetDirectInstance()->Open(filename, AZ::IO::GetOpenModeFromStringMode("rb"), fileHandle); - - if (fileHandle == AZ::IO::InvalidHandle) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to open image file %s", filename); - return nullptr; - } - - auto tifHandle = std17::unique_resource_checked(TIFFClientOpen(filename, "rb", reinterpret_cast(static_cast(fileHandle)), TiffIO::Read, TiffIO::Write, TiffIO::Seek, TiffIO::Close, &TiffIO::Size, TiffIO::Map, TiffIO::Unmap), (TIFF*)nullptr, TIFFClose); - if (!tifHandle) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to load image %s", filename); - return nullptr; - } - - int width = 0; - int height = 0; - TIFFGetField(tifHandle, TIFFTAG_IMAGEWIDTH, &width); - TIFFGetField(tifHandle, TIFFTAG_IMAGELENGTH, &height); - std::vector data(4 * width * height); - if (!TIFFReadRGBAImageOriented(tifHandle, width, height, reinterpret_cast(data.data()), ORIENTATION_TOPLEFT)) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to load image %s", filename); - return nullptr; - } - - //strip alpha - int every4th = 0; - data.erase(std::remove_if(begin(data), end(data), [&](unsigned char) - { - return (every4th++ & 3) == 3; - }), end(data)); - - return std::make_unique(std::move(data), width, height); -#else - CRY_ASSERT(0); // UNIMPLEMENTED - return nullptr; -#endif -} - -bool ImageHandler::SaveImage([[maybe_unused]] IImageHandler::IImage* image, [[maybe_unused]] const char* filename) const -{ -#if AZ_LEGACY_CRYSYSTEM_TRAIT_IMAGEHANDLER_TIFFIO - - AZ::IO::HandleType fileHandle; - AZ::IO::FileIOBase::GetDirectInstance()->Open(filename, AZ::IO::GetOpenModeFromStringMode("wb"), fileHandle); - - if (fileHandle == AZ::IO::InvalidHandle) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to open image file for write %s", filename); - return false; - } - - auto tifHandle = std17::unique_resource_checked(TIFFClientOpen(filename, "wb", reinterpret_cast(static_cast(fileHandle)), TiffIO::Read, TiffIO::Write, TiffIO::Seek, TiffIO::Close, &TiffIO::Size, TiffIO::Map, TiffIO::Unmap), (TIFF*)nullptr, TIFFClose); - if (!tifHandle) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to save image %s", filename); - return false; - } - - TIFFSetField(tifHandle, TIFFTAG_IMAGEWIDTH, image->GetWidth()); - TIFFSetField(tifHandle, TIFFTAG_IMAGELENGTH, image->GetHeight()); - TIFFSetField(tifHandle, TIFFTAG_SAMPLESPERPIXEL, c_BytesPerPixel); - TIFFSetField(tifHandle, TIFFTAG_BITSPERSAMPLE, 8); - TIFFSetField(tifHandle, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tifHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tifHandle, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); - TIFFSetField(tifHandle, TIFFTAG_COMPRESSION, COMPRESSION_LZW); - - tsize_t bytesPerLine = c_BytesPerPixel * image->GetWidth(); - std::vector lineBuffer; - if (TIFFScanlineSize(tifHandle) != bytesPerLine) - { - lineBuffer.resize(bytesPerLine); - } - else - { - lineBuffer.resize(TIFFScanlineSize(tifHandle)); - } - TIFFSetField(tifHandle, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tifHandle, image->GetWidth() * c_BytesPerPixel)); - auto srcData = image->GetData().data(); - - for (uint32 row = 0; row < image->GetHeight(); row++) - { - memcpy(lineBuffer.data(), &srcData[row * bytesPerLine], bytesPerLine); - if (TIFFWriteScanline(tifHandle, lineBuffer.data(), row, 0) < 0) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Failed to write part of image %s", filename); - return false; - } - } - - return true; -#else - CRY_ASSERT(0); // UNIMPLEMENTED - return false; -#endif -} - -std::unique_ptr ImageHandler::CreateDiffImage(IImageHandler::IImage* image1, IImageHandler::IImage* image2) const -{ - if (!image1 || !image2) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not create diff image, null arguments"); - return nullptr; - } - if (image1->GetWidth() != image2->GetWidth() || image1->GetHeight() != image2->GetHeight()) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not create diff image, 2 images were not the same size"); - return nullptr; - } - CRY_ASSERT(image1->GetData().size() == image1->GetWidth() * image1->GetHeight() * ImageHandler::c_BytesPerPixel); - CRY_ASSERT(image2->GetData().size() == image2->GetWidth() * image2->GetHeight() * ImageHandler::c_BytesPerPixel); - - std::vector resultRGBData; - - auto iter1 = image1->GetData().data(); - auto iter2 = image2->GetData().data(); - for (int i = 0; i < image1->GetWidth() * image1->GetHeight() * c_BytesPerPixel; ++i) - { - resultRGBData.push_back(static_cast(abs(static_cast(iter1[i]) - static_cast(iter2[i])))); - } - - return std::make_unique(std::move(resultRGBData), image1->GetWidth(), image1->GetHeight()); -} - -float ImageHandler::CalculatePSNR(IImageHandler::IImage* diffIimage) const -{ - if (!diffIimage) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not create diff image, null arguments"); - return 0; - } - CRY_ASSERT(diffIimage->GetData().size() == diffIimage->GetWidth() * diffIimage->GetHeight() * ImageHandler::c_BytesPerPixel); - - auto mse = std17::accumulate(diffIimage->GetData(), 0.0, [](double result, unsigned char value) -> double { return result += (double)value * (double)value; }); - mse /= (c_BytesPerPixel * diffIimage->GetWidth() * diffIimage->GetHeight()); - - if (mse <= 0) - { - return std::numeric_limits::max(); - } - - // see http://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio for a derivation of this formula and source for magic numbers - return static_cast(20 * log10(255) - 10 * log10(mse)); -} diff --git a/Code/CryEngine/CrySystem/ImageHandler.h b/Code/CryEngine/CrySystem/ImageHandler.h deleted file mode 100644 index bba596a266..0000000000 --- a/Code/CryEngine/CrySystem/ImageHandler.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#pragma once -#ifndef CRYINCLUDE_CRYSYSTEM_IMAGEHANDLER_H -#define CRYINCLUDE_CRYSYSTEM_IMAGEHANDLER_H - -#include "IImageHandler.h" - -class ImageHandler - : public IImageHandler -{ -public: - static const int c_BytesPerPixel = 3; //This only deals with RGB data for now, no alpha -private: - virtual std::unique_ptr CreateImage(std::vector&& rgbData, int width, int height) const override; - virtual std::unique_ptr LoadImage(const char* filename) const override; - virtual bool SaveImage(IImageHandler::IImage* image, const char* filename) const override; - virtual std::unique_ptr CreateDiffImage(IImageHandler::IImage* image1, IImageHandler::IImage* image2) const override; - virtual float CalculatePSNR(IImageHandler::IImage* diffIimage) const override; -}; -#endif // CRYINCLUDE_CRYSYSTEM_IMAGEHANDLER_H diff --git a/Code/CryEngine/CrySystem/LZ4Decompressor.cpp b/Code/CryEngine/CrySystem/LZ4Decompressor.cpp deleted file mode 100644 index a4b8a2b8e6..0000000000 --- a/Code/CryEngine/CrySystem/LZ4Decompressor.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : lz4 hc decompress wrapper - - -#include "CrySystem_precompiled.h" -#include -#include "LZ4Decompressor.h" - -bool CLZ4Decompressor::DecompressData(const char* pIn, char* pOut, const uint outputSize) const -{ - return LZ4_decompress_fast(pIn, pOut, outputSize) >= 0; -} - -void CLZ4Decompressor::Release() -{ - delete this; -} diff --git a/Code/CryEngine/CrySystem/LZ4Decompressor.h b/Code/CryEngine/CrySystem/LZ4Decompressor.h deleted file mode 100644 index 20652a8e78..0000000000 --- a/Code/CryEngine/CrySystem/LZ4Decompressor.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : lz4 hc decompress wrapper - - -#ifndef CRYINCLUDE_CRYSYSTEM_LZ4DECOMPRESSOR_H -#define CRYINCLUDE_CRYSYSTEM_LZ4DECOMPRESSOR_H -#pragma once - - -#include "ILZ4Decompressor.h" - -class CLZ4Decompressor - : public ILZ4Decompressor -{ -public: - virtual bool DecompressData(const char* pIn, char* pOut, const uint outputSize) const; - virtual void Release(); - -private: - virtual ~CLZ4Decompressor() {} -}; - -#endif // CRYINCLUDE_CRYSYSTEM_LZ4DECOMPRESSOR_H diff --git a/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp b/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp index 0af52d8cc4..68fc4b558a 100644 --- a/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp +++ b/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp @@ -17,7 +17,6 @@ #include "LevelSystem.h" #include #include "IMovieSystem.h" -#include #include #include "CryPath.h" #include @@ -261,16 +260,6 @@ void CLevelSystem::Rescan(const char* levelsFolder) { if (levelsFolder) { - if (const ICmdLineArg* pModArg = m_pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "MOD")) - { - if (m_pSystem->IsMODValid(pModArg->GetValue())) - { - m_levelsFolder.format("Mods/%s/%s", pModArg->GetValue(), levelsFolder); - m_levelInfos.clear(); - ScanFolder(0, true); - } - } - m_levelsFolder = levelsFolder; } @@ -778,9 +767,6 @@ void CLevelSystem::PrepareNextLevel(const char* levelName) // switched to level heap, so now imm start the loading screen (renderer will be reinitialized in the levelheap) gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_LOAD_START_LOADINGSCREEN, 0, 0); gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_PREPARE); - - // Inform resource manager about loading of the new level. - GetISystem()->GetIResourceManager()->PrepareLevel(pLevelInfo->GetPath(), pLevelInfo->GetName()); } for (AZStd::vector::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) @@ -987,8 +973,6 @@ void CLevelSystem::UnloadLevel() m_lastLevelName.clear(); - GetISystem()->GetIResourceManager()->UnloadLevel(); - SAFE_RELEASE(m_pCurrentLevel); // Force Lua garbage collection (may no longer be needed now the legacy renderer has been removed). diff --git a/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp b/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp index 8b3c75cce2..ff6ebc0d17 100644 --- a/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp +++ b/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp @@ -14,7 +14,6 @@ #include "SpawnableLevelSystem.h" #include #include "IMovieSystem.h" -#include #include @@ -566,8 +565,6 @@ namespace LegacyLevelSystem m_lastLevelName.clear(); - GetISystem()->GetIResourceManager()->UnloadLevel(); - // Force Lua garbage collection (may no longer be needed now the legacy renderer has been removed). // Normally the GC step is triggered at the end of this method (by the ESYSTEM_EVENT_LEVEL_POST_UNLOAD event). EBUS_EVENT(AZ::ScriptSystemRequestBus, GarbageCollect); diff --git a/Code/CryEngine/CrySystem/Log.cpp b/Code/CryEngine/CrySystem/Log.cpp index c51947d8bc..c37e12cebd 100644 --- a/Code/CryEngine/CrySystem/Log.cpp +++ b/Code/CryEngine/CrySystem/Log.cpp @@ -20,7 +20,6 @@ //this should not be included here #include #include -#include #include "System.h" #include "CryPath.h" // PathUtil::ReplaceExtension() #include @@ -418,7 +417,7 @@ void CLog::LogV(const ELogType type, const char* szFormat, va_list args) LogV(type, 0, szFormat, args); } -void CLog::LogV(const ELogType type, int flags, const char* szFormat, va_list args) +void CLog::LogV(const ELogType type, [[maybe_unused]]int flags, const char* szFormat, va_list args) { // this is here in case someone called LogV directly, with an invalid formatter. if (!CheckLogFormatter(szFormat)) @@ -596,28 +595,6 @@ void CLog::LogV(const ELogType type, int flags, const char* szFormat, va_list ar GetISystem()->GetIRemoteConsole()->AddLogError(szString); break; } - - ////////////////////////////////////////////////////////////////////////// - if (type == eWarningAlways || type == eWarning || type == eError || type == eErrorAlways) - { - IValidator* pValidator = m_pSystem->GetIValidator(); - if (pValidator && (flags & VALIDATOR_FLAG_SKIP_VALIDATOR) == 0) - { - CryAutoCriticalSection scope_lock(m_logCriticalSection); - - SValidatorRecord record; - record.text = szBuffer; - record.module = VALIDATOR_MODULE_SYSTEM; - record.severity = VALIDATOR_WARNING; - record.assetScope = GetAssetScopeString(); - record.flags = flags; - if (type == eError || type == eErrorAlways) - { - record.severity = VALIDATOR_ERROR; - } - pValidator->Report(record); - } - } } //will log the text both to the end of file and console @@ -1439,22 +1416,6 @@ void CLog::UpdateLoadingScreen(const char* szFormat, ...) va_end(args); } #endif - - if (CryGetCurrentThreadId() == m_nMainThreadId) - { -#ifndef LINUX - // Take this opportunity to update streaming engine. - if (IStreamEngine* pStreamEngine = GetISystem()->GetStreamEngine()) - { - const float curTime = m_pSystem->GetITimer()->GetAsyncCurTime(); - if (curTime - m_fLastLoadingUpdateTime > .1f) // not frequent than once in 100ms - { - m_fLastLoadingUpdateTime = curTime; - pStreamEngine->Update(); - } - } -#endif - } } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/CryEngine/CrySystem/MTSafeAllocator.cpp b/Code/CryEngine/CrySystem/MTSafeAllocator.cpp deleted file mode 100644 index 7d9c08d3c4..0000000000 --- a/Code/CryEngine/CrySystem/MTSafeAllocator.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "MTSafeAllocator.h" -#include - -extern CMTSafeHeap* g_pPakHeap; - -// Uncomment this define to enable time tracing of the MTSAFE heap -#define MTSAFE_PROFILE 1 -//#undef MTSAFE_PROFILE - -namespace -{ - class CSimpleTimer - { - LARGE_INTEGER& m_result; - LARGE_INTEGER m_start; - public: - - CSimpleTimer(LARGE_INTEGER& li) - : m_result(li) - { QueryPerformanceCounter(&m_start); } - - ~CSimpleTimer() - { - LARGE_INTEGER end; - QueryPerformanceCounter(&end); - m_result.QuadPart = end.QuadPart - m_start.QuadPart; - } - }; -}; - -////////////////////////////////////////////////////////////////////////// -CMTSafeHeap::CMTSafeHeap() - : m_LiveTempAllocations() - , m_TotalAllocations() - , m_TempAllocationsFailed() - , m_TempAllocationsTime() -{ - size_t allocated = 0; - m_pGeneralHeapStorage = (char*)CryMalloc(MTSAFE_GENERAL_HEAP_SIZE, allocated, MTSAFE_DEFAULT_ALIGNMENT); - m_pGeneralHeapStorageEnd = m_pGeneralHeapStorage + MTSAFE_GENERAL_HEAP_SIZE; - m_pGeneralHeap = CryGetIMemoryManager()->CreateGeneralMemoryHeap(m_pGeneralHeapStorage, MTSAFE_GENERAL_HEAP_SIZE, "MTSafeHeap"); -} - -////////////////////////////////////////////////////////////////////////// -CMTSafeHeap::~CMTSafeHeap() -{ - SAFE_RELEASE(m_pGeneralHeap); - CryFree(m_pGeneralHeapStorage, MTSAFE_DEFAULT_ALIGNMENT); -} - -////////////////////////////////////////////////////////////////////////// -size_t CMTSafeHeap::PersistentAllocSize(size_t nSize) -{ - return nSize; -} - -////////////////////////////////////////////////////////////////////////// -void* CMTSafeHeap::PersistentAlloc(size_t nSize) -{ - size_t allocated = 0; - return CryMalloc(nSize, allocated, MTSAFE_DEFAULT_ALIGNMENT); -} - -////////////////////////////////////////////////////////////////////////// -void CMTSafeHeap::FreePersistent(void* p) -{ - CryFree(p, MTSAFE_DEFAULT_ALIGNMENT); -} - -////////////////////////////////////////////////////////////////////////// -void* CMTSafeHeap::TempAlloc(size_t nSize, const char* szDbgSource, bool& bFallBackToMalloc, uint32 align) -{ -# if MTSAFE_PROFILE - CSimpleTimer timer(m_TempAllocationsTime); -# endif - - void* ptr = NULL; - if (align) - { - ptr = m_pGeneralHeap->Memalign(align, nSize, szDbgSource); - } - else - { - ptr = m_pGeneralHeap->Malloc(nSize, szDbgSource); - } - - //explicit alignment not supported beyond this point, safer to return NULL - if (ptr || !bFallBackToMalloc) - { - bFallBackToMalloc = false; - return ptr; - } - - bFallBackToMalloc = true; - -# if MTSAFE_PROFILE - CryInterlockedAdd((volatile int*)&m_TempAllocationsFailed, (int)nSize); -# endif - - return CryModuleMemalign(nSize, align > 0 ? align : MTSAFE_DEFAULT_ALIGNMENT); -} - -////////////////////////////////////////////////////////////////////////// -void CMTSafeHeap::FreeTemporary(void* p) -{ -# if MTSAFE_PROFILE - CSimpleTimer timer(m_TempAllocationsTime); -# endif - - if (m_pGeneralHeap->IsInAddressRange(p)) - { - m_pGeneralHeap->Free(p); - return; - } - - // Fallback to free - CryModuleMemalignFree(p); -} - -////////////////////////////////////////////////////////////////////////// -void* CMTSafeHeap::StaticAlloc([[maybe_unused]] void* pOpaque, unsigned nItems, unsigned nSize) -{ - return g_pPakHeap->TempAlloc(nItems * nSize, "StaticAlloc"); -} - -////////////////////////////////////////////////////////////////////////// -void CMTSafeHeap::StaticFree ([[maybe_unused]] void* pOpaque, void* pAddress) -{ - g_pPakHeap->FreeTemporary(pAddress); -} - -////////////////////////////////////////////////////////////////////////// -void CMTSafeHeap::GetMemoryUsage(ICrySizer* pSizer) -{ - SIZER_COMPONENT_NAME(pSizer, "FileSystem Pool"); -} - -void CMTSafeHeap::PrintStats() -{ -# if MTSAFE_PROFILE - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - const double rFreq = 1. / static_cast(freq.QuadPart); - - CryLogAlways("mtsafe temporary pool failed for %" PRISIZE_T " bytes, time spent in allocations %3.08f seconds", - m_TempAllocationsFailed, static_cast(m_TempAllocationsTime.QuadPart) * rFreq); -# endif -} - diff --git a/Code/CryEngine/CrySystem/MTSafeAllocator.h b/Code/CryEngine/CrySystem/MTSafeAllocator.h deleted file mode 100644 index eeee5ff501..0000000000 --- a/Code/CryEngine/CrySystem/MTSafeAllocator.h +++ /dev/null @@ -1,108 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - - -#if defined(LINUX) -# include "Linux_Win32Wrapper.h" -#endif -#include - -//////////////////////////////////////////////////////////////////////////////// -#if defined(AZ_RESTRICTED_PLATFORM) -#include AZ_RESTRICTED_FILE(MTSafeAllocator_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(MOBILE) // IOS/Android -# define MTSAFE_DEFAULT_ALIGNMENT 8 -# define MTSAFE_GENERAL_HEAP_SIZE ((1U << 20) + (1U << 19)) -#elif defined(WIN32) || defined(WIN64) || defined(LINUX) || defined(MAC) -# define MTSAFE_GENERAL_HEAP_SIZE (12U << 20) -# define MTSAFE_DEFAULT_ALIGNMENT 8 -#else -# error Unknown target platform -#endif - -class CMTSafeHeap -{ -public: - // Constructor - CMTSafeHeap(); - - // Destructor - ~CMTSafeHeap(); - - // Performs a persisistent (in other words, non-temporary) allocation. - void* PersistentAlloc(size_t nSize); - - // Retrieves system memory allocation size for any call to PersistentAlloc. - // Required to not count virtual memory usage inside CrySizer - size_t PersistentAllocSize(size_t nSize); - - // Frees memory allocation - void FreePersistent(void* p); - - // Perform a allocation that is considered temporary and will be handled by - // the pool itself. - // Note: It is important that these temporary allocations are actually - // temporary and do not persist for a long persiod of time. - void* TempAlloc (size_t nSize, const char* szDbgSource, uint32 align = 0) - { - bool bFallbackToMalloc = true; - return TempAlloc(nSize, szDbgSource, bFallbackToMalloc, align); - } - - void* TempAlloc (size_t nSize, const char* szDbgSource, bool& bFallBackToMalloc, uint32 align = 0); - - bool IsInGeneralHeap(const void* p) - { - return m_pGeneralHeapStorage <= p && p < m_pGeneralHeapStorageEnd; - } - - // Free a temporary allocaton. - void FreeTemporary(void* p); - - // The number of live allocations allocation within the temporary pool - size_t NumAllocations() const { return m_LiveTempAllocations; } - - // The memory usage of the mtsafe allocator - void GetMemoryUsage(ICrySizer* pSizer); - - // zlib-compatible stubs - static void* StaticAlloc (void* pOpaque, unsigned nItems, unsigned nSize); - static void StaticFree (void* pOpaque, void* pAddress); - - // Dump some statistics to the cry log - void PrintStats(); - - -private: - friend class CSystem; - - IGeneralMemoryHeap* m_pGeneralHeap; - char* m_pGeneralHeapStorage; - char* m_pGeneralHeapStorageEnd; - - // The number of temporary allocations currently active within the pool - size_t m_LiveTempAllocations; - - // The total number of allocations performed in the pool - size_t m_TotalAllocations; - - // The total bytes that weren't temporarily allocated - size_t m_TempAllocationsFailed; - // The total number of temporary allocations that fell back to global system memory - LARGE_INTEGER m_TempAllocationsTime; -}; diff --git a/Code/CryEngine/CrySystem/MemoryAddressRange.cpp b/Code/CryEngine/CrySystem/MemoryAddressRange.cpp deleted file mode 100644 index bb547d80cc..0000000000 --- a/Code/CryEngine/CrySystem/MemoryAddressRange.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "MemoryAddressRange.h" -#include "System.h" - -#if defined(APPLE) || defined(LINUX) -#include -#endif - -CMemoryAddressRange::CMemoryAddressRange(char* pBaseAddress, size_t nPageSize, size_t nPageCount, [[maybe_unused]] const char* sName) - : m_pBaseAddress(pBaseAddress) - , m_nPageSize(nPageSize) - , m_nPageCount(nPageCount) -{ -} - -void CMemoryAddressRange::Release() -{ - delete this; -} - -char* CMemoryAddressRange::GetBaseAddress() const -{ - return m_pBaseAddress; -} - -size_t CMemoryAddressRange::GetPageCount() const -{ - return m_nPageCount; -} - -size_t CMemoryAddressRange::GetPageSize() const -{ - return m_nPageSize; -} - -#if AZ_LEGACY_CRYSYSTEM_TRAIT_MEMADDRESSRANGE_WINDOWS_STYLE - -void* CMemoryAddressRange::ReserveSpace(size_t capacity) -{ - return VirtualAlloc(NULL, capacity, MEM_RESERVE, PAGE_READWRITE); -} - -size_t CMemoryAddressRange::GetSystemPageSize() -{ - SYSTEM_INFO si; - GetSystemInfo(&si); - return si.dwPageSize; -} - -CMemoryAddressRange::CMemoryAddressRange(size_t capacity, [[maybe_unused]] const char* name) -{ - m_nPageSize = GetSystemPageSize(); - - size_t algnCap = Align(capacity, m_nPageSize); - m_pBaseAddress = (char*)ReserveSpace(algnCap); - m_nPageCount = algnCap / m_nPageSize; -} - -CMemoryAddressRange::~CMemoryAddressRange() -{ - VirtualFree(m_pBaseAddress, 0, MEM_RELEASE); -} - -void* CMemoryAddressRange::MapPage(size_t pageIdx) -{ - void* pRet = VirtualAlloc(m_pBaseAddress + pageIdx * m_nPageSize, m_nPageSize, MEM_COMMIT, PAGE_READWRITE); - return pRet; -} - -void CMemoryAddressRange::UnmapPage(size_t pageIdx) -{ - char* pBase = m_pBaseAddress + pageIdx * m_nPageSize; - - // Disable warning about only decommitting pages, and not releasing them - VirtualFree(pBase, m_nPageSize, MEM_DECOMMIT); -} - -#elif defined(AZ_RESTRICTED_PLATFORM) -#include AZ_RESTRICTED_FILE(MemoryAddressRange_cpp) -#elif defined(APPLE) || defined(LINUX) - -void* CMemoryAddressRange::ReserveSpace(size_t capacity) -{ - return mmap(0, capacity, PROT_NONE, MAP_ANON | MAP_NORESERVE | MAP_PRIVATE, -1, 0); -} - -size_t CMemoryAddressRange::GetSystemPageSize() -{ - return sysconf(_SC_PAGESIZE); -} - -CMemoryAddressRange::CMemoryAddressRange(size_t capacity, const char* name) -{ - m_nPageSize = GetSystemPageSize(); - - m_allocatedSpace = Align(capacity, m_nPageSize); - m_pBaseAddress = (char*)ReserveSpace(m_allocatedSpace); - assert(m_pBaseAddress != MAP_FAILED); - m_nPageCount = m_allocatedSpace / m_nPageSize; -} - -CMemoryAddressRange::~CMemoryAddressRange() -{ - int ret = munmap(m_pBaseAddress, m_allocatedSpace); - (void) ret; - assert(ret == 0); -} - -void* CMemoryAddressRange::MapPage(size_t pageIdx) -{ - // There is no equivalent to this function with mmap, this - // happens automatically in the OS. We just return the - // correct address. - void* pRet = NULL; - if (0 == mprotect(m_pBaseAddress + (pageIdx * m_nPageSize), m_nPageSize, PROT_READ | PROT_WRITE)) - { - pRet = m_pBaseAddress + (pageIdx * m_nPageSize); - } - - return pRet; -} - -void CMemoryAddressRange::UnmapPage(size_t pageIdx) -{ - char* pBase = m_pBaseAddress + pageIdx * m_nPageSize; - int ret = mprotect(pBase, m_nPageSize, PROT_NONE); - (void) ret; - assert(ret == 0); -} - - -#endif diff --git a/Code/CryEngine/CrySystem/MemoryAddressRange.h b/Code/CryEngine/CrySystem/MemoryAddressRange.h deleted file mode 100644 index b2679f6667..0000000000 --- a/Code/CryEngine/CrySystem/MemoryAddressRange.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_MEMORYADDRESSRANGE_H -#define CRYINCLUDE_CRYSYSTEM_MEMORYADDRESSRANGE_H -#pragma once - - -#include "IMemory.h" - -class CMemoryAddressRange - : public IMemoryAddressRange -{ -public: - static void* ReserveSpace(size_t sz); - static size_t GetSystemPageSize(); - -public: - CMemoryAddressRange(char* pBaseAddress, size_t nPageSize, size_t nPageCount, const char* sName); - CMemoryAddressRange(size_t capacity, const char* name); - ~CMemoryAddressRange(); - - ILINE bool IsInRange(void* p) const - { - return m_pBaseAddress <= p && p < (m_pBaseAddress + m_nPageSize * m_nPageCount); - } - -public: - void Release(); - - char* GetBaseAddress() const; - size_t GetPageCount() const; - size_t GetPageSize() const; - - void* MapPage(size_t pageIdx); - void UnmapPage(size_t pageIdx); - -private: - CMemoryAddressRange(const CMemoryAddressRange&); - CMemoryAddressRange& operator = (const CMemoryAddressRange&); - -private: - char* m_pBaseAddress; - size_t m_nPageSize; - size_t m_nPageCount; -#if defined(APPLE) || defined(LINUX) - size_t m_allocatedSpace; // Required to unmap latter on -#endif -}; - -#endif // CRYINCLUDE_CRYSYSTEM_MEMORYADDRESSRANGE_H diff --git a/Code/CryEngine/CrySystem/MemoryManager.cpp b/Code/CryEngine/CrySystem/MemoryManager.cpp deleted file mode 100644 index 3021d68539..0000000000 --- a/Code/CryEngine/CrySystem/MemoryManager.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "MemoryManager.h" -#include "platform.h" -#include "CustomMemoryHeap.h" -#include "GeneralMemoryHeap.h" -#include "PageMappingHeap.h" - - -#if defined(AZ_RESTRICTED_PLATFORM) -#undef AZ_RESTRICTED_SECTION -#define MEMORYMANAGER_CPP_SECTION_1 1 -#endif - -#if defined(WIN32) - #define WIN32_LEAN_AND_MEAN - #include - #include -#endif - -#if defined(APPLE) -#include // task_info -#endif - -#if defined(APPLE) || defined(LINUX) -#include // required by mman.h -#include //mmap - virtual memory manager -#endif - -#ifdef MEMMAN_STATIC -CCryMemoryManager g_memoryManager; -#endif - -////////////////////////////////////////////////////////////////////////// -CCryMemoryManager* CCryMemoryManager::GetInstance() -{ -#ifdef MEMMAN_STATIC - return &g_memoryManager; -#else - static CCryMemoryManager memman; - return &memman; -#endif -} - -////////////////////////////////////////////////////////////////////////// -bool CCryMemoryManager::GetProcessMemInfo(SProcessMemInfo& minfo) -{ - ZeroStruct(minfo); -#if defined(WIN32) - - MEMORYSTATUSEX mem; - mem.dwLength = sizeof(mem); - GlobalMemoryStatusEx (&mem); - - minfo.TotalPhysicalMemory = mem.ullTotalPhys; - minfo.FreePhysicalMemory = mem.ullAvailPhys; - - ////////////////////////////////////////////////////////////////////////// - typedef BOOL (WINAPI * GetProcessMemoryInfoProc)(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD); - - PROCESS_MEMORY_COUNTERS pc; - ZeroStruct(pc); - pc.cb = sizeof(pc); - static HMODULE hPSAPI = LoadLibraryA("psapi.dll"); - if (hPSAPI) - { - static GetProcessMemoryInfoProc pGetProcessMemoryInfo = (GetProcessMemoryInfoProc)GetProcAddress(hPSAPI, "GetProcessMemoryInfo"); - if (pGetProcessMemoryInfo) - { - if (pGetProcessMemoryInfo(GetCurrentProcess(), &pc, sizeof(pc))) - { - minfo.PageFaultCount = pc.PageFaultCount; - minfo.PeakWorkingSetSize = pc.PeakWorkingSetSize; - minfo.WorkingSetSize = pc.WorkingSetSize; - minfo.QuotaPeakPagedPoolUsage = pc.QuotaPeakPagedPoolUsage; - minfo.QuotaPagedPoolUsage = pc.QuotaPagedPoolUsage; - minfo.QuotaPeakNonPagedPoolUsage = pc.QuotaPeakNonPagedPoolUsage; - minfo.QuotaNonPagedPoolUsage = pc.QuotaNonPagedPoolUsage; - minfo.PagefileUsage = pc.PagefileUsage; - minfo.PeakPagefileUsage = pc.PeakPagefileUsage; - - return true; - } - } - } - return false; - -#else - -#define AZ_RESTRICTED_SECTION_IMPLEMENTED -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION MEMORYMANAGER_CPP_SECTION_1 - #include AZ_RESTRICTED_FILE(MemoryManager_cpp) -#endif - - bool retVal = true; - -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) - #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(LINUX) - - MEMORYSTATUS MemoryStatus; - GlobalMemoryStatus(&MemoryStatus); - minfo.PagefileUsage = minfo.PeakPagefileUsage = MemoryStatus.dwTotalPhys - MemoryStatus.dwAvailPhys; - - minfo.FreePhysicalMemory = MemoryStatus.dwAvailPhys; - minfo.TotalPhysicalMemory = MemoryStatus.dwTotalPhys; - -#if defined(ANDROID) - // On Android, mallinfo() is an EXTREMELY time consuming operation. Nearly 80% CPU time will be spent - // on this operation once -memreplay is given. Since WorkingSetSize is only used for statistics and - // debugging purpose, it's simply ignored. - minfo.WorkingSetSize = 0; -#else - struct mallinfo meminfo = mallinfo(); - minfo.WorkingSetSize = meminfo.usmblks + meminfo.uordblks; -#endif - -#elif defined(APPLE) - - MEMORYSTATUS MemoryStatus; - GlobalMemoryStatus(&MemoryStatus); - minfo.PagefileUsage = minfo.PeakPagefileUsage = MemoryStatus.dwTotalPhys - MemoryStatus.dwAvailPhys; - - minfo.FreePhysicalMemory = MemoryStatus.dwAvailPhys; - minfo.TotalPhysicalMemory = MemoryStatus.dwTotalPhys; - - // Retrieve WorkingSetSize from task_info - task_basic_info kTaskInfo; - mach_msg_type_number_t uInfoCount(sizeof(kTaskInfo) / sizeof(natural_t)); - if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&kTaskInfo, &uInfoCount) != 0) - { - gEnv->pLog->LogError("task_info failed\n"); - return false; - } - minfo.WorkingSetSize = kTaskInfo.resident_size; - -#else - - retVal = false; - -#endif - - return retVal; -#endif -} - -////////////////////////////////////////////////////////////////////////// -CCryMemoryManager::HeapHandle CCryMemoryManager::TraceDefineHeap([[maybe_unused]] const char* heapName, [[maybe_unused]] size_t size, [[maybe_unused]] const void* pBase) -{ - return 0; -} - -////////////////////////////////////////////////////////////////////////// -void CCryMemoryManager::TraceHeapAlloc([[maybe_unused]] HeapHandle heap, [[maybe_unused]] void* mem, [[maybe_unused]] size_t size, [[maybe_unused]] size_t blockSize, [[maybe_unused]] const char* sUsage, [[maybe_unused]] const char* sNameHint) -{ -} - -////////////////////////////////////////////////////////////////////////// -void CCryMemoryManager::TraceHeapFree([[maybe_unused]] HeapHandle heap, [[maybe_unused]] void* mem, [[maybe_unused]] size_t blockSize) -{ -} - - -////////////////////////////////////////////////////////////////////////// -void CCryMemoryManager::TraceHeapSetColor([[maybe_unused]] uint32 color) -{ -} - -////////////////////////////////////////////////////////////////////////// -void CCryMemoryManager::TraceHeapSetLabel([[maybe_unused]] const char* sLabel) -{ -} - -////////////////////////////////////////////////////////////////////////// -uint32 CCryMemoryManager::TraceHeapGetColor() -{ - return 0; -} - -////////////////////////////////////////////////////////////////////////// -ICustomMemoryHeap* const CCryMemoryManager::CreateCustomMemoryHeapInstance(IMemoryManager::EAllocPolicy const eAllocPolicy) -{ - return new CCustomMemoryHeap(eAllocPolicy); -} - -IGeneralMemoryHeap* CCryMemoryManager::CreateGeneralExpandingMemoryHeap(size_t upperLimit, size_t reserveSize, const char* sUsage) -{ - return new CGeneralMemoryHeap(static_cast(0), upperLimit, reserveSize, sUsage); -} - -IGeneralMemoryHeap* CCryMemoryManager::CreateGeneralMemoryHeap(void* base, size_t sz, const char* sUsage) -{ - return new CGeneralMemoryHeap(base, sz, sUsage); -} - -IMemoryAddressRange* CCryMemoryManager::ReserveAddressRange(size_t capacity, const char* sName) -{ - return new CMemoryAddressRange(capacity, sName); -} - -IPageMappingHeap* CCryMemoryManager::CreatePageMappingHeap(size_t addressSpace, const char* sName) -{ - return new CPageMappingHeap(addressSpace, sName); -} - -extern "C" -{ - CRYMEMORYMANAGER_API void CryGetIMemoryManagerInterface(void** pIMemoryManager) - { - // Static instance of the memory manager - *pIMemoryManager = CCryMemoryManager::GetInstance(); - } -}; diff --git a/Code/CryEngine/CrySystem/MemoryManager.h b/Code/CryEngine/CrySystem/MemoryManager.h deleted file mode 100644 index e29d5404d8..0000000000 --- a/Code/CryEngine/CrySystem/MemoryManager.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_MEMORYMANAGER_H -#define CRYINCLUDE_CRYSYSTEM_MEMORYMANAGER_H -#pragma once - -#include "ISystem.h" - -////////////////////////////////////////////////////////////////////////// -// Class that implements IMemoryManager interface. -////////////////////////////////////////////////////////////////////////// -#ifndef MEMMAN_STATIC -class CCryMemoryManager - : public IMemoryManager -{ -public: - // Singleton - static CCryMemoryManager* GetInstance(); - - ////////////////////////////////////////////////////////////////////////// - virtual bool GetProcessMemInfo(SProcessMemInfo& minfo); - - virtual HeapHandle TraceDefineHeap(const char* heapName, size_t size, const void* pBase); - virtual void TraceHeapAlloc(HeapHandle heap, void* mem, size_t size, size_t blockSize, const char* sUsage, const char* sNameHint = 0); - virtual void TraceHeapFree(HeapHandle heap, void* mem, size_t blockSize); - virtual void TraceHeapSetColor(uint32 color); - virtual uint32 TraceHeapGetColor(); - virtual void TraceHeapSetLabel(const char* sLabel); - - virtual ICustomMemoryHeap* const CreateCustomMemoryHeapInstance(IMemoryManager::EAllocPolicy const eAllocPolicy); - virtual IGeneralMemoryHeap* CreateGeneralExpandingMemoryHeap(size_t upperLimit, size_t reserveSize, const char* sUsage); - virtual IGeneralMemoryHeap* CreateGeneralMemoryHeap(void* base, size_t sz, const char* sUsage); - - virtual IMemoryAddressRange* ReserveAddressRange(size_t capacity, const char* sName); - virtual IPageMappingHeap* CreatePageMappingHeap(size_t addressSpace, const char* sName); -}; -#else -typedef IMemoryManager CCryMemoryManager; -#endif - -#endif // CRYINCLUDE_CRYSYSTEM_MEMORYMANAGER_H diff --git a/Code/CryEngine/CrySystem/MobileDetectSpec.cpp b/Code/CryEngine/CrySystem/MobileDetectSpec.cpp deleted file mode 100644 index 342537daeb..0000000000 --- a/Code/CryEngine/CrySystem/MobileDetectSpec.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include -#include -#include - -#include "MobileDetectSpec.h" - -namespace MobileSysInspect -{ - struct GpuApiPair - { - AZStd::string gpuDescription; - AZStd::string apiDescription; - }; - - AZStd::vector> deviceSpecMapping; - AZStd::vector> gpuSpecMapping; - const float LOW_SPEC_RAM = 1.0f; - const float MEDIUM_SPEC_RAM = 2.0f; - const float HIGH_SPEC_RAM = 3.0f; - - bool GetSpecForGPUAndAPI(const AZStd::string& gpuName, const AZStd::string& apiDescription, AZStd::string& specName) - { - for (const auto& descriptionSpecPair : gpuSpecMapping) - { - const GpuApiPair& currentPair = descriptionSpecPair.first; - AZStd::regex currentRegex(currentPair.gpuDescription.c_str()); - if (!AZStd::regex_search(gpuName, currentRegex)) - { - continue; - } - - currentRegex.assign(currentPair.apiDescription.c_str()); - if (!currentRegex.Empty() && !AZStd::regex_search(apiDescription, currentRegex)) - { - continue; - } - - specName = descriptionSpecPair.second; - return true; - } - - return false; - } - - namespace Internal - { - void LoadDeviceSpecMapping_impl(const char* filename) - { - XmlNodeRef xmlNode = GetISystem()->LoadXmlFromFile(filename); - - if (!xmlNode) - { - return; - } - - const int fileCount = xmlNode->getChildCount(); - - for (int i = 0; i < fileCount; ++i) - { - XmlNodeRef fileNode = xmlNode->getChild(i); - AZStd::string file = fileNode->getAttr("file"); - - if (!file.empty()) - { - const int mappingCount = fileNode->getChildCount(); - - deviceSpecMapping.reserve(mappingCount); - - for (int j = 0; j < mappingCount; ++j) - { - XmlNodeRef modelNode = fileNode->getChild(j); - AZStd::string model = modelNode->getAttr("model"); - - if (!model.empty()) - { - deviceSpecMapping.push_back(AZStd::make_pair(model, file)); - } - } - } - } - } - - void LoadGpuSpecMapping_impl(const char* filename) - { - XmlNodeRef xmlNode = GetISystem()->LoadXmlFromFile(filename); - - if (!xmlNode) - { - return; - } - - const int fileCount = xmlNode->getChildCount(); - - for (int i = 0; i < fileCount; ++i) - { - XmlNodeRef fileNode = xmlNode->getChild(i); - AZStd::string file = fileNode->getAttr("file"); - - if (!file.empty()) - { - const int mappingCount = fileNode->getChildCount(); - - gpuSpecMapping.reserve(mappingCount); - - for (int j = 0; j < mappingCount; ++j) - { - XmlNodeRef modelNode = fileNode->getChild(j); - GpuApiPair gpuApiPair; - gpuApiPair.gpuDescription = modelNode->getAttr("gpuName"); - gpuApiPair.apiDescription = modelNode->getAttr("apiVersion"); - - if (!gpuApiPair.gpuDescription.empty() || !gpuApiPair.apiDescription.empty()) - { - gpuSpecMapping.push_back(AZStd::make_pair(gpuApiPair, file)); - } - } - } - } - } - - bool GetSpecForModelName(const AZStd::string& modelName, AZStd::string& specName) - { - for (const auto& descriptionSpecPair : deviceSpecMapping) - { - AZStd::regex currentRegex(descriptionSpecPair.first.c_str()); - if (AZStd::regex_search(modelName, currentRegex)) - { - specName = descriptionSpecPair.second; - return true; - } - } - - return false; - } - - } // namespace Internal -} // namespace MobileSysInspect diff --git a/Code/CryEngine/CrySystem/MobileDetectSpec.h b/Code/CryEngine/CrySystem/MobileDetectSpec.h deleted file mode 100644 index bbb15d301a..0000000000 --- a/Code/CryEngine/CrySystem/MobileDetectSpec.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#pragma once - -#include "AzCore/std/containers/unordered_map.h" - -namespace MobileSysInspect -{ - extern const float LOW_SPEC_RAM; - extern const float MEDIUM_SPEC_RAM; - extern const float HIGH_SPEC_RAM; - - void LoadDeviceSpecMapping(); - bool GetAutoDetectedSpecName(AZStd::string &buffer); - bool GetSpecForGPUAndAPI(const AZStd::string& gpuName, const AZStd::string& apiDescription, AZStd::string& specName); - const float GetDeviceRamInGB(); - - namespace Internal - { - void LoadDeviceSpecMapping_impl(const char* fileName); - void LoadGpuSpecMapping_impl(const char* filename); - bool GetSpecForModelName(const AZStd::string& modelName, AZStd::string& specName); - } -} diff --git a/Code/CryEngine/CrySystem/MobileDetectSpec_Android.cpp b/Code/CryEngine/CrySystem/MobileDetectSpec_Android.cpp deleted file mode 100644 index 181200d383..0000000000 --- a/Code/CryEngine/CrySystem/MobileDetectSpec_Android.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include -#include -#include - -#include "MobileDetectSpec.h" - -namespace MobileSysInspect -{ - void LoadDeviceSpecMapping() - { - Internal::LoadDeviceSpecMapping_impl("@assets@/config/gpu/android_models.xml"); - Internal::LoadGpuSpecMapping_impl("@assets@/config/gpu/android_gpus.xml"); - } - - // Returns true if device is found in the device spec mapping - bool GetAutoDetectedSpecName(AZStd::string &buffer) - { - static constexpr const char* s_javaFieldName = "MODEL"; - AZ::Android::JNI::Object obj("android/os/Build"); - obj.RegisterStaticField(s_javaFieldName, "Ljava/lang/String;"); - AZStd::string name = obj.GetStaticStringField(s_javaFieldName); - - return Internal::GetSpecForModelName(name, buffer); - } - - const float GetDeviceRamInGB() - { - static constexpr const char* s_javaFuntionNameGetDeviceRamInGB = "GetDeviceRamInGB"; - AZ::Android::JNI::Object obj("com/amazon/lumberyard/AndroidDeviceManager"); - obj.RegisterStaticMethod(s_javaFuntionNameGetDeviceRamInGB, "()F"); - return obj.InvokeStaticFloatMethod(s_javaFuntionNameGetDeviceRamInGB); - } -} diff --git a/Code/CryEngine/CrySystem/MobileDetectSpec_Ios.cpp b/Code/CryEngine/CrySystem/MobileDetectSpec_Ios.cpp deleted file mode 100644 index dc0a28490d..0000000000 --- a/Code/CryEngine/CrySystem/MobileDetectSpec_Ios.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include - -#include "MobileDetectSpec.h" -#include - -namespace MobileSysInspect -{ - void LoadDeviceSpecMapping() - { - Internal::LoadDeviceSpecMapping_impl("@assets@/config/gpu/ios_models.xml"); - } - - // Returns true if device is found in the device spec mapping - bool GetAutoDetectedSpecName(AZStd::string &buffer) - { - AZStd::string name = SystemUtilsApple::GetMachineName(); - - return Internal::GetSpecForModelName(name, buffer); - } - - const float GetDeviceRamInGB() - { - // not supported on this platform - return 0.0f; - } -} diff --git a/Code/CryEngine/CrySystem/PageMappingHeap.cpp b/Code/CryEngine/CrySystem/PageMappingHeap.cpp deleted file mode 100644 index d42d75db5b..0000000000 --- a/Code/CryEngine/CrySystem/PageMappingHeap.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "PageMappingHeap.h" - -namespace -{ - template - inline void FindZeroRanges(const uint32* str, size_t strLen, Func& yield) - { - size_t carry = 0; - size_t bitIdx = 0; - - for (size_t wordIdx = 0; wordIdx < strLen; ++wordIdx) - { - size_t wordBitIdx = 0; - int64 word = str[wordIdx]; - - // Set up sign extension to insert bits that are the last bit, inverted. - - if (!(word & 0x80000000)) - { - reinterpret_cast(word) |= 0xffffffff00000000ULL; - } - - do - { - size_t wordZeroRunLen = countTrailingZeroes(word); - - wordBitIdx += wordZeroRunLen; - carry += wordZeroRunLen; - - if (wordBitIdx == 32) - { - break; - } - - yield(bitIdx, carry); - word >>= wordZeroRunLen; - bitIdx += carry; - carry = 0; - - size_t wordOneRunLen = countTrailingZeroes(~word); - bitIdx += wordOneRunLen; - wordBitIdx += wordOneRunLen; - - if (wordBitIdx == 32) - { - break; - } - - word >>= wordOneRunLen; - } - while (true); - } - - if (carry) - { - yield(bitIdx, carry); - } - } - - struct DLMMapFindBest - { - DLMMapFindBest(size_t size) - : requiredLength(size) - , bestPosition(-1) - , bestFragmentLength(INT_MAX) - { - } - - bool operator () (size_t position, size_t length) - { - if (length == requiredLength) - { - bestPosition = position; - bestFragmentLength = 0; - return false; - } - else if (length > requiredLength) - { - size_t fragment = length - requiredLength; - if (fragment < bestFragmentLength) - { - bestPosition = position; - bestFragmentLength = fragment; - } - } - - return true; - } - - size_t requiredLength; - ptrdiff_t bestPosition; - size_t bestFragmentLength; - }; - - struct FindLargest - { - FindLargest() - : largest(0) - { - } - bool operator () (size_t, size_t length) - { - largest = max(largest, length); - return true; - } - - size_t largest; - }; -} - -CPageMappingHeap::CPageMappingHeap(char* pAddressSpace, size_t nNumPages, size_t nPageSize, const char* sName) - : m_addrRange(pAddressSpace, nPageSize, nNumPages, sName) -{ - Init(); -} - -CPageMappingHeap::CPageMappingHeap(size_t addressSpace, const char* sName) - : m_addrRange(addressSpace, sName) -{ - Init(); -} - -CPageMappingHeap::~CPageMappingHeap() -{ -} - -void CPageMappingHeap::Release() -{ - delete this; -} - -size_t CPageMappingHeap::GetGranularity() const -{ - return m_addrRange.GetPageSize(); -} - -bool CPageMappingHeap::IsInAddressRange(void* ptr) const -{ - return m_addrRange.IsInRange(ptr); -} - -size_t CPageMappingHeap::FindLargestFreeBlockSize() const -{ - CryAutoLock lock(m_lock); - - const size_t pageSize = m_addrRange.GetPageSize(); - - FindLargest findLargest; - FindZeroRanges(&m_pageBitmap[0], m_pageBitmap.size(), findLargest); - - return findLargest.largest * pageSize; -} - -void* CPageMappingHeap::Map(size_t length) -{ - CryAutoLock lock(m_lock); - - const size_t pageBitmapElemBitSize = (sizeof(uint32) * 8); - const size_t pageSize = m_addrRange.GetPageSize(); - const size_t numPages = m_addrRange.GetPageCount(); - - if (length % pageSize) - { - __debugbreak(); - length = (length + (pageSize - 1)) & ~(pageSize - 1); - } - - DLMMapFindBest findBest(length / pageSize); - FindZeroRanges(&m_pageBitmap[0], m_pageBitmap.size(), findBest); - - if ((findBest.bestPosition == -1) || (findBest.bestPosition >= (int)numPages)) - { - return NULL; - } - - void* mapAddress = m_addrRange.GetBaseAddress() + pageSize * findBest.bestPosition; - - for (size_t pageIdx = findBest.bestPosition, pageIdxEnd = pageIdx + length / pageSize; pageIdx != pageIdxEnd; ++pageIdx) - { - if (!m_addrRange.MapPage(pageIdx)) - { - // Unwind the pages we've already mapped. - for (; pageIdx > static_cast(findBest.bestPosition); --pageIdx) - { - m_addrRange.UnmapPage(pageIdx - 1); - } - - return NULL; - } - } - - for (size_t pageIdx = findBest.bestPosition, pageIdxEnd = pageIdx + length / pageSize; pageIdx != pageIdxEnd; ++pageIdx) - { - size_t pageSegment = pageIdx / pageBitmapElemBitSize; - uint32 pageMask = 1U << static_cast(pageIdx % pageBitmapElemBitSize); - - m_pageBitmap[pageSegment] |= pageMask; - } - - return mapAddress; -} - -void CPageMappingHeap::Unmap(void* mem, size_t length) -{ - CryAutoLock lock(m_lock); - const size_t pageSize = m_addrRange.GetPageSize(); - - if (length % pageSize) - { - __debugbreak(); - length = (length + (pageSize - 1)) & ~(pageSize - 1); - } - - char* mapAddress = reinterpret_cast(mem); - for (size_t pageIdx = (mapAddress - m_addrRange.GetBaseAddress()) / pageSize, pageIdxEnd = pageIdx + length / pageSize; pageIdx != pageIdxEnd; ++pageIdx) - { - m_addrRange.UnmapPage(pageIdx); - - const size_t pageBitmapElemBitSize = (sizeof(uint32) * 8); - - size_t pageSegment = pageIdx / pageBitmapElemBitSize; - uint32 pageMask = ~(1U << static_cast(pageIdx % pageBitmapElemBitSize)); - - m_pageBitmap[pageSegment] &= pageMask; - } -} - -void CPageMappingHeap::Init() -{ - UINT_PTR start = (UINT_PTR)m_addrRange.GetBaseAddress(); - UINT_PTR end = start + m_addrRange.GetPageCount() * m_addrRange.GetPageSize(); - - size_t addressSpace = end - start; - size_t pageSize = m_addrRange.GetPageSize(); - size_t numPages = (addressSpace + pageSize - 1) / pageSize; - m_pageBitmap.resize((numPages + 31) / 32); - - size_t pageCapacity = m_pageBitmap.size() * 32; - size_t numUnavailablePages = pageCapacity - numPages; - if (numUnavailablePages > 0) - { - m_pageBitmap.back() = ~((1 << (32 - numUnavailablePages)) - 1); - } -} diff --git a/Code/CryEngine/CrySystem/PageMappingHeap.h b/Code/CryEngine/CrySystem/PageMappingHeap.h deleted file mode 100644 index 8cd3a7a315..0000000000 --- a/Code/CryEngine/CrySystem/PageMappingHeap.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_PAGEMAPPINGHEAP_H -#define CRYINCLUDE_CRYSYSTEM_PAGEMAPPINGHEAP_H -#pragma once - - -#include "MemoryAddressRange.h" - -#include "IMemory.h" - -class CPageMappingHeap - : public IPageMappingHeap -{ -public: - CPageMappingHeap(char* pAddressSpace, size_t nNumPages, size_t nPageSize, const char* sName); - CPageMappingHeap(size_t addressSpace, const char* sName); - ~CPageMappingHeap(); - -public: // IPageMappingHeap Members - virtual void Release(); - - virtual size_t GetGranularity() const; - virtual bool IsInAddressRange(void* ptr) const; - - virtual size_t FindLargestFreeBlockSize() const; - - virtual void* Map(size_t sz); - virtual void Unmap(void* ptr, size_t sz); - -private: - CPageMappingHeap(const CPageMappingHeap&); - CPageMappingHeap& operator = (const CPageMappingHeap&); - -private: - void Init(); - -private: - mutable CryCriticalSectionNonRecursive m_lock; - CMemoryAddressRange m_addrRange; - std::vector m_pageBitmap; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_PAGEMAPPINGHEAP_H diff --git a/Code/CryEngine/CrySystem/PhysRenderer.cpp b/Code/CryEngine/CrySystem/PhysRenderer.cpp deleted file mode 100644 index a17fcb7063..0000000000 --- a/Code/CryEngine/CrySystem/PhysRenderer.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : impelemnation of a simple dedicated renderer for the physics subsystem - - -#include "CrySystem_precompiled.h" - diff --git a/Code/CryEngine/CrySystem/PhysRenderer.h b/Code/CryEngine/CrySystem/PhysRenderer.h deleted file mode 100644 index bbcca4626e..0000000000 --- a/Code/CryEngine/CrySystem/PhysRenderer.h +++ /dev/null @@ -1,22 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : declaration of a simple dedicated renderer for the physics subsystem - - -#ifndef CRYINCLUDE_CRYSYSTEM_PHYSRENDERER_H -#define CRYINCLUDE_CRYSYSTEM_PHYSRENDERER_H -#pragma once - - -#endif // CRYINCLUDE_CRYSYSTEM_PHYSRENDERER_H diff --git a/Code/CryEngine/CrySystem/Platform/Android/platform_android.cmake b/Code/CryEngine/CrySystem/Platform/Android/platform_android.cmake deleted file mode 100644 index bafe20e506..0000000000 --- a/Code/CryEngine/CrySystem/Platform/Android/platform_android.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -# Platform specific cmake file for configuring target compiler/link properties -# based on the active platform -# NOTE: functions in cmake are global, therefore adding functions to this file -# is being avoided to prevent overriding functions declared in other targets platfrom -# specific cmake files diff --git a/Code/CryEngine/CrySystem/Platform/Android/platform_android_files.cmake b/Code/CryEngine/CrySystem/Platform/Android/platform_android_files.cmake deleted file mode 100644 index ce1124fe07..0000000000 --- a/Code/CryEngine/CrySystem/Platform/Android/platform_android_files.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - ../../MobileDetectSpec_Android.cpp - ../../MobileDetectSpec.cpp - ../../MobileDetectSpec.h - ../../ThermalInfoAndroid.h - ../../ThermalInfoAndroid.cpp -) diff --git a/Code/CryEngine/CrySystem/Platform/Linux/platform_linux.cmake b/Code/CryEngine/CrySystem/Platform/Linux/platform_linux.cmake deleted file mode 100644 index 971c8ad67f..0000000000 --- a/Code/CryEngine/CrySystem/Platform/Linux/platform_linux.cmake +++ /dev/null @@ -1,21 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -# Platform specific cmake file for configuring target compiler/link properties -# based on the active platform -# NOTE: functions in cmake are global, therefore adding functions to this file -# is being avoided to prevent overriding functions declared in other targets platfrom -# specific cmake files - -set(LY_BUILD_DEPENDENCIES - PRIVATE - m -) diff --git a/Code/CryEngine/CrySystem/Platform/Mac/platform_mac.cmake b/Code/CryEngine/CrySystem/Platform/Mac/platform_mac.cmake deleted file mode 100644 index bafe20e506..0000000000 --- a/Code/CryEngine/CrySystem/Platform/Mac/platform_mac.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -# Platform specific cmake file for configuring target compiler/link properties -# based on the active platform -# NOTE: functions in cmake are global, therefore adding functions to this file -# is being avoided to prevent overriding functions declared in other targets platfrom -# specific cmake files diff --git a/Code/CryEngine/CrySystem/Platform/Mac/platform_mac_files.cmake b/Code/CryEngine/CrySystem/Platform/Mac/platform_mac_files.cmake deleted file mode 100644 index 4d5680a30d..0000000000 --- a/Code/CryEngine/CrySystem/Platform/Mac/platform_mac_files.cmake +++ /dev/null @@ -1,10 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# diff --git a/Code/CryEngine/CrySystem/Platform/Windows/platform_windows.cmake b/Code/CryEngine/CrySystem/Platform/Windows/platform_windows.cmake deleted file mode 100644 index bafe20e506..0000000000 --- a/Code/CryEngine/CrySystem/Platform/Windows/platform_windows.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -# Platform specific cmake file for configuring target compiler/link properties -# based on the active platform -# NOTE: functions in cmake are global, therefore adding functions to this file -# is being avoided to prevent overriding functions declared in other targets platfrom -# specific cmake files diff --git a/Code/CryEngine/CrySystem/Platform/iOS/platform_ios.cmake b/Code/CryEngine/CrySystem/Platform/iOS/platform_ios.cmake deleted file mode 100644 index f607478131..0000000000 --- a/Code/CryEngine/CrySystem/Platform/iOS/platform_ios.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(LY_COMPILE_OPTIONS - PRIVATE - -xobjective-c++ -) - -find_library(UI_KIT_FRAMEWORK UIKit) - -set(LY_BUILD_DEPENDENCIES - PRIVATE - ${UI_KIT_FRAMEWORK} -) diff --git a/Code/CryEngine/CrySystem/Platform/iOS/platform_ios_files.cmake b/Code/CryEngine/CrySystem/Platform/iOS/platform_ios_files.cmake deleted file mode 100644 index bbe61fb488..0000000000 --- a/Code/CryEngine/CrySystem/Platform/iOS/platform_ios_files.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - ../../MobileDetectSpec_Ios.cpp - ../../MobileDetectSpec.cpp - ../../MobileDetectSpec.h -) - - diff --git a/Code/CryEngine/CrySystem/ResourceManager.cpp b/Code/CryEngine/CrySystem/ResourceManager.cpp deleted file mode 100644 index 5e9477a99c..0000000000 --- a/Code/CryEngine/CrySystem/ResourceManager.cpp +++ /dev/null @@ -1,868 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Interface to the Resource Manager - - -#include "CrySystem_precompiled.h" -#include "ResourceManager.h" -#include "System.h" -#include "MaterialUtils.h" -#include -#include -#include -#include -#include -#include - -#if defined(AZ_RESTRICTED_PLATFORM) -#undef AZ_RESTRICTED_SECTION -#define RESOURCEMANAGER_CPP_SECTION_1 1 -#define RESOURCEMANAGER_CPP_SECTION_2 2 -#endif - -#if defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION RESOURCEMANAGER_CPP_SECTION_1 -#include AZ_RESTRICTED_FILE(ResourceManager_cpp) -#endif - -#define LEVEL_PAK_FILENAME "level.pak" -#define LEVEL_PAK_INMEMORY_MAXSIZE 10 * 1024 * 1024 - -#define ENGINE_PAK_FILENAME "engine.pak" -#define LEVEL_CACHE_PAK_FILENAME "xml.pak" - -#define GAME_DATA_PAK_FILENAME "gamedata.pak" -#define FAST_LOADING_PAKS_SRC_FOLDER "_fastload/" -#define FRONTEND_COMMON_PAK_FILENAME_SP "modes/menucommon_sp.pak" -#define FRONTEND_COMMON_PAK_FILENAME_MP "modes/menucommon_mp.pak" -#define FRONTEND_COMMON_LIST_FILENAME "menucommon" -#define LEVEL_CACHE_SRC_FOLDER "_levelcache/" -#define LEVEL_CACHE_BIND_ROOT "LevelCache" -#define LEVEL_RESOURCE_LIST "resourcelist.txt" -#define AUTO_LEVEL_RESOURCE_LIST "auto_resourcelist.txt" -#define AUTO_LEVEL_SEQUENCE_RESOURCE_LIST "auto_resources_sequence.txt" -#define AUTO_LEVEL_TOTAL_RESOURCE_LIST "auto_resourcelist_total.txt" -#define AUTO_LEVEL_TOTAL_SEQUENCE_RESOURCE_LIST "auto_resources_total_sequence.txt" - -////////////////////////////////////////////////////////////////////////// -// IResourceList implementation class. -////////////////////////////////////////////////////////////////////////// -class CLevelResourceList - : public AZ::IO::IResourceList -{ -public: - CLevelResourceList() - { - m_pFileBuffer = 0; - m_nBufferSize = 0; - m_nCurrentLine = 0; - }; - ~CLevelResourceList() - { - Clear(); - }; - - uint32 GetFilenameHash(const char* sResourceFile) - { - char filename[512]; - azstrcpy(filename, AZ_ARRAY_SIZE(filename), sResourceFile); - MaterialUtils::UnifyMaterialName(filename); - - uint32 code = CCrc32::ComputeLowercase(filename); - return code; - } - - virtual void Add([[maybe_unused]] AZStd::string_view sResourceFile) - { - assert(0); // Not implemented. - } - virtual void Clear() - { - delete [] m_pFileBuffer; - m_pFileBuffer = 0; - m_nBufferSize = 0; - stl::free_container(m_lines); - stl::free_container(m_resources_crc32); - m_nCurrentLine = 0; - } - - struct ComparePredicate - { - bool operator()(const char* s1, const char* s2) - { - return strcmp(s1, s2) < 0; - } - }; - - virtual bool IsExist(AZStd::string_view sResourceFile) - { - uint32 nHash = GetFilenameHash(sResourceFile.data()); - if (stl::binary_find(m_resources_crc32.begin(), m_resources_crc32.end(), nHash) != m_resources_crc32.end()) - { - return true; - } - return false; - } - virtual bool Load(AZStd::string_view sResourceListFilename) - { - Clear(); - CCryFile file; - if (file.Open(sResourceListFilename.data(), "rb", AZ::IO::IArchive::FOPEN_ONDISK)) // File access can happen from disk as well. - { - m_nBufferSize = file.GetLength(); - if (m_nBufferSize > 0) - { - m_pFileBuffer = new char[m_nBufferSize]; - size_t numBytesRead = file.ReadRaw(m_pFileBuffer, file.GetLength()); - - if (numBytesRead <= 0 || numBytesRead != file.GetLength()) - { - AZ_Error("ResourceManager", false, "Unable to read data for: %.*s", aznumeric_cast(sResourceListFilename.size()), sResourceListFilename.data()); - return false; - } - m_pFileBuffer[m_nBufferSize - 1] = 0; - - char seps[] = "\r\n"; - - m_lines.reserve(5000); - - // Parse file, every line in a file represents a resource filename. - char* nextToken = nullptr; - char* token = azstrtok(m_pFileBuffer, 0, seps, &nextToken); - while (token != NULL) - { - m_lines.push_back(token); - token = azstrtok(NULL, 0, seps, &nextToken); - } - - m_resources_crc32.resize(m_lines.size()); - for (int i = 0, numlines = m_lines.size(); i < numlines; i++) - { - MaterialUtils::UnifyMaterialName(const_cast(m_lines[i])); - m_resources_crc32[i] = CCrc32::ComputeLowercase(m_lines[i]); - } - std::sort(m_resources_crc32.begin(), m_resources_crc32.end()); - } - return true; - } - return false; - } - virtual const char* GetFirst() - { - m_nCurrentLine = 0; - if (!m_lines.empty()) - { - return m_lines[0]; - } - return NULL; - } - virtual const char* GetNext() - { - m_nCurrentLine++; - if (m_nCurrentLine < (int)m_lines.size()) - { - return m_lines[m_nCurrentLine]; - } - return NULL; - } - - void GetMemoryStatistics(ICrySizer* pSizer) - { - pSizer->Add(this, sizeof(*this)); - pSizer->Add(m_pFileBuffer, m_nBufferSize); - pSizer->AddContainer(m_lines); - pSizer->AddContainer(m_resources_crc32); - } - -public: - char* m_pFileBuffer; - int m_nBufferSize; - typedef std::vector Lines; - Lines m_lines; - int m_nCurrentLine; - std::vector m_resources_crc32; -}; - - -////////////////////////////////////////////////////////////////////////// -CResourceManager::CResourceManager() -{ - m_bRegisteredFileOpenSink = false; - m_bOwnResourceList = false; - m_bLevelTransitioning = false; - - m_fastLoadPakPaths.reserve(8); -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::PrepareLevel(const char* sLevelFolder, const char* sLevelName) -{ - LOADING_TIME_PROFILE_SECTION; - - m_sLevelFolder = sLevelFolder; - m_sLevelName = sLevelName; - m_bLevelTransitioning = false; - m_currentLevelCacheFolder = CryPathString(LEVEL_CACHE_SRC_FOLDER) + sLevelName; - - if (g_cvars.archiveVars.nLoadCache) - { - bool usePrefabSystemForLevels = false; - AzFramework::ApplicationRequests::Bus::BroadcastResult( - usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled); - - // The prefab system doesn't use level.pak - if (!usePrefabSystemForLevels) - { - CryPathString levelpak = PathUtil::Make(sLevelFolder, LEVEL_PAK_FILENAME); - size_t nPakFileSize = gEnv->pCryPak->FGetSize(levelpak.c_str()); - if (nPakFileSize < LEVEL_PAK_INMEMORY_MAXSIZE) // 10 megs. - { - // Force level.pak from this level in memory. - gEnv->pCryPak->LoadPakToMemory(LEVEL_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_GPU); - } - } - - gEnv->pCryPak->LoadPakToMemory(ENGINE_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_GPU); - - // - // Load _levelCache paks in the order they are stored on the disk - reduce seek time - // - - if (gEnv->pConsole->GetCVar("e_StreamCgf") && gEnv->pConsole->GetCVar("e_StreamCgf")->GetIVal() != 0) - { - LoadLevelCachePak("cga.pak", "", true); - LoadLevelCachePak("cgf.pak", "", true); - - if (g_cvars.archiveVars.nStreamCache) - { - LoadLevelCachePak("cgf_cache.pak", "", false); - } - } - - LoadLevelCachePak("chr.pak", "", true); - - if (g_cvars.archiveVars.nStreamCache) - { - LoadLevelCachePak("chr_cache.pak", "", false); - } - - LoadLevelCachePak("dds0.pak", "", true); - - if (g_cvars.archiveVars.nStreamCache) - { - LoadLevelCachePak("dds_cache.pak", "", false); - } - - LoadLevelCachePak("skin.pak", "", true); - - if (g_cvars.archiveVars.nStreamCache) - { - LoadLevelCachePak("skin_cache.pak", "", false); - } - - LoadLevelCachePak(LEVEL_CACHE_PAK_FILENAME, "", true); - } - - AZStd::intrusive_ptr pResList = new CLevelResourceList; - gEnv->pCryPak->SetResourceList(AZ::IO::IArchive::RFOM_Level, pResList.get()); - m_bOwnResourceList = true; - - // Load resourcelist.txt, TODO: make sure there are no duplicates - if (g_cvars.archiveVars.nSaveLevelResourceList == 0) - { - string filename = PathUtil::Make(sLevelFolder, AUTO_LEVEL_RESOURCE_LIST); - if (!pResList->Load(filename.c_str())) // If we saving resource list do not use auto_resourcelist.txt - { - // Try resource list created by the editor. - filename = PathUtil::Make(sLevelFolder, LEVEL_RESOURCE_LIST); - pResList->Load(filename.c_str()); - } - } - //LoadFastLoadPaks(); - - if (g_cvars.archiveVars.nStreamCache) - { - m_AsyncPakManager.ParseLayerPaks(GetCurrentLevelCacheFolder()); - } -} - -////////////////////////////////////////////////////////////////////////// -bool CResourceManager::LoadFastLoadPaks(bool bToMemory) -{ - if (g_cvars.archiveVars.nSaveFastloadResourceList != 0) - { - // Record a file list for _FastLoad/startup.pak - m_recordedFiles.clear(); - gEnv->pCryPak->RegisterFileAccessSink(this); - m_bRegisteredFileOpenSink = true; - return false; - } - else - { - LOADING_TIME_PROFILE_SECTION; - - // Load a special _fastload paks - int nPakPreloadFlags = AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32 | AZ::IO::INestedArchive::FLAGS_OVERRIDE_PAK; - if (bToMemory && g_cvars.archiveVars.nLoadCache) - { - nPakPreloadFlags |= AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY; - } - - const char* const assetsDir = "@assets@"; - -#if defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION RESOURCEMANAGER_CPP_SECTION_2 -#include AZ_RESTRICTED_FILE(ResourceManager_cpp) -#endif - - gEnv->pCryPak->OpenPacks(assetsDir, AZ::IO::PathString(FAST_LOADING_PAKS_SRC_FOLDER) + "*.pak", nPakPreloadFlags, &m_fastLoadPakPaths); - gEnv->pCryPak->OpenPack(assetsDir, "Engine.pak", AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY); - return !m_fastLoadPakPaths.empty(); - } -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::UnloadFastLoadPaks() -{ - for (uint32 i = 0; i < m_fastLoadPakPaths.size(); i++) - { - // Unload a special _fastload paks - gEnv->pCryPak->ClosePack(m_fastLoadPakPaths[i].c_str(), AZ::IO::IArchive::FLAGS_PATH_REAL); - } - m_fastLoadPakPaths.clear(); -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::UnloadLevel() -{ - gEnv->pCryPak->SetResourceList(AZ::IO::IArchive::RFOM_Level, NULL); - - if (m_bRegisteredFileOpenSink) - { - if (g_cvars.archiveVars.nSaveTotalResourceList) - { - SaveRecordedResources(true); - m_recordedFiles.clear(); - } - } - - stl::free_container(m_sLevelFolder); - stl::free_container(m_sLevelName); - stl::free_container(m_currentLevelCacheFolder); - - // should always be empty, since it is freed at the end of - // the level loading process, if it is not - // something went wrong and we have a levelheap leak - assert(m_openedPaks.capacity() == 0); - - m_pSequenceResourceList = NULL; -} - -////////////////////////////////////////////////////////////////////////// -AZ::IO::IResourceList* CResourceManager::GetLevelResourceList() -{ - auto pResList = gEnv->pCryPak->GetResourceList(AZ::IO::IArchive::RFOM_Level); - return pResList; -} - -////////////////////////////////////////////////////////////////////////// -bool CResourceManager::LoadLevelCachePak(const char* sPakName, const char* sBindRoot, bool bOnlyDuringLevelLoading) -{ - LOADING_TIME_PROFILE_SECTION; - CryPathString pakPath = GetCurrentLevelCacheFolder() + "/" + sPakName; - - pakPath.MakeLower(); - pakPath.replace(AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR); - - // Check if pak is already loaded - for (int i = 0; i < (int)m_openedPaks.size(); i++) - { - if (strstr(m_openedPaks[i].filename.c_str(), pakPath.c_str())) - { - return true; - } - } - - // check pak file size. - size_t nFileSize = gEnv->pCryPak->FGetSize(pakPath.c_str(), true); - - if (nFileSize <= 0) - { - // Cached file does not exist - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Level cache pak file %s does not exist", pakPath.c_str()); - return false; - } - - //set these flags as DLC LevelCache Paks are found via the mod paths, - //and the paks can never be inside other paks so we optimise the search - uint32 nOpenPakFlags = AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32 | AZ::IO::IArchive::FLAGS_CHECK_MOD_PATHS | AZ::IO::IArchive::FLAGS_NEVER_IN_PAK; - - if (nFileSize < LEVEL_PAK_INMEMORY_MAXSIZE) // 10 megs. - { - if (!(nOpenPakFlags & AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY_CPU)) - { - nOpenPakFlags |= AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY; - } - } - - SOpenedPak op; - - if (gEnv->pCryPak->OpenPack(sBindRoot, { pakPath.c_str(), pakPath.size() }, nOpenPakFlags | AZ::IO::IArchive::FOPEN_HINT_QUIET, NULL, &op.filename)) - { - op.bOnlyDuringLevelLoading = bOnlyDuringLevelLoading; - m_openedPaks.push_back(op); - return true; - } - return false; -} - -////////////////////////////////////////////////////////////////////////// -bool CResourceManager::LoadModeSwitchPak(const char* sPakName, const bool multiplayer) -{ - if (g_cvars.archiveVars.nSaveLevelResourceList) - { - //Don't load the pak if we're trying to save a resourcelist in order to build it. - m_recordedFiles.clear(); - gEnv->pCryPak->RegisterFileAccessSink(this); - m_bRegisteredFileOpenSink = true; - return true; - } - else - { - if (g_cvars.archiveVars.nLoadModePaks) - { - // Unload SP common pak if switching to multiplayer - if (multiplayer) - { - UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP, FRONTEND_COMMON_LIST_FILENAME "_sp"); - } - else - { - UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_MP, FRONTEND_COMMON_LIST_FILENAME "_mp"); - } - //Load the mode switching pak. If this is available and up to date it speeds up this process considerably - bool bOpened = gEnv->pCryPak->OpenPack("@assets@", sPakName, 0); - bool bLoaded = gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_GPU); - return (bOpened && bLoaded); - } - else - { - return true; - } - } -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::UnloadModeSwitchPak(const char* sPakName, const char* sResourceListName, const bool multiplayer) -{ - if (g_cvars.archiveVars.nSaveLevelResourceList && m_bRegisteredFileOpenSink) - { - m_sLevelFolder = sResourceListName; - SaveRecordedResources(); - gEnv->pCryPak->UnregisterFileAccessSink(this); - m_bRegisteredFileOpenSink = false; - } - else - { - if (g_cvars.archiveVars.nLoadModePaks) - { - //Unload the mode switching pak. - gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_Unload); - gEnv->pCryPak->ClosePack(sPakName, 0); - //Load the frontend common mode switch pak, this can considerably reduce the time spent switching especially from disc, currently SP only - if (!multiplayer && LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP) == false) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not load %s during init. This file can significantly reduce frontend loading times.\n", FRONTEND_COMMON_PAK_FILENAME_SP); - } - else if (multiplayer && LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_MP) == false) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not load %s during init. This file can significantly reduce frontend loading times.\n", FRONTEND_COMMON_PAK_FILENAME_MP); - } - } - } -} - -////////////////////////////////////////////////////////////////////////// -bool CResourceManager::LoadMenuCommonPak(const char* sPakName) -{ - if (g_cvars.archiveVars.nSaveMenuCommonResourceList) - { - //Don't load the pak if we're trying to save a resourcelist in order to build it. - m_recordedFiles.clear(); - gEnv->pCryPak->RegisterFileAccessSink(this); - m_bRegisteredFileOpenSink = true; - return true; - } - else - { - //Load the mode switching pak. If this is available and up to date it speeds up this process considerably - bool bOpened = gEnv->pCryPak->OpenPack("@assets@", sPakName, 0); - bool bLoaded = gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_GPU); - return (bOpened && bLoaded); - } -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::UnloadMenuCommonPak(const char* sPakName, const char* sResourceListName) -{ - if (g_cvars.archiveVars.nSaveMenuCommonResourceList) - { - m_sLevelFolder = sResourceListName; - SaveRecordedResources(); - gEnv->pCryPak->UnregisterFileAccessSink(this); - m_bRegisteredFileOpenSink = false; - } - else - { - //Unload the mode switching pak. - gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_Unload); - gEnv->pCryPak->ClosePack(sPakName, 0); - } -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::UnloadLevelCachePak(const char* sPakName) -{ - LOADING_TIME_PROFILE_SECTION; - CryPathString pakPath = GetCurrentLevelCacheFolder() + "/" + sPakName; - pakPath.MakeLower(); - pakPath.replace(AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR); - - for (int i = 0; i < (int)m_openedPaks.size(); i++) - { - if (strstr(m_openedPaks[i].filename.c_str(), pakPath.c_str())) - { - gEnv->pCryPak->ClosePack(m_openedPaks[i].filename.c_str(), AZ::IO::IArchive::FLAGS_PATH_REAL); - m_openedPaks.erase(m_openedPaks.begin() + i); - break; - } - } - - if (m_openedPaks.empty()) - { - stl::free_container(m_openedPaks); - } -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::UnloadAllLevelCachePaks(bool bLevelLoadEnd) -{ - LOADING_TIME_PROFILE_SECTION; - - if (!bLevelLoadEnd) - { - m_AsyncPakManager.Clear(); - UnloadFastLoadPaks(); - } - else - { - m_AsyncPakManager.UnloadLevelLoadPaks(); - } - - uint32 nClosePakFlags = AZ::IO::IArchive::FLAGS_PATH_REAL; //AZ::IO::IArchive::FLAGS_CHECK_MOD_PATHS | AZ::IO::IArchive::FLAGS_NEVER_IN_PAK | AZ::IO::IArchive::FLAGS_PATH_REAL; - - for (int i = 0; i < (int)m_openedPaks.size(); i++) - { - if ((m_openedPaks[i].bOnlyDuringLevelLoading && bLevelLoadEnd) || - !bLevelLoadEnd) - { - gEnv->pCryPak->ClosePack(m_openedPaks[i].filename.c_str(), nClosePakFlags); - } - } - - if (g_cvars.archiveVars.nLoadCache) - { - gEnv->pCryPak->LoadPakToMemory(ENGINE_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_Unload); - - bool usePrefabSystemForLevels = false; - AzFramework::ApplicationRequests::Bus::BroadcastResult( - usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled); - - if (!usePrefabSystemForLevels) - { - // Force level.pak out of memory. - gEnv->pCryPak->LoadPakToMemory(LEVEL_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_Unload); - } - } - if (!bLevelLoadEnd) - { - stl::free_container(m_openedPaks); - } -} - -////////////////////////////////////////////////////////////////////////// - -bool CResourceManager::LoadPakToMemAsync(const char* pPath, bool bLevelLoadOnly) -{ - return m_AsyncPakManager.LoadPakToMemAsync(pPath, bLevelLoadOnly); -} - -bool CResourceManager::LoadLayerPak(const char* sLayerName) -{ - return m_AsyncPakManager.LoadLayerPak(sLayerName); -} - -void CResourceManager::UnloadLayerPak(const char* sLayerName) -{ - m_AsyncPakManager.UnloadLayerPak(sLayerName); -} - -void CResourceManager::GetLayerPakStats(SLayerPakStats& stats, bool bCollectAllStats) const -{ - m_AsyncPakManager.GetLayerPakStats(stats, bCollectAllStats); -} - -void CResourceManager::UnloadAllAsyncPaks() -{ - m_AsyncPakManager.Clear(); -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::Update() -{ - m_AsyncPakManager.Update(); -} -////////////////////////////////////////////////////////////////////////// -void CResourceManager::Init() -{ - GetISystem()->GetISystemEventDispatcher()->RegisterListener(this); -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::Shutdown() -{ - UnloadAllLevelCachePaks(false); - if (GetISystem() && GetISystem()->GetISystemEventDispatcher()) - { - GetISystem()->GetISystemEventDispatcher()->RemoveListener(this); - } -} - -////////////////////////////////////////////////////////////////////////// -bool CResourceManager::IsStreamingCachePak(const char* filename) const -{ - const char* cachePaks[] = { - "dds_cache.pak", - "cgf_cache.pak", - "skin_cache.pak", - "chr_cache.pak" - }; - - for (int i = 0; i < sizeof(cachePaks) / sizeof(cachePaks[0]); ++i) - { - if (strstr(filename, cachePaks[i])) - { - return true; - } - } - - return false; -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam) -{ - switch (event) - { - case ESYSTEM_EVENT_FRONTEND_INITIALISED: - { - GetISystem()->GetStreamEngine()->PauseStreaming(false, -1); - } - break; - - case ESYSTEM_EVENT_GAME_POST_INIT_DONE: - { - if (g_cvars.archiveVars.nSaveFastloadResourceList != 0) - { - SaveRecordedResources(); - - if (g_cvars.archiveVars.nSaveLevelResourceList == 0 && g_cvars.archiveVars.nSaveTotalResourceList == 0) - { - m_recordedFiles.clear(); - } - } - // Unload all paks from memory, after game init. - UnloadAllLevelCachePaks(false); - gEnv->pCryPak->LoadPaksToMemory(0, false); - - if (g_cvars.archiveVars.nLoadCache) - { - //Load the frontend common mode switch pak, this can considerably reduce the time spent switching especially from disc - if (LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP) == false) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not load %s during init. This file can significantly reduce frontend loading times.\n", FRONTEND_COMMON_PAK_FILENAME_SP); - } - } - - break; - } - - case ESYSTEM_EVENT_LEVEL_LOAD_PREPARE: - { - UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP, FRONTEND_COMMON_LIST_FILENAME "_sp"); - - m_bLevelTransitioning = !m_sLevelName.empty(); - - m_lastLevelLoadTime.SetValue(0); - m_beginLevelLoadTime = gEnv->pTimer->GetAsyncTime(); - if (g_cvars.archiveVars.nSaveLevelResourceList || g_cvars.archiveVars.nSaveTotalResourceList) - { - if (!g_cvars.archiveVars.nSaveTotalResourceList) - { - m_recordedFiles.clear(); - } - - if (!m_bRegisteredFileOpenSink) - { - gEnv->pCryPak->RegisterFileAccessSink(this); - m_bRegisteredFileOpenSink = true; - } - } - - // Cancel any async pak loading, it will fight with the impending sync IO - m_AsyncPakManager.CancelPendingJobs(); - - // Pause streaming engine for anything but sound, music, video and flash. - uint32 nMask = (1 << eStreamTaskTypeFlash) | (1 << eStreamTaskTypeVideo) | STREAM_TASK_TYPE_AUDIO_ALL; // Unblock specified streams - nMask = ~nMask; // Invert mask, bit set means blocking type. - GetISystem()->GetStreamEngine()->PauseStreaming(true, nMask); - } - break; - - case ESYSTEM_EVENT_LEVEL_LOAD_END: - { - if (m_bOwnResourceList) - { - m_bOwnResourceList = false; - // Clear resource list, after level loading. - auto pResList = gEnv->pCryPak->GetResourceList(AZ::IO::IArchive::RFOM_Level); - if (pResList) - { - pResList->Clear(); - } - } - } - - break; - - case ESYSTEM_EVENT_LEVEL_UNLOAD: - UnloadAllLevelCachePaks(false); - - break; - - case ESYSTEM_EVENT_LEVEL_PRECACHE_START: - { - // Unpause all streams in streaming engine. - GetISystem()->GetStreamEngine()->PauseStreaming(false, -1); - } - break; - - case ESYSTEM_EVENT_LEVEL_PRECACHE_FIRST_FRAME: - { - UnloadAllLevelCachePaks(true); - } - break; - - case ESYSTEM_EVENT_LEVEL_PRECACHE_END: - { - CTimeValue t = gEnv->pTimer->GetAsyncTime(); - m_lastLevelLoadTime = t - m_beginLevelLoadTime; - - if (g_cvars.archiveVars.nSaveLevelResourceList && m_bRegisteredFileOpenSink) - { - SaveRecordedResources(); - - if (!g_cvars.archiveVars.nSaveTotalResourceList) - { - gEnv->pCryPak->UnregisterFileAccessSink(this); - m_bRegisteredFileOpenSink = false; - } - } - - UnloadAllLevelCachePaks(true); - } - break; - } -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::GetMemoryStatistics(ICrySizer* pSizer) -{ - pSizer->AddContainer(m_openedPaks); -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::ReportFileOpen([[maybe_unused]] AZ::IO::HandleType inFileHandle, AZStd::string_view szFullPath) -{ - if (!g_cvars.archiveVars.nSaveLevelResourceList && !g_cvars.archiveVars.nSaveFastloadResourceList && !g_cvars.archiveVars.nSaveMenuCommonResourceList && !g_cvars.archiveVars.nSaveTotalResourceList) - { - return; - } - - string file = PathUtil::MakeGamePath(string(szFullPath.data(), szFullPath.size())); - file.replace('\\', '/'); - file.MakeLower(); - { - CryAutoCriticalSection lock(recordedFilesLock); - m_recordedFiles.push_back(file); - } -} - -////////////////////////////////////////////////////////////////////////// -void CResourceManager::SaveRecordedResources(bool bTotalList) -{ - CryAutoCriticalSection lock(recordedFilesLock); - - std::set fileset; - - // eliminate duplicate values - std::vector::iterator endLocation = std::unique(m_recordedFiles.begin(), m_recordedFiles.end()); - m_recordedFiles.erase(endLocation, m_recordedFiles.end()); - - fileset.insert(m_recordedFiles.begin(), m_recordedFiles.end()); - - string sSequenceFilename = PathUtil::AddSlash(m_sLevelFolder) + (bTotalList ? AUTO_LEVEL_TOTAL_SEQUENCE_RESOURCE_LIST : AUTO_LEVEL_SEQUENCE_RESOURCE_LIST); - { - AZ::IO::HandleType fileHandle = fxopen(sSequenceFilename, "wb", true); - if (fileHandle != AZ::IO::InvalidHandle) - { - for (std::vector::iterator it = m_recordedFiles.begin(); it != m_recordedFiles.end(); ++it) - { - const char* str = it->c_str(); - AZ::IO::Print(fileHandle, "%s\n", str); - } - gEnv->pFileIO->Close(fileHandle); - } - } - - string sResourceSetFilename = PathUtil::AddSlash(m_sLevelFolder) + (bTotalList ? AUTO_LEVEL_TOTAL_RESOURCE_LIST : AUTO_LEVEL_RESOURCE_LIST); - { - AZ::IO::HandleType fileHandle = fxopen(sResourceSetFilename, "wb", true); - if (fileHandle != AZ::IO::InvalidHandle) - { - for (std::set::iterator it = fileset.begin(); it != fileset.end(); ++it) - { - const char* str = it->c_str(); - AZ::IO::Print(fileHandle, "%s\n", str); - } - gEnv->pFileIO->Close(fileHandle); - } - } -} - -////////////////////////////////////////////////////////////////////////// -CTimeValue CResourceManager::GetLastLevelLoadTime() const -{ - return m_lastLevelLoadTime; -} diff --git a/Code/CryEngine/CrySystem/ResourceManager.h b/Code/CryEngine/CrySystem/ResourceManager.h deleted file mode 100644 index aa697b3927..0000000000 --- a/Code/CryEngine/CrySystem/ResourceManager.h +++ /dev/null @@ -1,116 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Interface to the Resource Manager - - -#ifndef CRYINCLUDE_CRYSYSTEM_RESOURCEMANAGER_H -#define CRYINCLUDE_CRYSYSTEM_RESOURCEMANAGER_H -#pragma once - - -#include -#include "AsyncPakManager.h" - -////////////////////////////////////////////////////////////////////////// -// IResource manager interface -////////////////////////////////////////////////////////////////////////// -class CResourceManager - : public IResourceManager - , public ISystemEventListener - , public AZ::IO::IArchiveFileAccessSink -{ -public: - CResourceManager(); - - void Init(); - void Shutdown(); - - bool IsStreamingCachePak(const char* filename) const; - - ////////////////////////////////////////////////////////////////////////// - // IResourceManager interface implementation. - ////////////////////////////////////////////////////////////////////////// - void PrepareLevel(const char* sLevelFolder, const char* sLevelName); - void UnloadLevel(); - AZ::IO::IResourceList* GetLevelResourceList(); - bool LoadLevelCachePak(const char* sPakName, const char* sBindRoot, bool bOnlyDuringLevelLoading); - void UnloadLevelCachePak(const char* sPakName); - bool LoadModeSwitchPak(const char* sPakName, const bool multiplayer); - void UnloadModeSwitchPak(const char* sPakName, const char* sResourceListName, const bool multiplayer); - bool LoadMenuCommonPak(const char* sPakName); - void UnloadMenuCommonPak(const char* sPakName, const char* sResourceListName); - bool LoadPakToMemAsync(const char* pPath, bool bLevelLoadOnly); - void UnloadAllAsyncPaks(); - bool LoadLayerPak(const char* sLayerName); - void UnloadLayerPak(const char* sLayerName); - void UnloadAllLevelCachePaks(bool bLevelLoadEnd); - void GetMemoryStatistics(ICrySizer* pSizer); - bool LoadFastLoadPaks(bool bToMemory); - void UnloadFastLoadPaks(); - CTimeValue GetLastLevelLoadTime() const; - void GetLayerPakStats(SLayerPakStats& stats, bool bCollectAllStats) const; - ////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - // ISystemEventListener interface implementation. - ////////////////////////////////////////////////////////////////////////// - virtual void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam); - ////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - // IArchiveFileAccessSink interface implementation. - ////////////////////////////////////////////////////////////////////////// - virtual void ReportFileOpen(AZ::IO::HandleType inFileHandle, AZStd::string_view szFullPath); - ////////////////////////////////////////////////////////////////////////// - - // Per frame update of the resource manager. - void Update(); - - CryPathString GetCurrentLevelCacheFolder() const { return m_currentLevelCacheFolder; }; - void SaveRecordedResources(bool bTotalList = false); - -private: - - ////////////////////////////////////////////////////////////////////////// - - CryPathString m_currentLevelCacheFolder; - - struct SOpenedPak - { - AZStd::fixed_string filename; - bool bOnlyDuringLevelLoading; - }; - std::vector m_openedPaks; - - CAsyncPakManager m_AsyncPakManager; - - string m_sLevelFolder; - string m_sLevelName; - bool m_bLevelTransitioning; - - bool m_bRegisteredFileOpenSink; - bool m_bOwnResourceList; - - CTimeValue m_beginLevelLoadTime; - CTimeValue m_lastLevelLoadTime; - - AZStd::intrusive_ptr m_pSequenceResourceList; - - CryCriticalSection recordedFilesLock; - std::vector m_recordedFiles; - - AZStd::vector< AZStd::fixed_string > m_fastLoadPakPaths; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_RESOURCEMANAGER_H diff --git a/Code/CryEngine/CrySystem/SSAPI.DLL b/Code/CryEngine/CrySystem/SSAPI.DLL deleted file mode 100644 index b1f3d6cfce..0000000000 --- a/Code/CryEngine/CrySystem/SSAPI.DLL +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:45dfbb9836e8a8ac4ed5b427528dadf9134618e6977a1eb67af067e0eaadc185 -size 561936 diff --git a/Code/CryEngine/CrySystem/Sampler.cpp b/Code/CryEngine/CrySystem/Sampler.cpp deleted file mode 100644 index b6866ba6cd..0000000000 --- a/Code/CryEngine/CrySystem/Sampler.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "Sampler.h" - -#if defined(WIN32) - -#include -#include -#include - -#define MAX_SYMBOL_LENGTH 512 - -////////////////////////////////////////////////////////////////////////// -// Makes thread. -////////////////////////////////////////////////////////////////////////// -class CSamplingThread -{ -public: - CSamplingThread(CSampler* pSampler) - { - m_hThread = NULL; - m_pSampler = pSampler; - m_bStop = false; - m_samplePeriodMs = pSampler->GetSamplePeriod(); - - m_hProcess = GetCurrentProcess(); - m_hSampledThread = GetCurrentThread(); - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &m_hSampledThread, 0, FALSE, DUPLICATE_SAME_ACCESS); - } - - // Start thread. - void Start(); - void Stop(); - -protected: - virtual ~CSamplingThread() {}; - static DWORD WINAPI ThreadFunc(void* pThreadParam); - void Run(); // Derived classes must override this. - - HANDLE m_hProcess; - HANDLE m_hThread; - HANDLE m_hSampledThread; - DWORD m_ThreadId; - - CSampler* m_pSampler; - bool m_bStop; - int m_samplePeriodMs; -}; - -////////////////////////////////////////////////////////////////////////// -void CSamplingThread::Start() -{ - m_hThread = CreateThread(NULL, 0, ThreadFunc, this, 0, &m_ThreadId); -} - -////////////////////////////////////////////////////////////////////////// -void CSamplingThread::Stop() -{ - m_bStop = true; -} - -////////////////////////////////////////////////////////////////////////// -DWORD CSamplingThread::ThreadFunc(void* pThreadParam) -{ - CSamplingThread* thread = (CSamplingThread*)pThreadParam; - thread->Run(); - // Auto destruct thread class. - delete thread; - return 0; -} - -////////////////////////////////////////////////////////////////////////// -void CSamplingThread::Run() -{ - //SetThreadPriority( m_hThread,THREAD_PRIORITY_HIGHEST ); - SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL); - while (!m_bStop) - { - SuspendThread(m_hSampledThread); - - CONTEXT context; - context.ContextFlags = CONTEXT_CONTROL; - - uint64 ip = 0; - if (GetThreadContext(m_hSampledThread, &context)) - { -#ifdef CONTEXT_i386 - ip = context.Eip; -#else - ip = context.Rip; -#endif - } - ResumeThread(m_hSampledThread); - - if (!m_pSampler->AddSample(ip)) - { - break; - } - - Sleep(m_samplePeriodMs); - } -} - -////////////////////////////////////////////////////////////////////////// -CSampler::CSampler() -{ - m_pSamplingThread = NULL; - SetMaxSamples(2000); - m_bSamplingFinished = false; - m_bSampling = false; - m_samplePeriodMs = 1; //1ms -} - -////////////////////////////////////////////////////////////////////////// -CSampler::~CSampler() -{ -} - -////////////////////////////////////////////////////////////////////////// -void CSampler::SetMaxSamples(int nMaxSamples) -{ - m_rawSamples.reserve(nMaxSamples); - m_nMaxSamples = nMaxSamples; -} - -////////////////////////////////////////////////////////////////////////// -void CSampler::Start() -{ - if (m_bSampling) - { - return; - } - - CryLogAlways("Staring Sampling with interval %dms, max samples: %d ...", m_samplePeriodMs, m_nMaxSamples); - - m_bSampling = true; - m_bSamplingFinished = false; - m_pSamplingThread = new CSamplingThread(this); - m_rawSamples.clear(); - m_functionSamples.clear(); - - m_pSamplingThread->Start(); -} - -////////////////////////////////////////////////////////////////////////// -void CSampler::Stop() -{ - if (m_bSamplingFinished) - { - } - if (m_bSampling) - { - m_pSamplingThread->Stop(); - } - m_bSampling = false; - m_pSamplingThread = 0; -} - -////////////////////////////////////////////////////////////////////////// -void CSampler::Update() -{ - if (m_bSamplingFinished) - { - ProcessSampledData(); - m_bSamplingFinished = false; - } -} - -////////////////////////////////////////////////////////////////////////// -bool CSampler::AddSample(uint64 ip) -{ - if ((int)m_rawSamples.size() >= m_nMaxSamples) - { - m_bSamplingFinished = true; - m_bSampling = false; - m_pSamplingThread = 0; - return false; - } - m_rawSamples.push_back(ip); - return true; -} - -inline bool CompareFunctionSamples(const CSampler::SFunctionSample& s1, const CSampler::SFunctionSample& s2) -{ - return s1.nSamples < s2.nSamples; -} - -////////////////////////////////////////////////////////////////////////// -void CSampler::ProcessSampledData() -{ - CryLogAlways("Processing collected samples..."); - - uint32 i; - // Count duplicates. - std::map counts; - std::map::iterator cit; - for (i = 0; i < m_rawSamples.size(); i++) - { - uint32 ip = (uint32)m_rawSamples[i]; - cit = counts.find(ip); - if (cit != counts.end()) - { - cit->second++; - } - else - { - counts[ip] = 0; - } - } - - std::map funcCounts; - - AZ::Debug::SymbolStorage::StackLine func, file, module; - int line; - void* baseAddr; - string funcName; - for (i = 0; i < m_rawSamples.size(); i++) - { - // lookup module name here, and aggregate the results - AZ::Debug::SymbolStorage::FindFunctionFromIP((void*)m_rawSamples[i], &func, &file, &module, line, baseAddr); - - // Developer note: this file was using the module name instead of the function name. There was stub code - // to use the function name instead that. This function was updated to use FindFunctionFromIP(), but - // continues to use the module instead of the function. - funcName = module; - funcCounts[funcName] += 1; - } - - { - // Combine function samples. - std::map::iterator it; - for (it = funcCounts.begin(); it != funcCounts.end(); ++it) - { - SFunctionSample fs; - fs.function = it->first; - fs.nSamples = it->second; - m_functionSamples.push_back(fs); - } - } - - // Sort vector by number of samples. - std::sort(m_functionSamples.begin(), m_functionSamples.end(), CompareFunctionSamples); - - LogSampledData(); -} - -////////////////////////////////////////////////////////////////////////// -void CSampler::LogSampledData() -{ - int nTotalSamples = m_rawSamples.size(); - - // Log sample info. - CryLogAlways("========================================================================="); - CryLogAlways("= Profiler Output"); - CryLogAlways("========================================================================="); - - float fOnePercent = (float)nTotalSamples / 100; - - float fPercentTotal = 0; - int nSampleSum = 0; - for (uint32 i = 0; i < m_functionSamples.size(); i++) - { - // Calculate percentage. - float fPercent = m_functionSamples[i].nSamples / fOnePercent; - const char* func = m_functionSamples[i].function; - CryLogAlways("%6.2f%% (%4d samples) : %s", fPercent, m_functionSamples[i].nSamples, func); - fPercentTotal += fPercent; - nSampleSum += m_functionSamples[i].nSamples; - } - CryLogAlways("Samples: %d / %d (%.2f%%)", nSampleSum, nTotalSamples, fPercentTotal); - CryLogAlways("========================================================================="); -} - - -#endif // defined(WIN32) diff --git a/Code/CryEngine/CrySystem/Sampler.h b/Code/CryEngine/CrySystem/Sampler.h deleted file mode 100644 index b2c61013a2..0000000000 --- a/Code/CryEngine/CrySystem/Sampler.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_SAMPLER_H -#define CRYINCLUDE_CRYSYSTEM_SAMPLER_H -#pragma once - -#ifdef WIN32 - -class CSamplingThread; - -////////////////////////////////////////////////////////////////////////// -// Sampler class is running a second thread which is at regular intervals -// eg 1ms samples main thread and stores current IP in the samples buffers. -// After sampling finishes it can resolve collected IP buffer info to -// the function names and calculated where most of the execution time spent. -////////////////////////////////////////////////////////////////////////// -class CSampler -{ -public: - struct SFunctionSample - { - string function; - uint32 nSamples; // Number of samples per function. - }; - - CSampler(); - ~CSampler(); - - void Start(); - void Stop(); - void Update(); - - // Adds a new sample to the ip buffer, return false if no more samples can be added. - bool AddSample(uint64 ip); - void SetMaxSamples(int nMaxSamples); - - int GetSamplePeriod() const { return m_samplePeriodMs; } - void SetSamplePeriod(int millis) { m_samplePeriodMs = millis; } - -private: - void ProcessSampledData(); - void LogSampledData(); - - // Buffer for IP samples. - std::vector m_rawSamples; - std::vector m_functionSamples; - int m_nMaxSamples; - bool m_bSampling; - bool m_bSamplingFinished; - - int m_samplePeriodMs; - - CSamplingThread* m_pSamplingThread; -}; - -#else //WIN32 - -// Dummy sampler. -class CSampler -{ -public: - void Start() {} - void Stop() {} - void Update() {} - void SetMaxSamples(int) {} - void SetSamplePeriod(int) {} -}; - -#endif // WIN32 - -#endif // CRYINCLUDE_CRYSYSTEM_SAMPLER_H diff --git a/Code/CryEngine/CrySystem/ServerHandler.cpp b/Code/CryEngine/CrySystem/ServerHandler.cpp deleted file mode 100644 index 85b3192650..0000000000 --- a/Code/CryEngine/CrySystem/ServerHandler.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" - -#include "ProjectDefines.h" -#if defined(MAP_LOADING_SLICING) - -#include "ServerHandler.h" - -ServerHandler::ServerHandler(const char* bucket, int affinity, int serverTimeout) - : HandlerBase(bucket, affinity) -{ - m_serverTimeout = serverTimeout; - DoScan(); -} - -void ServerHandler::DoScan() -{ - std::set gotIndices; - for (int i = 0; i < m_srvLocks.size(); ++i) - { - gotIndices.insert(m_srvLocks[i]->number); - } - for (int i = 0; i < MAX_CLIENTS_NUM; ++i) - { - if (gotIndices.find(i) == gotIndices.end()) - { - std::unique_ptr lock(new SSyncLock(m_clientLockName, i, false)); - if (lock->IsValid()) - { - std::unique_ptr srv(new SSyncLock(m_serverLockName, i, true)); - if (srv->IsValid()) - { - m_srvLocks.push_back(std::move(srv)); - m_clientLocks.push_back(std::move(lock)); - CryLogAlways("Client %d bound", i); - } - else - { - CryLogAlways("Failed to bind client %d", i); - } - } - } - } - if (!m_clientLocks.empty()) - { - SetAffinity(); - } - m_lastScan = gEnv->pTimer->GetAsyncTime(); -} - -bool ServerHandler::Sync() -{ - if ((gEnv->pTimer->GetAsyncTime() - m_lastScan).GetSeconds() > 1.0f) - { - DoScan(); - } - for (int i = 0; i < m_srvLocks.size(); ) - { - m_srvLocks[i]->Signal(); - if (!m_clientLocks[i]->Wait(m_serverTimeout))//actually if not waited, let's kill it! - { - CryLogAlways("Dropped client %d", m_clientLocks[i]->number); - m_clientLocks[i]->Own(m_clientLockName); - m_clientLocks.erase(m_clientLocks.begin() + i); - m_srvLocks.erase(m_srvLocks.begin() + i); - continue; - } - ++i; - } - return false;//!m_clientLocks.empty(); -} - -#endif // defined(MAP_LOADING_SLICING) diff --git a/Code/CryEngine/CrySystem/ServerHandler.h b/Code/CryEngine/CrySystem/ServerHandler.h deleted file mode 100644 index 37a870efee..0000000000 --- a/Code/CryEngine/CrySystem/ServerHandler.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_SERVERHANDLER_H -#define CRYINCLUDE_CRYSYSTEM_SERVERHANDLER_H -#pragma once - -#include "HandlerBase.h" -#include "SyncLock.h" - -struct ServerHandler - : public HandlerBase -{ - ServerHandler(const char* bucket, int affinity, int serverTimeout); - - void DoScan(); - bool Sync(); - -private: - int m_serverTimeout; - std::vector > m_clientLocks; - std::vector > m_srvLocks; - CTimeValue m_lastScan; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_SERVERHANDLER_H diff --git a/Code/CryEngine/CrySystem/ServerThrottle.cpp b/Code/CryEngine/CrySystem/ServerThrottle.cpp deleted file mode 100644 index c183f1a4fc..0000000000 --- a/Code/CryEngine/CrySystem/ServerThrottle.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "ServerThrottle.h" -#include "TimeValue.h" -#include "ISystem.h" -#include "ITimer.h" -#include "IConsole.h" - -#if defined(WIN32) -static float ftdiff(const FILETIME& b, const FILETIME& a) -{ - uint64 aa = *reinterpret_cast(&a); - uint64 bb = *reinterpret_cast(&b); - return (bb - aa) * 1e-7f; -} - -class CCPUMonitor -{ -public: - CCPUMonitor(ISystem* pSystem, int nCPUs) - : m_lastUpdate(0.0f) - , m_pTimer(pSystem->GetITimer()) - , m_nCPUs(nCPUs) - { - FILETIME notNeeded; - GetProcessTimes(GetCurrentProcess(), ¬Needed, ¬Needed, &m_lastKernel, &m_lastUser); - } - - float* Update() - { - CTimeValue frameTime = gEnv->pTimer->GetFrameStartTime(); - if (frameTime - m_lastUpdate > 5.0f) - { - m_lastUpdate = frameTime; - - static float result = 0.0f; - - FILETIME kernel, user, cur; - FILETIME notNeeded; - GetSystemTimeAsFileTime(&cur); - GetProcessTimes(GetCurrentProcess(), ¬Needed, ¬Needed, &kernel, &user); - - float sKernel = ftdiff(kernel, m_lastKernel); - float sUser = ftdiff(user, m_lastUser); - float sCur = ftdiff(cur, m_lastTime); - - result = 100 * (sKernel + sUser) / sCur / m_nCPUs; - - m_lastTime = cur; - m_lastKernel = kernel; - m_lastUser = user; - - return &result; - } - return 0; - } - -private: - ITimer* m_pTimer; - CTimeValue m_lastUpdate; - FILETIME m_lastKernel, m_lastUser, m_lastTime; - int m_nCPUs; -}; -#else -class CCPUMonitor -{ -public: - CCPUMonitor(ISystem*, int) {} - - float* Update() { return 0; } -}; -#endif - -CServerThrottle::CServerThrottle(ISystem* pSys, int nCPUs) -{ - m_pCPUMonitor.reset(new CCPUMonitor(pSys, nCPUs)); - m_pDedicatedMaxRate = pSys->GetIConsole()->GetCVar("sv_DedicatedMaxRate"); - m_pDedicatedCPU = pSys->GetIConsole()->GetCVar("sv_DedicatedCPUPercent"); - m_pDedicatedCPUVariance = pSys->GetIConsole()->GetCVar("sv_DedicatedCPUVariance"); - - m_minFPS = 20; - m_maxFPS = 60; - m_nSteps = 8; - m_nCurStep = 0; - - if (m_pDedicatedCPU->GetFVal() >= 1.0f) - { - SetStep(m_nSteps / 2, 0); - } -} - -CServerThrottle::~CServerThrottle() -{ -} - -void CServerThrottle::Update() -{ - float tgtCPU = m_pDedicatedCPU->GetFVal(); - if (tgtCPU < 1) - { - return; - } - if (float* pCPU = m_pCPUMonitor->Update()) - { - float varCPU = m_pDedicatedCPUVariance->GetFVal(); - if (tgtCPU < 5) - { - tgtCPU = 5; - } - else if (tgtCPU > 95) - { - tgtCPU = 95; - } - float minCPU = std::max(tgtCPU - varCPU, tgtCPU / 2.0f); - float maxCPU = std::min(tgtCPU + varCPU, (100.0f + tgtCPU) / 2.0f); - - if (*pCPU > maxCPU) - { - SetStep(m_nCurStep - 1, pCPU); - } - else if (*pCPU < minCPU) - { - SetStep(m_nCurStep + 1, pCPU); - } - } -} - -void CServerThrottle::SetStep(int step, float* pDueToCPU) -{ - if (step < 0) - { - step = 0; - } - else if (step > m_nSteps) - { - step = m_nSteps; - } - if (step != m_nCurStep) - { - float fps = step * (m_maxFPS - m_minFPS) / m_nSteps + m_minFPS; - m_pDedicatedMaxRate->Set(fps); - if (pDueToCPU) - { - CryLog("ServerThrottle: Set framerate to %.1f fps [due to cpu being %d%%]", fps, int(*pDueToCPU + 0.5f)); - } - else - { - CryLog("ServerThrottle: Set framerate to %.1f fps", fps); - } - m_nCurStep = step; - } -} diff --git a/Code/CryEngine/CrySystem/ServerThrottle.h b/Code/CryEngine/CrySystem/ServerThrottle.h deleted file mode 100644 index ce658f4d2e..0000000000 --- a/Code/CryEngine/CrySystem/ServerThrottle.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Handle raising/lowering the frame rate on server -// based upon CPU usage - - -#ifndef CRYINCLUDE_CRYSYSTEM_SERVERTHROTTLE_H -#define CRYINCLUDE_CRYSYSTEM_SERVERTHROTTLE_H -#pragma once - - -struct ISystem; - -class CCPUMonitor; - -class CServerThrottle -{ -public: - CServerThrottle(ISystem* pSys, int nCPUs); - ~CServerThrottle(); - void Update(); - -private: - std::unique_ptr m_pCPUMonitor; - - void SetStep(int step, float* dueToCPU); - - float m_minFPS; - float m_maxFPS; - int m_nSteps; - int m_nCurStep; - ICVar* m_pDedicatedMaxRate; - ICVar* m_pDedicatedCPU; - ICVar* m_pDedicatedCPUVariance; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_SERVERTHROTTLE_H diff --git a/Code/CryEngine/CrySystem/StreamEngine/AZRequestReadStream.cpp b/Code/CryEngine/CrySystem/StreamEngine/AZRequestReadStream.cpp deleted file mode 100644 index 4344af45dc..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/AZRequestReadStream.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Streaming Engine - - -#include "CrySystem_precompiled.h" -#include -#include - -#include "AZRequestReadStream.h" -#include -#include -#include -#include "StreamEngine.h" - -AZRequestReadStream* AZRequestReadStream::Allocate(const EStreamTaskType tSource, const char* filename, IStreamCallback* callback, - const StreamReadParams* params) -{ - //Once an async method is available to read file sizes this code should be removed: - // and the file size should be known before calling this method and pass it as a - // parameter to this method. - //REMOVE In the Future START. - AZ::IO::SizeType fileSize = 0; - if (params && params->nSize) - { - fileSize = params->nSize; - } - else - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - AZ::IO::Result res = fileIO->Size(filename, fileSize); - if (!res) - { - AZ_Error("AZRequestReadStream", false, "Failed to read file size of %s", filename); - return nullptr; - } - //REMOVE In the Future END. - } - - auto streamer = AZ::Interface::Get(); - - AZRequestReadStream* retReq; - retReq = aznew AZRequestReadStream(); - - retReq->m_Type = tSource; - retReq->m_fileName = filename; - retReq->m_callback = callback; - retReq->m_fileSize = fileSize; - //REMARK: if params->pBuffer is NOT NULL, then retReq->m_buffer - //should become params->pBuffer, this is called stream-in-place. - //The only reason we are not doing this here is because - //some platforms support stream-in-place to WRITE ONLY buffers. - //Because there are no guarantees that low level streaming and decompression apis - //would treat the output buffer as WRITE ONLY, we still allocate the buffer and memcpy - //to params->pBuffer upon the completion callback being called. - //Once LY-98089 is complete/fixed, we should be able to safely - //set retReq->m_buffer = params->pBuffer and skip the memory allocation. - retReq->m_buffer = azmalloc(fileSize, streamer->GetRecommendations().m_memoryAlignment); - if (params) - { - retReq->m_params = *params; - } - - return retReq; -} - -////////////////////////////////////////////////////////////////////////// -AZRequestReadStream::AZRequestReadStream() : m_fileName(""), m_fileRequest(nullptr), - m_buffer(nullptr), m_Type(eStreamTaskTypeTexture), - m_callback(nullptr), m_fileSize(0), m_numBytesRead(0), m_isAsyncCallbackExecuted(false), - m_isSyncCallbackExecuted(false), m_isFileRequestComplete(false), m_isError(false), m_isFinished(false), - m_IOError(0) -{ - AZStd::atomic_init(&m_refCount, 0); - m_params = StreamReadParams(); -} - -////////////////////////////////////////////////////////////////////////// -AZRequestReadStream::~AZRequestReadStream() -{ - azfree(m_buffer); -} - -// tries to stop reading the stream; this is advisory and may have no effect -// all the callbacks will be called after this. If you just destructing object, -// dereference this object and it will automatically abort and release all associated resources. -void AZRequestReadStream::Abort() -{ - { - CryAutoCriticalSection lock(m_callbackLock); - // Increase ref counting to avoid preliminary destruction - AZRequestReadStream_AutoPtr refCountLock(this); - - if (m_isFileRequestComplete || m_isError) - { - // It is possible the file I/O request to be completed by AZ::IO::Streamer, - // but if the completion callback is deferred for the main thread then - // the stream is not finished. So, only if it is finished then - // it is safe to do nothing. - if (m_isFinished) - { - return; - } - } - - m_isError = true; - m_IOError = ERROR_USER_ABORT; - m_isFileRequestComplete = true; - m_numBytesRead = 0; - - if (m_fileRequest) - { - auto streamer = AZ::Interface::Get(); - streamer->QueueRequest(streamer->Cancel(m_fileRequest)); - } - - // all the callbacks have to handle error cases and needs to be called anyway, even if the stream I/O is aborted - ExecuteAsyncCallback_CBLocked(); - ExecuteSyncCallback_CBLocked(); - - m_callback = nullptr; - } - -} - -bool AZRequestReadStream::TryAbort() -{ - // Increase ref counting to avoid preliminary destruction - AZRequestReadStream_AutoPtr refCountLock(this); - - if (!m_callbackLock.TryLock()) - { - return false; - } - - if (m_isFileRequestComplete || m_isError) - { - // It is possible the file I/O request to be completed by AZ::IO::Streamer, - // but if the completion callback is deferred for the main thread then - // the stream is not finished. So, only if it is finished then - // it is safe to do nothing. - if (m_isFinished) - { - m_callbackLock.Unlock(); - return false; - } - } - - m_isError = true; - m_IOError = ERROR_USER_ABORT; - m_isFileRequestComplete = true; - m_numBytesRead = 0; - - if (m_fileRequest) - { - auto streamer = AZ::Interface::Get(); - streamer->QueueRequest(streamer->Cancel(m_fileRequest)); - } - - // all the callbacks have to handle error cases and needs to be called anyway, even if the stream I/O is aborted - ExecuteAsyncCallback_CBLocked(); - ExecuteSyncCallback_CBLocked(); - - m_callback = nullptr; - - m_callbackLock.Unlock(); - - return true; -} - -// tries to raise the priority of the read; this is advisory and may have no effect -void AZRequestReadStream::SetPriority(EStreamTaskPriority ePriority) -{ - CryAutoCriticalSection lock(m_callbackLock); - - if (m_params.ePriority != ePriority) - { - m_params.ePriority = ePriority; - if (m_fileRequest) - { - AZ::Interface::Get()->RescheduleRequest(m_fileRequest, AZ::IO::IStreamerTypes::s_noDeadline, - CStreamEngine::CryStreamPriorityToAZStreamPriority(ePriority)); - } - } -} - -// unconditionally waits until the callback is called -// i.e. if the stream hasn't yet finish, it's guaranteed that the user-supplied callback -// is called before return from this function (unless no callback was specified) -void AZRequestReadStream::Wait(int maxWaitMillis) -{ - // lock this object to avoid preliminary destruction - AZRequestReadStream_AutoPtr refCountLock(this); - - if (!m_isFinished && !m_isError && !m_fileRequest) - { - AZ_Error("AZRequestReadStream", false, "Stream for file %s is unwaitable", m_fileName.c_str()); - return; - } - - if (maxWaitMillis > 0) - { - m_wait.try_acquire_for(AZStd::chrono::milliseconds(maxWaitMillis)); - } - else - { - m_wait.acquire(); - } -} - -////////////////////////////////////////////////////////////////////////// -const char* AZRequestReadStream::GetErrorName() const -{ - switch (m_IOError) - { - case ERROR_UNKNOWN_ERROR: - return "Unknown error"; - case ERROR_UNEXPECTED_DESTRUCTION: - return "Unexpected destruction"; - case ERROR_INVALID_CALL: - return "Invalid call"; - case ERROR_CANT_OPEN_FILE: - return "Cannot open the file"; - case ERROR_REFSTREAM_ERROR: - return "Refstream error"; - case ERROR_OFFSET_OUT_OF_RANGE: - return "Offset out of range"; - case ERROR_REGION_OUT_OF_RANGE: - return "Region out of range"; - case ERROR_SIZE_OUT_OF_RANGE: - return "Size out of range"; - case ERROR_CANT_START_READING: - return "Cannot start reading"; - case ERROR_OUT_OF_MEMORY: - return "Out of memory"; - case ERROR_ABORTED_ON_SHUTDOWN: - return "Aborted on shutdown"; - case ERROR_OUT_OF_MEMORY_QUOTA: - return "Out of memory quota"; - case ERROR_ZIP_CACHE_FAILURE: - return "ZIP cache failure"; - case ERROR_USER_ABORT: - return "User aborted"; - } - return "Unrecognized error"; -} - -int AZRequestReadStream::AddRef() -{ - return m_refCount.fetch_add(1) + 1; -} - -int AZRequestReadStream::Release() -{ - int refCount = m_refCount.fetch_sub(1); - -#ifndef _RELEASE - if (refCount < 1) - { - __debugbreak(); - } -#endif - - if (refCount == 1) - { - //UNUSUAL, yet necessary. - //Why "delete this"? - //So, AZRequestReadStream is a replacement of CReadStream. The original design of - //Cry Texture Mips Streaming makes use of CReadStream through IReadStreamPtr, which - //is a smart pointer design that calls AddRef() and Release() but never calls "delete", - //like AZStd::shared_ptr<> does. This means the original Cry design had a memory leak - //because it never called delete on IReadStream objects. If you look at the original - //code of CReadStream (StreamReadStream.cpp) , the static Allocate method has two paths - //to allocate memory, one used a stack based memory allocation hack, and the other path - //was doing a "new CReadStream". Using VS2017 debugger I found both paths to be used, but - //"delete" and hence the destructor of CReadStream is never called causing minor memory leaks. - //The best solution I found was to call "delete this" here and later when we chnage IReadStreamPtr - //for AZstd::smart_ptr then AddRef() and Release() won't be needed anymore and this "delete this" - //hack won't be necessary either. - delete this; - } - - return refCount - 1; -} - -////////////////////////////////////////////////////////////////////////// -void AZRequestReadStream::ExecuteAsyncCallback_CBLocked() -{ - FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM); - - if (!m_isAsyncCallbackExecuted && m_callback) - { - m_isAsyncCallbackExecuted = true; - m_callback->StreamAsyncOnComplete(this, m_IOError); - } -} - -void AZRequestReadStream::ExecuteSyncCallback_CBLocked() -{ - FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM); - - if (!m_isSyncCallbackExecuted && m_callback && (0 == (m_params.nFlags & IStreamEngine::FLAGS_NO_SYNC_CALLBACK))) - { - m_isSyncCallbackExecuted = true; - - AZRequestReadStream_AutoPtr refCountLock(this); // Stream can be freed inside the callback! - - m_callback->StreamOnComplete(this, m_IOError); - - m_isFinished = true; - FreeTemporaryMemory(); - } - -} - -////////////////////////////////////////////////////////////////////////// -void AZRequestReadStream::FreeTemporaryMemory() -{ - // Make sure m_buffer is not freed if the file request is still in flight, as Streamer can still write to m_buffer in that case - if (!m_fileRequest || AZ::Interface::Get()->HasRequestCompleted(m_fileRequest)) - { - azfree(m_buffer); - m_buffer = nullptr; - m_numBytesRead = 0; - } -} - -////////////////////////////////////////////////////////////////////////// -void AZRequestReadStream::OnRequestComplete(AZ::IO::SizeType numBytesRead, [[maybe_unused]] void* buffer, AZ::IO::IStreamerTypes::RequestStatus requestState) -{ - CryAutoCriticalSection lock(m_callbackLock); - - if (!m_isFileRequestComplete) - { - switch (requestState) - { - case AZ::IO::IStreamerTypes::RequestStatus::Completed: - m_IOError = 0; - m_numBytesRead = static_cast(numBytesRead); - m_isError = false; - if (m_params.pBuffer) - { - //In some systems, streaming-in-place is supported. The caveat - //is that in some cases, the destination buffer is write-only. This is why - //a final memcpy must be done here until support is added to AZ::IO::Streamer API - //to decompress/load data into write-only buffers. SEE: LY-98089 - AZ_Assert(m_params.pBuffer != m_buffer, "Streaming-In-Place requires destination and source buffers to be different"); - memcpy(m_params.pBuffer, m_buffer, numBytesRead); - } - break; - case AZ::IO::IStreamerTypes::RequestStatus::Canceled: - m_IOError = ERROR_USER_ABORT; - m_numBytesRead = 0; - m_isError = true; - break; - default: - m_IOError = ERROR_UNKNOWN_ERROR; - m_numBytesRead = 0; - m_isError = true; - break; - } - - ExecuteAsyncCallback_CBLocked(); - m_isFileRequestComplete = true; - - if (m_params.nFlags & IStreamEngine::FLAGS_NO_SYNC_CALLBACK) - { - // We do not need FileRequest here anymore, and not its temporary memory. - m_fileRequest = nullptr; - m_isFinished = true; - } - else - { - //The completion must be triggered from MainThread. (Typically only happens when loading Terrain Macro Textures - AddRef(); - AZ::SystemTickBus::QueueFunction([this] { - RequestCompleteOnMainThread(); - }); - } - } - - m_wait.release(); -} - - -void AZRequestReadStream::RequestCompleteOnMainThread() -{ - FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM); - - // call asynchronous callback function if needed synchronously - { - CryAutoCriticalSection lock(m_callbackLock); - ExecuteSyncCallback_CBLocked(); - } - - //Always called because before enqueuing this call was called AddRef() - Release(); -} - diff --git a/Code/CryEngine/CrySystem/StreamEngine/AZRequestReadStream.h b/Code/CryEngine/CrySystem/StreamEngine/AZRequestReadStream.h deleted file mode 100644 index be925ad6c0..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/AZRequestReadStream.h +++ /dev/null @@ -1,151 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -// Description : An IReadStream implementation designed to work with AZ::IO::Streamer -// instead of CStreamEngine. - -#pragma once - -#include -#include -#include -#include -#include "IStreamEngine.h" - -namespace AZ -{ - namespace IO - { - class Request; - } -} - -//This class is a wrapper of AZ::IO::Request so Cry Classes can use AZ::IO::Streamer. -//Basicallythis replaces CReadStream. -class AZRequestReadStream - : public IReadStream -{ -public: - AZ_CLASS_ALLOCATOR(AZRequestReadStream, AZ::SystemAllocator, 0); - - static AZRequestReadStream* Allocate(const EStreamTaskType tSource, const char* filename, IStreamCallback* callback, - const StreamReadParams* params); - - int AddRef() override; - int Release() override; - - DWORD_PTR GetUserData() override {return m_params.dwUserData; } - - // set user defined data into stream's params - void SetUserData(DWORD_PTR userData) override { m_params.dwUserData = userData; }; - - // returns true if the file read was not successful. - bool IsError() override { return m_isError; }; - - // returns true if the file read was completed (successfully or unsuccessfully) - // check IsError to check if the whole requested file (piece) was read - bool IsFinished() override { return m_isFinished; }; - - // returns the number of bytes read so far (the whole buffer size if IsFinished()) - unsigned int GetBytesRead([[maybe_unused]] bool bWait) override { return static_cast(m_numBytesRead); }; - - // returns the buffer into which the data has been or will be read - // at least GetBytesRead() bytes in this buffer are guaranteed to be already read - const void* GetBuffer() override { return m_buffer; }; - - // tries to stop reading the stream; this is advisory and may have no effect - // but the callback will not be called after this. If you just destructing object, - // dereference this object and it will automatically abort and release all associated resources. - void Abort() override; - bool TryAbort() override; - - - - // unconditionally waits until the callback is called - // i.e. if the stream hasn't yet finish, it's guaranteed that the user-supplied callback - // is called before return from this function (unless no callback was specified) - void Wait(int maxWaitMillis = -1) override; - - const StreamReadParams& GetParams() const override {return m_params; } - - const EStreamTaskType GetCallerType() const override { return m_Type; } - - //We must define this one. But it is never used in the context of AZ::IO::Streamer. - //Legacy Cry StreamEngine stuff. - EStreamSourceMediaType GetMediaType() const override { return EStreamSourceMediaType::eStreamSourceTypeUnknown; } - - // return pointer to callback routine(can be NULL) - IStreamCallback* GetCallback() const override { return m_callback; }; - - // return IO error # - unsigned GetError() const override { return m_IOError; }; - - // Returns IO error name - const char* GetErrorName() const override; - - // return stream name - const char* GetName() const override { return m_fileName.c_str(); }; - - void FreeTemporaryMemory() override; - - // tries to raise the priority of the read; this is advisory and may have no effect - void SetPriority(EStreamTaskPriority EPriority); - uint64 GetPriority() const { return m_params.ePriority; }; - - void* GetFileReadBuffer() { return m_buffer; } //GetBuffer from IReadStream is "const void *" - AZStd::size_t GetFileSize() { return m_fileSize; } - - void SetFileRequest(AZ::IO::FileRequestPtr request) { m_fileRequest = AZStd::move(request); } - AZ::IO::FileRequestPtr GetFileRequest() { return m_fileRequest; } - - void OnRequestComplete(AZ::IO::SizeType numBytesRead, void* buffer, AZ::IO::IStreamerTypes::RequestStatus requestState); - -private: - AZRequestReadStream(); - virtual ~AZRequestReadStream(); - - // call the async callback - void ExecuteAsyncCallback_CBLocked(); - void ExecuteSyncCallback_CBLocked(); - void RequestCompleteOnMainThread(); - - AZStd::atomic_int m_refCount; - - CryCriticalSection m_callbackLock; - StreamReadParams m_params; - AZStd::semaphore m_wait; - - CryStringLocal m_fileName; - AZ::IO::FileRequestPtr m_fileRequest; - - // Bytes actually read from media. - void* m_buffer; - - // the type of the task - EStreamTaskType m_Type; - // the initial data from the user - // the callback; may be NULL - IStreamCallback* m_callback; - - AZ::IO::SizeType m_fileSize; //Expected number of bytes to be read. - AZ::IO::SizeType m_numBytesRead; //On a successful read m_nBytesRead == m_fileSize; - - bool m_isAsyncCallbackExecuted; - bool m_isSyncCallbackExecuted; - bool m_isFileRequestComplete; - - bool m_isError; - bool m_isFinished; - unsigned int m_IOError; -}; - -TYPEDEF_AUTOPTR(AZRequestReadStream); diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamAsyncFileRequest.cpp b/Code/CryEngine/CrySystem/StreamEngine/StreamAsyncFileRequest.cpp deleted file mode 100644 index 61052bc991..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamAsyncFileRequest.cpp +++ /dev/null @@ -1,1027 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" - -#include "StreamAsyncFileRequest.h" - -#include - -#include "StreamEngine.h" -#include "../System.h" -#include -#include - -extern CMTSafeHeap* g_pPakHeap; - -#if defined(STREAMENGINE_ENABLE_STATS) -extern SStreamEngineStatistics* g_pStreamingStatistics; -#endif - -extern SStreamEngineOpenStats* g_pStreamingOpenStatistics; - -volatile int CAsyncIOFileRequest::s_nLiveRequests; -SLockFreeSingleLinkedListHeader CAsyncIOFileRequest::s_freeRequests; - - -#ifdef STREAMENGINE_ENABLE_LISTENER - -class NotifyListenerIO -{ -public: - NotifyListenerIO(IStreamEngineListener* pL, CAsyncIOFileRequest* pReq, AZ::IO::CCachedFileData* pZipEntry, uint32 readSize) - : m_pL(pL) - , m_pReq(pReq) - { - if (m_pL) - { - m_pL->OnStreamBeginIO( - m_pReq, - (pZipEntry && pZipEntry->m_pFileEntry->nMethod) ? pZipEntry->GetFileEntry()->desc.lSizeCompressed : m_pReq->m_nFileSize, - readSize, - pReq->m_eMediaType); - } - } - ~NotifyListenerIO() - { - End(); - } - void End() - { - if (m_pL) - { - m_pL->OnStreamEndIO(m_pReq); - m_pL = NULL; - } - } - -private: - NotifyListenerIO(const NotifyListenerIO&); - NotifyListenerIO& operator = (const NotifyListenerIO&); - -private: - IStreamEngineListener* m_pL; - CAsyncIOFileRequest* m_pReq; -}; - -#endif //STREAMENGINE_ENABLE_LISTENER - -////////////////////////////////////////////////////////////////////////// - -void* CAsyncIOFileRequest::operator new (size_t sz) -{ - return CryModuleMemalign(sz, alignof(CAsyncIOFileRequest)); -} - -void CAsyncIOFileRequest::operator delete(void* p) -{ - CryModuleMemalignFree(p); -} - -////////////////////////////////////////////////////////////////////////// -CAsyncIOFileRequest::CAsyncIOFileRequest() - : m_nRefCount(0) - , m_pMemoryBuffer(NULL) -{ - Reset(); -} - -////////////////////////////////////////////////////////////////////////// -CAsyncIOFileRequest::~CAsyncIOFileRequest() -{ -#ifndef _RELEASE - if (m_pMemoryBuffer) - { - __debugbreak(); - } - if (m_eType) - { - __debugbreak(); - } -#endif -} - -////////////////////////////////////////////////////////////////////////// -uint32 CAsyncIOFileRequest::ConfigureRead(AZ::IO::CCachedFileData* pFileData) -{ - AZ::IO::ZipDir::FileEntry* pFileEntry = pFileData ? pFileData->m_pFileEntry : NULL; - - if (!pFileData || !pFileEntry->IsCompressed()) - { - m_bCompressedBuffer = false; - m_nFileSizeCompressed = m_nFileSize; - m_nSizeOnMedia = m_nRequestedSize; - - m_nPageReadStart = m_nRequestedOffset; - m_nPageReadEnd = m_nRequestedOffset + m_nRequestedSize; - } - else - { - m_bCompressedBuffer = true; - m_nFileSize = pFileEntry->desc.lSizeUncompressed; - m_nFileSizeCompressed = pFileEntry->desc.lSizeCompressed; - m_nSizeOnMedia = m_nFileSizeCompressed; - - m_nPageReadStart = 0; - m_nPageReadEnd = m_nFileSizeCompressed; - } - - if (pFileData && !m_bWriteOnlyExternal) - { - m_crc32FromHeader = pFileEntry->desc.lCRC32; - } - - m_nPageReadCurrent = 0; - - m_bStreamInPlace = !m_bCompressedBuffer || ((!m_pExternalMemoryBuffer || !m_bWriteOnlyExternal) && (m_nFileSize > m_nFileSizeCompressed)); - m_bReadBegun = 1; - - return 0; -} - -bool CAsyncIOFileRequest::CanReadInPages() -{ - bool bReadInBlocks = false; - - if (g_cvars.sys_streaming_in_blocks) - { - //stream is compressed and uncompressed size is greater than one page - if (!m_bCompressedBuffer || m_nFileSizeCompressed > STREAMING_BLOCK_SIZE) - { - bReadInBlocks = true; - } - } - - return bReadInBlocks; -} - -uint32 CAsyncIOFileRequest::AllocateOutput([[maybe_unused]] AZ::IO::CCachedFileData* pZipEntry) -{ - if (!m_bOutputAllocated) - { - uint32 nAllocSize = 0; - uint32 nReadAllocSize = 0; - uint32 nZStreamOffs = 0; - uint32 nLookaheadOffs = 0; - - if (m_pExternalMemoryBuffer) - { - nReadAllocSize = m_bCompressedBuffer - ? (m_nRequestedSize < m_nFileSize ? m_nFileSize : 0) - : 0; - } - else - { - nReadAllocSize = m_bCompressedBuffer - ? m_nFileSize - : m_nRequestedSize; - } - - nAllocSize = Align(nReadAllocSize, BUFFER_ALIGNMENT); - - bool bReadInBlocks = CanReadInPages(); - bool bNeedsLookahead = m_bStreamInPlace; - bool bBlockDecompress = m_bCompressedBuffer && bReadInBlocks; - - if (bBlockDecompress) - { - nZStreamOffs = nAllocSize; - nAllocSize += Align(sizeof(z_stream), BUFFER_ALIGNMENT); - - if (bNeedsLookahead) - { - nLookaheadOffs = nAllocSize; - nAllocSize += Align(sizeof(*m_pLookahead), BUFFER_ALIGNMENT); - } - } - - char* pBuffer = NULL; - - if (nAllocSize) - { - const char* usageHint = "AsyncIO TempBuffer"; - pBuffer = (char*)GetStreamEngine()->TempAlloc(nAllocSize, usageHint, true, IgnoreOutofTmpMem(), BUFFER_ALIGNMENT); - if (!pBuffer) - { - return ERROR_OUT_OF_MEMORY; - } - } - - if (pBuffer) - { - m_pMemoryBuffer = pBuffer; - m_nMemoryBufferSize = nAllocSize; - } - - if (nReadAllocSize) - { - m_pReadMemoryBuffer = pBuffer; - m_nReadMemoryBufferSize = nReadAllocSize; - } - else - { - m_pReadMemoryBuffer = m_pExternalMemoryBuffer; - m_nReadMemoryBufferSize = m_nRequestedSize; - } - - m_pOutputMemoryBuffer = m_pExternalMemoryBuffer - ? m_pExternalMemoryBuffer - : m_pReadMemoryBuffer; - - if (bBlockDecompress) - { - m_pZlibStream = (z_stream*)&pBuffer[nZStreamOffs]; - memset(m_pZlibStream, 0, sizeof(z_stream)); - - if (bNeedsLookahead) - { - m_pLookahead = new (&pBuffer[nLookaheadOffs]) AZ::IO::ZipDir::UncompressLookahead; - } - - m_pZlibStream->zalloc = CMTSafeHeap::StaticAlloc; - m_pZlibStream->zfree = CMTSafeHeap::StaticFree; - m_pZlibStream->opaque = g_pPakHeap; - } - - if (m_bCompressedBuffer) - { - m_pDecompQueue = new SStreamJobQueue; - } - - // Doesn't need to be atomic, as there's no concurrency yet. - int nMemoryBufferUsers = 0; - if (nReadAllocSize > 0) - { - ++nMemoryBufferUsers; - } - if (m_bCompressedBuffer) - { - ++nMemoryBufferUsers; - } - m_nMemoryBufferUsers = nMemoryBufferUsers; - - m_bOutputAllocated = 1; - } - - return 0; -} - -byte* CAsyncIOFileRequest::AllocatePage(size_t sz, bool bOnlyPakMem, SStreamPageHdr*& pHdrOut) -{ - const char* usageHint = "streaming page"; - size_t nSzAligned = Align(sz, BUFFER_ALIGNMENT); - size_t nToAlloc = nSzAligned + sizeof(SStreamPageHdr); - byte* pRet = (byte*)GetStreamEngine()->TempAlloc(nToAlloc, usageHint, true, !bOnlyPakMem, BUFFER_ALIGNMENT); - if (pRet) - { - pHdrOut = new (pRet + nSzAligned)SStreamPageHdr(nToAlloc); - } - - return pRet; -} - -////////////////////////////////////////////////////////////////////////// -void CAsyncIOFileRequest::Cancel() -{ - if (!HasFailed()) - { - CryOptionalAutoLock readLock(m_externalBufferLockRead, m_pExternalMemoryBuffer != NULL); - CryOptionalAutoLock decompLock(m_externalBufferLockDecompress, m_pExternalMemoryBuffer != NULL); - - Failed(ERROR_USER_ABORT); - } -} - -void CAsyncIOFileRequest::SyncWithDecompress() -{ - m_decompJobExecutor.reset(); // destructor waits on job completion -} - -////////////////////////////////////////////////////////////////////////// -bool CAsyncIOFileRequest::TryCancel() -{ - if (!HasFailed()) - { - bool bExt = false; - if (m_pExternalMemoryBuffer != NULL) - { - if (!m_externalBufferLockRead.TryLock()) - { - return false; - } - if (!m_externalBufferLockDecompress.TryLock()) - { - m_externalBufferLockRead.Unlock(); - return false; - } - bExt = true; - } - - Failed(ERROR_USER_ABORT); - - if (bExt) - { - m_externalBufferLockDecompress.Unlock(); - m_externalBufferLockRead.Unlock(); - } - } - - return true; -} - -////////////////////////////////////////////////////////////////////////// -void CAsyncIOFileRequest::FreeBuffer() -{ - if (m_pZlibStream) - { - //if the stream was cancelled in flight, inform zlib to free internal allocs - if (m_pZlibStream->state) - { - inflateEnd(m_pZlibStream); - } - - m_pZlibStream = NULL; - } - - m_pLookahead = NULL; - - SStreamEngineTempMemStats& tms = GetStreamEngine()->GetTempMemStats(); - - if (m_pDecompQueue) - { - m_pDecompQueue->Flush(tms); - delete m_pDecompQueue; - m_pDecompQueue = NULL; - } - - if (m_pMemoryBuffer) - { - CStreamEngine* pStreamEngine = GetStreamEngine(); - - pStreamEngine->TempFree(m_pMemoryBuffer, m_nMemoryBufferSize); - m_pMemoryBuffer = 0; - } - -#ifdef STREAMENGINE_ENABLE_STATS - // Update Streaming statistics. - if (g_pStreamingStatistics && m_nSizeOnMedia != 0 && m_bStatsUpdated) - { - m_bStatsUpdated = false; - int nSize = (int)m_nSizeOnMedia; - SStreamEngineStatistics& stats = *g_pStreamingStatistics; - CryInterlockedAdd(&stats.nPendingReadBytes, -nSize); - CryInterlockedAdd(&stats.typeInfo[m_eType].nPendingReadBytes, -nSize); - } -#endif -} - -CAsyncIOFileRequest* CAsyncIOFileRequest::Allocate(EStreamTaskType eType) -{ - CAsyncIOFileRequest* pReq = static_cast(CryInterlockedPopEntrySList(s_freeRequests)); - IF_UNLIKELY (!pReq) - { - pReq = new CAsyncIOFileRequest; - } - - pReq->Init(eType); - - return pReq; -} - -void CAsyncIOFileRequest::Flush() -{ - for (CAsyncIOFileRequest* pReq = static_cast(CryInterlockedPopEntrySList(s_freeRequests)); - pReq; - pReq = static_cast(CryInterlockedPopEntrySList(s_freeRequests))) - { - delete pReq; - } -} - -void CAsyncIOFileRequest::Reset() -{ - m_decompJobExecutor.reset(); // destructor waits on job completion - -#ifndef _RELEASE - if (m_pMemoryBuffer) - { - __debugbreak(); - } -#endif - - m_pReadStream = NULL; - m_strFileName.resize(0); - m_pakFile.resize(0); - - // Reset POD members of the structure - memset(&m_nSortKey, 0, ((char*)(this + 1) - (char*)&m_nSortKey)); -} - -void CAsyncIOFileRequest::Init(EStreamTaskType eType) -{ -#ifndef _RELEASE - if (!eType) - { - __debugbreak(); - } -#endif - - m_eType = eType; - -#ifdef STREAMENGINE_ENABLE_STATS - m_startTime = gEnv->pTimer->GetAsyncTime(); -#endif - - if (g_pStreamingOpenStatistics) - { - SStreamEngineOpenStats& stats = *g_pStreamingOpenStatistics; - CryInterlockedIncrement(&stats.nOpenRequestCount); - CryInterlockedIncrement(&stats.nOpenRequestCountByType[eType]); - } - - CryInterlockedIncrement(&s_nLiveRequests); -} - -void CAsyncIOFileRequest::Finalize() -{ -#ifndef _RELEASE - if (!m_eType) - { - __debugbreak(); - } -#endif - -#ifdef STREAMENGINE_ENABLE_LISTENER - IStreamEngineListener* pListener = gEnv->pSystem->GetStreamEngine()->GetListener(); - if (pListener) - { - pListener->OnStreamDone(this); - } -#endif - - if (g_pStreamingOpenStatistics) - { - SStreamEngineOpenStats& stats = *g_pStreamingOpenStatistics; - CryInterlockedDecrement(&stats.nOpenRequestCount); - CryInterlockedDecrement(&stats.nOpenRequestCountByType[m_eType]); - } - - CryInterlockedDecrement(&s_nLiveRequests); - - FreeBuffer(); - Reset(); -} - -uint32 CAsyncIOFileRequest::OpenFile(CCryFile& file) -{ - auto* pIPak = gEnv ? gEnv->pCryPak : NULL; - PREFAST_ASSUME(pIPak); - - if (m_pReadStream && m_pReadStream->GetParams().nFlags & IStreamEngine::FLAGS_FILE_ON_DISK) - { - pIPak = 0; - } - - file = CCryFile(pIPak); - if (!file.Open(m_strFileName.c_str(), "rb", AZ::IO::IArchive::FOPEN_FORSTREAMING)) - { - return ERROR_CANT_OPEN_FILE; - } - - return 0; -} - -////////////////////////////////////////////////////////////////////////// -uint32 CAsyncIOFileRequest::ReadFile(CStreamingIOThread* pIOThread) -{ - uint32 nError = m_nError; - - if (nError) - { - return nError; - } - - CCryFile file; - nError = OpenFile(file); - if (nError) - { - return nError; - } - - m_nFileSize = file.GetLength(); - - if (m_nRequestedOffset >= m_nFileSize) - { - return ERROR_OFFSET_OUT_OF_RANGE; - } - - if (m_nRequestedOffset + m_nRequestedSize > m_nFileSize) - { - return ERROR_SIZE_OUT_OF_RANGE; - } - - if (m_nRequestedSize == 0) - { - // by default, we read the whole file - m_nRequestedSize = m_nFileSize - m_nRequestedOffset; - } - - if (!m_pExternalMemoryBuffer && m_pReadStream) - { - bool bAbortOnFailToAlloc = false; - CReadStream* pReadStream = static_cast(&*m_pReadStream); - m_pExternalMemoryBuffer = pReadStream->OnNeedStorage(m_nFileSize, bAbortOnFailToAlloc); - - if (!m_pExternalMemoryBuffer && bAbortOnFailToAlloc) - { - Cancel(); - m_pReadStream->Abort(); - return ERROR_USER_ABORT; - } - } - - if (HasFailed()) - { - return m_nError; - } - - auto pZipEntry = ((AZ::IO::Archive*)(gEnv->pCryPak))->GetOpenedFileDataInZip(file.GetHandle()); - nError = ConfigureRead(pZipEntry.get()); - if (nError) - { - return nError; - } - - nError = AllocateOutput(pZipEntry.get()); - if (nError) - { - return nError; - } - - return ReadFileInPages(pIOThread, file); -} - -uint32 CAsyncIOFileRequest::ReadFileResume(CStreamingIOThread* pIOThread) -{ - uint32 nError = m_nError; - - if (nError) - { - return nError; - } - - CCryFile file; - nError = OpenFile(file); - if (nError) - { - return nError; - } - - auto pZipEntry = ((AZ::IO::Archive*)(gEnv->pCryPak))->GetOpenedFileDataInZip(file.GetHandle()); - - nError = AllocateOutput(pZipEntry.get()); - if (nError) - { - return nError; - } - -#ifdef STREAMENGINE_ENABLE_LISTENER - IStreamEngineListener* pListener = gEnv->pSystem->GetStreamEngine()->GetListener(); - if (pListener) - { - pListener->OnStreamResumed(this); - } -#endif - - return ReadFileInPages(pIOThread, file); -} - -uint32 CAsyncIOFileRequest::ReadFileInPages(CStreamingIOThread* pIOThread, CCryFile& file) -{ - auto pCryPak = static_cast(gEnv->pCryPak); - auto pZipEntry = pCryPak->GetOpenedFileDataInZip(file.GetHandle()); - - AZ::IO::ZipDir::Cache* pZip = NULL; - unsigned int nZipFlags = 0; - if (pZipEntry) - { - pZip = pZipEntry->GetZip(); - nZipFlags = pZipEntry->m_nArchiveFlags; - } - - if (pIOThread->IsMisscheduled(EStreamSourceMediaType::eStreamSourceTypeHDD)) - { - // We're on the wrong IO thread! - return ERROR_MISSCHEDULED; - } - - bool bReadInPages = CanReadInPages(); - - uint32 nPageReadLen = (m_nPageReadEnd - m_nPageReadStart); - - bool const bCompressed = m_bCompressedBuffer; - bool const bInPlace = m_bStreamInPlace; - bool const bIgnoreOutOfTmp = IgnoreOutofTmpMem(); - - size_t const nReadStartOffset = bCompressed - ? (m_nFileSize - m_nFileSizeCompressed) - : 0; - - byte* const pReadBase = (byte*)m_pReadMemoryBuffer + nReadStartOffset; - byte* const pReadEnd = (byte*)m_pReadMemoryBuffer + m_nReadMemoryBufferSize; - - CStreamEngine* pStreamEngine = static_cast(gEnv->pSystem->GetStreamEngine()); - - uint32 nPageSize = bReadInPages - ? min((uint32)STREAMING_PAGE_SIZE, nPageReadLen - m_nPageReadCurrent) - : nPageReadLen - m_nPageReadCurrent; - - while (nPageSize > 0) - { - CryOptionalAutoLock readLock(m_externalBufferLockRead, m_pExternalMemoryBuffer != NULL); - - uint32 nError = m_nError; - - if (nError) - { - return nError; - } - - //check if job needs to be pre-empted - nError = ReadFileCheckPreempt(pIOThread); - if (nError) - { - return nError; - } - - byte* pReadTarget = pReadBase + m_nPageReadCurrent; - byte* pReadTargetEnd = pReadTarget + nPageSize; - bool bTemporaryReadTarget = false; - SStreamPageHdr* pTemporaryPageHdr = NULL; - - if (bInPlace) - { - if (pReadTargetEnd > pReadEnd) - { - __debugbreak(); - } - } - else - { - pReadTarget = AllocatePage(nPageSize, !bIgnoreOutOfTmp, pTemporaryPageHdr); - - if (!pReadTarget) - { - return ERROR_OUT_OF_MEMORY; - } - - bTemporaryReadTarget = true; - pTemporaryPageHdr->nRefs = 1; - } - -#ifndef _RELEASE - if (m_nPageReadCurrent + nPageSize > nPageReadLen) - { - __debugbreak(); - } -#endif - - { -#ifdef STREAMENGINE_ENABLE_LISTENER - NotifyListenerIO IOListener(gEnv->pSystem->GetStreamEngine()->GetListener(), this, pZipEntry.get(), nPageSize); -#endif - -#ifdef STREAMENGINE_ENABLE_STATS - CTimeValue t0 = gEnv->pTimer->GetAsyncTime(); -#endif - - //printf("[StreamRead] %p %i %p %i %i\n", this, m_bCompressedBuffer, pReadTarget, m_nPageReadStart + m_nPageReadCurrent, nPageSize); - - bool bReadOk = false; - - if (pZipEntry) - { - bReadOk = pZipEntry->m_pZip->ReadFile(pZipEntry->m_pFileEntry, pReadTarget, nullptr) == AZ::IO::ZipDir::ZD_ERROR_SUCCESS; - } - else - { - file.Seek(m_nPageReadStart + m_nPageReadCurrent, SEEK_SET); - bReadOk = file.ReadRaw(pReadTarget, nPageSize) == nPageSize; - } - - if (bReadOk) - { - //send each block to listener -#ifdef STREAMENGINE_ENABLE_LISTENER - IOListener.End(); -#endif - -#ifdef STREAMENGINE_ENABLE_STATS - m_readTime += gEnv->pTimer->GetAsyncTime() - t0; -#endif - - //release external mem lock, allows jobs to be cancelled mid stream - readLock.Release(); - } - else - { - if (bTemporaryReadTarget) - { - GetStreamEngine()->TempFree(pReadTarget, pTemporaryPageHdr->nSize); - } - - return ERROR_REFSTREAM_ERROR; - } - - bool bLastBlock = (m_nPageReadCurrent + nPageSize) == nPageReadLen; - - if (bCompressed) - { - PushDecompressPage(pStreamEngine->GetJobEngineState(), pReadTarget, pTemporaryPageHdr, nPageSize, bLastBlock); - } - else if (bTemporaryReadTarget) - { - __debugbreak(); - } - - if (pTemporaryPageHdr && CryInterlockedDecrement(&pTemporaryPageHdr->nRefs) == 0) - { - GetStreamEngine()->TempFree(pReadTarget, pTemporaryPageHdr->nSize); - } - - m_nPageReadCurrent += nPageSize; - nPageSize = min((uint32)STREAMING_PAGE_SIZE, nPageReadLen - m_nPageReadCurrent); - } - } - - return 0; -} - -uint32 CAsyncIOFileRequest::ReadFileCheckPreempt(CStreamingIOThread* pIOThread) -{ - if (m_ePriority != estpUrgent) - { - if (pIOThread->HasUrgentRequests()) - { - //printf("Read Job %s pre-empted mid stream. Progress %d / %d bytes\n", m_strFileName.c_str(), m_nBytesRead, m_nFileSizeCompressed); -#ifdef STREAMENGINE_ENABLE_LISTENER - IStreamEngineListener* pListener = gEnv->pSystem->GetStreamEngine()->GetListener(); - if (pListener) - { - pListener->OnStreamPreempted(this); - } -#endif - return ERROR_PREEMPTED; - } - } - - return 0; -} - -////////////////////////////////////////////////////////////////////////// -CStreamEngine* CAsyncIOFileRequest::GetStreamEngine() -{ - return (CStreamEngine*)GetISystem()->GetStreamEngine(); -} - -////////////////////////////////////////////////////////////////////////// -EStreamSourceMediaType CAsyncIOFileRequest::GetMediaType() -{ - EStreamSourceMediaType mediaType = m_eMediaType; - - if (mediaType == eStreamSourceTypeUnknown) - { - if (m_bSortKeyComputed) - { - return mediaType; - } - - if (m_strFileName.empty()) - { - mediaType = eStreamSourceTypeMemory; - return mediaType; - } - - mediaType = gEnv->pCryPak->GetFileMediaType(m_strFileName.c_str()); - } - - return mediaType; -} - -////////////////////////////////////////////////////////////////////////// -void CAsyncIOFileRequest::ComputeSortKey(uint64 nCurrentKeyInProgress) -{ - if (m_bSortKeyComputed) - { - return; - } - - m_bSortKeyComputed = true; - - if (m_strFileName.empty()) - { - m_eMediaType = eStreamSourceTypeMemory; - m_nSortKey = m_ePriority; - return; - } - if (HasFailed()) - { - m_nSortKey = 0; - return; - } - - const int MaxPath = 0x800; - char szFullPathBuf[MaxPath]; - const char* szFullPath = gEnv->pCryPak->AdjustFileName(m_strFileName.c_str(), szFullPathBuf, AZ_ARRAY_SIZE(szFullPathBuf), AZ::IO::IArchive::FOPEN_HINT_QUIET); - - auto pCryPak = static_cast(gEnv->pCryPak); - - AZ::IO::ZipDir::CachePtr pZip = 0; - unsigned int archFlags = 0; - AZ::IO::ZipDir::FileEntry* pFileEntry = NULL; - - // tests if the given file path refers to an existing file inside registered (opened) packs - // the path must be absolute normalized lower-case with forward-slashes - AZ::IO::ArchiveLocationPriority varPakPriority = pCryPak->GetPakPriority(); - bool willOpenFromPak = (varPakPriority != AZ::IO::ArchiveLocationPriority::ePakPriorityFileFirst) - || !AZ::IO::FileIOBase::GetDirectInstance()->Exists(szFullPath); - - if (willOpenFromPak) - { - pFileEntry = pCryPak->FindPakFileEntry(szFullPath, archFlags, &pZip, false); - } - - EStreamSourceMediaType ssmt = pCryPak->GetFileMediaType(szFullPath); - - if (pFileEntry) - { - pZip->Refresh(pFileEntry); - m_nDiskOffset = (uint64)pFileEntry->nFileDataOffset; - - m_nSizeOnMedia = pFileEntry->desc.lSizeCompressed; - m_nFileSize = pFileEntry->desc.lSizeUncompressed; - - m_pakFile = pZip->GetFilePath(); - } - - m_eMediaType = ssmt; - - if (ssmt != eStreamSourceTypeMemory) - { - int32 nCurrentSweep = (nCurrentKeyInProgress >> 30) & ((1 << 10) - 1); - int32 nCurrentTG = (nCurrentKeyInProgress >> 40) & ((1 << 20) - 1); - - if (pFileEntry && !pFileEntry->IsCompressed()) - { - m_nDiskOffset += m_nRequestedOffset; - } - - // group items by priority, then by snapped request time, then sort by disk offset - m_nTimeGroup = (uint64)(gEnv->pTimer->GetAsyncTime().GetSeconds() / max(1, g_cvars.sys_streaming_requests_grouping_time_period)); - m_nSweep = (m_nTimeGroup == nCurrentTG) - ? nCurrentSweep - : 0; - uint64 nPrioriry = m_ePriority; - - int64 nDiskOffsetKB = m_nDiskOffset >> 10; // KB - m_nSortKey = (nDiskOffsetKB) | (((uint64)m_nTimeGroup) << 40) | ((uint64)m_nSweep << 30) | (nPrioriry << 60); - - // make sure we do not break incremental head movement within time group on every new request - if (m_nSortKey <= nCurrentKeyInProgress) - { - ++m_nSweep; - m_nSortKey = (nDiskOffsetKB) | (((uint64)m_nTimeGroup) << 40) | ((uint64)m_nSweep << 30) | (nPrioriry << 60); - } - } - else - { - m_nSortKey = m_ePriority; - } - -#if defined(STREAMENGINE_ENABLE_STATS) - // Update Streaming statistics. - if (!m_bStatsUpdated && g_pStreamingStatistics && m_nSizeOnMedia != 0) - { - m_bStatsUpdated = true; - SStreamEngineStatistics& stats = *g_pStreamingStatistics; - - // if the file is not compressed then it will only read the requested size - uint32 nReadSize = m_nSizeOnMedia; - if (m_nSizeOnMedia == m_nFileSize) - { - nReadSize = m_nRequestedSize; - } - - CryInterlockedAdd(&stats.nPendingReadBytes, nReadSize); - CryInterlockedAdd(&stats.typeInfo[m_eType].nPendingReadBytes, nReadSize); - } -#endif -} - -void CAsyncIOFileRequest::SetPriority(EStreamTaskPriority estp) -{ - m_ePriority = estp; - - if (m_eMediaType != eStreamSourceTypeMemory) - { - m_nSortKey &= ~(15ULL << 60); - m_nSortKey |= static_cast(estp) << 60; - } - else - { - m_nSortKey = m_ePriority; - } -} - -void CAsyncIOFileRequest::BumpSweep() -{ - ++m_nSweep; - if (m_eMediaType != eStreamSourceTypeMemory) - { - m_nSortKey += 1 << 30; - } -} - -////////////////////////////////////////////////////////////////////////// -bool CAsyncIOFileRequest::IgnoreOutofTmpMem() const -{ - if (m_pReadStream && - (m_pReadStream->GetParams().ePriority == estpUrgent || - m_pReadStream->GetParams().nFlags & IStreamEngine::FLAGS_IGNORE_TMP_OUT_OF_MEM)) - { - return true; - } - - return false; -} - -SStreamRequestQueue::SStreamRequestQueue() -{ - m_requests.reserve(4096); -} - -SStreamRequestQueue::~SStreamRequestQueue() -{ - Reset(); -} - -void SStreamRequestQueue::Reset() -{ - CryAutoLock l(m_lock); - for (size_t i = 0, c = m_requests.size(); i != c; ++i) - { - m_requests[i]->Release(); - } - m_requests.clear(); -} - -bool SStreamRequestQueue::IsEmpty() const -{ - return m_requests.empty(); -} - -bool SStreamRequestQueue::TryPopRequest(CAsyncIOFileRequest_AutoPtr& pOut) -{ - CryAutoLock l(m_lock); - if (!m_requests.empty()) - { - pOut = m_requests.front(); - pOut->Release(); - m_requests.erase(m_requests.begin()); - return true; - } - return false; -} - -void* SStreamEngineTempMemStats::TempAlloc(CMTSafeHeap* pHeap, size_t nSize, const char* szDbgSource, bool bFallBackToMalloc, bool bUrgent, uint32 align) -{ - // Only allow falling back to malloc if the size fits within the stream budget, the request is urgent, or the temp memory is 0 - for those files that are over budget on their own. - long nInUse = m_nTempAllocatedMemory; - bFallBackToMalloc = - bUrgent - || (bFallBackToMalloc && ((nInUse == 0) || (nInUse + static_cast(nSize) <= m_nTempMemoryBudget))) - ; - - void* p = pHeap->TempAlloc(nSize, szDbgSource, bFallBackToMalloc, align); -#if MTSAFE_USE_GENERAL_HEAP - bool bInGenHeap = pHeap->IsInGeneralHeap(p); -#else - bool bInGenHeap = false; -#endif - if (p && !bInGenHeap) - { - ReportTempMemAlloc(nSize, 0, false); - } - - return p; -} diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamAsyncFileRequest.h b/Code/CryEngine/CrySystem/StreamEngine/StreamAsyncFileRequest.h deleted file mode 100644 index 4a112ef68f..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamAsyncFileRequest.h +++ /dev/null @@ -1,571 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Streaming Thread for IO - - -#ifndef CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMASYNCFILEREQUEST_H -#define CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMASYNCFILEREQUEST_H -#pragma once - -#include -#include -#include "TimeValue.h" - -#define STREAMENGINE_LL_ALIGN _MS_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) - -class CStreamEngine; -class CAsyncIOFileRequest; -struct z_stream_s; -class CStreamingIOThread; -namespace AZ::IO -{ - struct CCachedFileData; -} -class CCryFile; -struct SStreamJobEngineState; -class CMTSafeHeap; -class CAsyncIOFileRequest_TransferPtr; -struct SStreamEngineTempMemStats; - -#if !defined(USE_EDGE_ZLIB) -// Prevent compilation conflicts - zconf.h (included by zlib.h) defines WINDOWS and WIN32 - those -// definitions conflict with CryEngine's definitions. - -# if defined(CRY_TMP_DEFINED_WINDOWS) || defined(CRY_TMP_DEFINED_WIN32) -# error CRY_TMP_DEFINED_WINDOWS and/or CRY_TMP_DEFINED_WIN32 already defined -# endif - -# if defined(WINDOWS) -# define CRY_TMP_DEFINED_WINDOWS 1 -# endif -# if defined(WIN32) -# define CRY_TMP_DEFINED_WIN32 1 -# endif - -# include - -# if !defined(CRY_TMP_DEFINED_WINDOWS) -# undef WINDOWS -#endif -# undef CRY_TMP_DEFINED_WINDOWS -# if !defined(CRY_TMP_DEFINED_WIN32) -# undef WIN32 -# endif -# undef CRY_TMP_DEFINED_WIN32 - -// Undefine macros defined in zutil.h to prevent compilation errors in 'steamclientpublic.h', 'OVR_Math.h' etc. -# undef Assert -# undef Trace -# undef Tracev -# undef Tracevv -# undef Tracec -# undef Tracecv - -#endif // !defined(USE_EDGE_ZLIB) - -namespace AZ::IO::ZipDir { - struct UncompressLookahead; -} - -struct IAsyncIOFileCallback -{ - virtual ~IAsyncIOFileCallback(){} - // Asynchronous finished event. - // Must be thread safe, can be called from a different thread. - virtual void OnAsyncFinished(CAsyncIOFileRequest* pFileRequest) = 0; -}; - -struct SStreamPageHdr -{ - explicit SStreamPageHdr(int size) - : nRefs() - , nSize(size) - {} - - volatile int nRefs; - int nSize; -}; - -struct SStreamJobQueue -{ - enum - { - MaxJobs = 256, - }; - - struct Job - { - void* pSrc; - SStreamPageHdr* pSrcHdr; - uint32 nOffs; - uint32 nBytes : 31; - uint32 bLast : 1; - }; - - SStreamJobQueue() - : m_sema(MaxJobs, MaxJobs) - { - m_nQueueLen = 0; - m_nPush = 0; - m_nPop = 0; - memset(m_jobs, 0, sizeof(m_jobs)); - } - - void Flush(SStreamEngineTempMemStats& tms); - - int Push(void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nOffs, uint32 nBytes, bool bLast); - int Pop(); - - CryFastSemaphore m_sema; - Job m_jobs[MaxJobs]; - volatile int m_nQueueLen; - volatile int m_nPush; - volatile int m_nPop; -}; - -// This class represent a request to read some file from disk asynchronously via one of the IO threads. -class CAsyncIOFileRequest -{ -public: - enum EStatus - { - eStatusNotReady, - eStatusInFileQueue, - eStatusFailed, - eStatusUnzipComplete, - eStatusDone, - }; - - enum - { - BUFFER_ALIGNMENT = 128, - WINDOW_SIZE = 1 << 15, - -#if defined(ANDROID) - STREAMING_PAGE_SIZE = (128 * 1024), -#else - STREAMING_PAGE_SIZE = (1 * 1024 * 1024), -#endif - -#if defined(ANDROID) - STREAMING_BLOCK_SIZE = (64 * 1024), -#else - STREAMING_BLOCK_SIZE = (32 * 1024), -#endif - }; - -public: - static CAsyncIOFileRequest* Allocate(EStreamTaskType eType); - static void Flush(); - -public: - void AddRef(); - int Release(); - -public: - void Init(EStreamTaskType eType); - void Finalize(); - - void Reset(); - - ILINE bool IsCancelled() const { return m_nError == ERROR_USER_ABORT; } - ILINE bool HasFailed() const { return m_nError != 0; } - void Failed(uint32 nError) - { - CryInterlockedCompareExchange(reinterpret_cast(&m_nError), nError, 0); - } - - uint32 OpenFile(CCryFile& file); - - uint32 ReadFile(CStreamingIOThread* pIOThread); - uint32 ReadFileResume(CStreamingIOThread* pIOThread); - uint32 ReadFileInPages(CStreamingIOThread* pIOThread, CCryFile& file); - uint32 ReadFileCheckPreempt(CStreamingIOThread* pIOThread); - - uint32 ConfigureRead(AZ::IO::CCachedFileData* pFileData); - bool CanReadInPages(); - uint32 AllocateOutput(AZ::IO::CCachedFileData* pZipEntry); - unsigned char* AllocatePage(size_t sz, bool bOnlyPakMem, SStreamPageHdr*& pHdrOut); - - static void JobFinalize_Read(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState); - - uint32 PushDecompressPage(const SStreamJobEngineState& engineState, void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nBytes, bool bLast); - uint32 PushDecompressBlock(const SStreamJobEngineState& engineState, void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nOffs, uint32 nBytes, bool bLast); - static void JobStart_Decompress(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState, int nSlot); - void DecompressBlockEntry(SStreamJobEngineState engineState, int nJob); - - void Cancel(); - bool TryCancel(); - void SyncWithDecompress(); - void ComputeSortKey(uint64 nCurrentKeyInProgress); - void SetPriority(EStreamTaskPriority estp); - void BumpSweep(); - void FreeBuffer(); - - bool IgnoreOutofTmpMem() const; - - CStreamEngine* GetStreamEngine(); - - EStreamSourceMediaType GetMediaType(); - -private: - void* operator new (size_t sz); - void operator delete(void* p); - -private: - static void JobFinalize_Decompress(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState); - static void JobFinalize_Transfer(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState); - -private: - void JobFinalize_Buffer(const SStreamJobEngineState& engineState); - void JobFinalize_Validate(const SStreamJobEngineState& engineState); - -private: - CAsyncIOFileRequest(); - ~CAsyncIOFileRequest(); - -public: - static volatile int s_nLiveRequests; - static SLockFreeSingleLinkedListHeader s_freeRequests; - -public: - // Must be first - STREAMENGINE_LL_ALIGN SLockFreeSingleLinkedListEntry m_nextFree; - - volatile int m_nRefCount; - - // Locks to be held whilst the file is being read, and an external memory buffer is in use - // (to ensure that if cancelled, the stream engine doesn't write to the external buffer) - // Separate locks for read and decomp as they can overlap (block decompress) - // Cancel() must acquire both - CryCriticalSection m_externalBufferLockRead; - CryCriticalSection m_externalBufferLockDecompress; - - CryStringLocal m_strFileName; - string m_pakFile; - - // If request come from stream, it will be not 0. - IReadStreamPtr m_pReadStream; - - AZStd::unique_ptr m_decompJobExecutor; - - // Only POD data should exist beyond this point - will be memsetted to 0 on Reset ! - - uint64 m_nSortKey; - - EStreamTaskPriority m_ePriority; - EStreamSourceMediaType m_eMediaType; - EStreamTaskType m_eType; - - volatile EStatus m_status; - volatile uint32 m_nError; - - uint32 m_nRequestedOffset; - uint32 m_nRequestedSize; - - // the file size, or 0 if the file couldn't be opened - uint32 m_nFileSize; - uint32 m_nFileSizeCompressed; - - void* m_pMemoryBuffer; - uint32 m_nMemoryBufferSize; - volatile int m_nMemoryBufferUsers; - - void* m_pExternalMemoryBuffer; - void* m_pOutputMemoryBuffer; - void* m_pReadMemoryBuffer; - uint32 m_nReadMemoryBufferSize; - - uint32 m_bCompressedBuffer : 1; - uint32 m_bStatsUpdated : 1; - uint32 m_bStreamInPlace : 1; - uint32 m_bWriteOnlyExternal : 1; - uint32 m_bSortKeyComputed : 1; - uint32 m_bOutputAllocated : 1; - uint32 m_bReadBegun : 1; - - // Actual size of the data on the media. - uint32 m_nSizeOnMedia; - - int64 m_nDiskOffset; - int32 m_nReadHeadOffsetKB; // Offset of the Read Head when reading from media. - int32 m_nTimeGroup; - int32 m_nSweep; - - IAsyncIOFileCallback* m_pCallback; - - // - // Block based streaming - // - - uint32 m_nPageReadStart; - uint32 m_nPageReadCurrent; - uint32 m_nPageReadEnd; - - volatile uint32 m_nBytesDecompressed; - - uint32 m_crc32FromHeader; - - volatile LONG m_nFinalised; - - z_stream_s* m_pZlibStream; - AZ::IO::ZipDir::UncompressLookahead* m_pLookahead; - SStreamJobQueue* m_pDecompQueue; - -#ifdef STREAMENGINE_ENABLE_STATS - // Time that read operation took. - CTimeValue m_readTime; - CTimeValue m_unzipTime; - CTimeValue m_verifyTime; - CTimeValue m_startTime; - CTimeValue m_completionTime; - - uint32 m_nReadCounter; -#endif -}; -TYPEDEF_AUTOPTR(CAsyncIOFileRequest); - -struct SStreamRequestQueue -{ - CryCriticalSection m_lock; - std::vector m_requests; - - CryEvent m_awakeEvent; - - SStreamRequestQueue(); - ~SStreamRequestQueue(); - - void Reset(); - bool IsEmpty() const; - - // Transfers ownership (rather than shares ownership) to the queue - void TransferRequest(CAsyncIOFileRequest_TransferPtr& pReq); - bool TryPopRequest(CAsyncIOFileRequest_AutoPtr& pOut); - -private: - SStreamRequestQueue(const SStreamRequestQueue&); - SStreamRequestQueue& operator = (const SStreamRequestQueue&); -}; - -#if defined(STREAMENGINE_ENABLE_STATS) -struct SStreamEngineDecompressStats -{ - uint64 m_nTotalBytesUnziped; - uint64 m_nTempBytesUnziped; - uint64 m_nTotalBytesVerified; - uint64 m_nTempBytesVerified; - - CTimeValue m_totalUnzipTime; - CTimeValue m_tempUnzipTime; - CTimeValue m_totalVerifyTime; - CTimeValue m_tempVerifyTime; -}; -#endif - -class CAsyncIOFileRequest_TransferPtr -{ -public: - explicit CAsyncIOFileRequest_TransferPtr(CAsyncIOFileRequest* p) - : m_p(p) - { - } - - ~CAsyncIOFileRequest_TransferPtr() - { - if (m_p) - { - m_p->Release(); - } - } - - CAsyncIOFileRequest* operator -> () { return m_p; } - CAsyncIOFileRequest& operator * () { return *m_p; } - - const CAsyncIOFileRequest* operator -> () const { return m_p; } - const CAsyncIOFileRequest& operator * () const { return *m_p; } - - operator bool () const { - return m_p != NULL; - } - - CAsyncIOFileRequest* Relinquish() - { - CAsyncIOFileRequest* p = m_p; - m_p = NULL; - return p; - } - - CAsyncIOFileRequest_TransferPtr& operator = (CAsyncIOFileRequest* p) - { -#ifndef _RELEASE - if (m_p) - { - __debugbreak(); - } -#endif - m_p = p; - return *this; - } - -private: - CAsyncIOFileRequest_TransferPtr(const CAsyncIOFileRequest_TransferPtr&); - CAsyncIOFileRequest_TransferPtr& operator = (const CAsyncIOFileRequest_TransferPtr&); - -private: - CAsyncIOFileRequest* m_p; -}; - -class CStreamEngineWakeEvent -{ -public: - CStreamEngineWakeEvent() - : m_state(0) - { - } - - void Set() - { - volatile LONG oldState, newState; - bool bSignalInner; - - do - { - bSignalInner = false; - oldState = m_state; - - newState = oldState | 0x80000000; - if (oldState & 0x7fffffff) - { - bSignalInner = true; - } - } - while (CryInterlockedCompareExchange(&m_state, newState, oldState) != oldState); - - if (bSignalInner) - { - m_innerEvent.Set(); - } - } - - bool Wait(uint32 timeout = 0) - { - bool bTimedOut = false; - bool bAcquiredSignal = false; - - while (!bTimedOut && !bAcquiredSignal) - { - volatile long oldState, newState; - do - { - bAcquiredSignal = false; - - oldState = m_state; - if (oldState & 0x80000000) - { - // Signalled - newState = oldState & 0x7fffffff; - bAcquiredSignal = true; - } - else - { - newState = oldState + 1; - } - } - while (CryInterlockedCompareExchange(&m_state, newState, oldState) != oldState); - - if (!bAcquiredSignal) - { - if (!timeout) - { - m_innerEvent.Wait(); - } - else - { - bTimedOut = !m_innerEvent.Wait(timeout); - } - - if (!bTimedOut) - { - m_innerEvent.Reset(); - } - - do - { - bAcquiredSignal = false; - - oldState = m_state; - if (!bTimedOut && (oldState & 0x80000000)) - { - newState = (oldState & 0x7fffffff) - 1; - bAcquiredSignal = true; - } - else - { - newState = oldState - 1; - } - } - while (CryInterlockedCompareExchange(&m_state, newState, oldState) != oldState); - } - } - - return bAcquiredSignal; - } - -private: - CStreamEngineWakeEvent(const CStreamEngineWakeEvent&); - CStreamEngineWakeEvent& operator = (const CStreamEngineWakeEvent&); - -private: - volatile LONG m_state; - CryEvent m_innerEvent; -}; - -struct SStreamEngineTempMemStats -{ - enum - { - MaxWakeEvents = 8, - }; - - SStreamEngineTempMemStats() - { - memset(this, 0, sizeof(*this)); - } - - void* TempAlloc(CMTSafeHeap* pHeap, size_t nSize, const char* szDbgSource, bool bFallBackToMalloc = true, bool bUrgent = false, uint32 align = 0); - void TempFree(CMTSafeHeap* pHeap, const void* p, size_t nSize); - void ReportTempMemAlloc(uint32 nSizeAlloc, uint32 nSizeFree, bool bTriggerWake); - - volatile LONG m_nTempAllocatedMemory; - volatile LONG m_nTempAllocatedMemoryFrameMax; - int m_nTempMemoryBudget; - CStreamEngineWakeEvent* m_wakeEvents[MaxWakeEvents]; - int m_nWakeEvents; -}; - -struct SStreamJobEngineState -{ - std::vector* pReportQueues; - -#if defined(STREAMENGINE_ENABLE_STATS) - SStreamEngineStatistics* pStats; - SStreamEngineDecompressStats* pDecompressStats; -#endif - - SStreamEngineTempMemStats* pTempMem; - - CMTSafeHeap* pHeap; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMASYNCFILEREQUEST_H diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamAsyncFileRequest_Jobs.cpp b/Code/CryEngine/CrySystem/StreamEngine/StreamAsyncFileRequest_Jobs.cpp deleted file mode 100644 index b8bebb49c3..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamAsyncFileRequest_Jobs.cpp +++ /dev/null @@ -1,531 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include - -#include -#include "StreamAsyncFileRequest.h" - -#include "MTSafeAllocator.h" - -namespace AZ::IO::ZipDir::ZipDirStructuresInternal -{ - extern void ZlibInflateElementPartial_Impl( - int* pReturnCode, z_stream* pZStream, ZipDir::UncompressLookahead* pLookahead, - uint8_t* pOutput, size_t nOutputLen, bool bOutputWriteOnly, - const uint8_t* pInput, size_t nInputLen, size_t* pTotalOut); -} - -#ifdef STREAMENGINE_ENABLE_LISTENER -#include "IStreamEngine.h" -class NotifyListener -{ -public: - NotifyListener(IStreamEngineListener* pL, CAsyncIOFileRequest* pReq) - : m_pL(pL) - , m_pReq(pReq) - , m_bInProgress(false) {} - virtual ~NotifyListener() {} -protected: - IStreamEngineListener* m_pL; - CAsyncIOFileRequest* m_pReq; - bool m_bInProgress; -}; -class NotifyListenerInflate - : NotifyListener -{ -public: - NotifyListenerInflate(IStreamEngineListener* pL, CAsyncIOFileRequest* pReq) - : NotifyListener(pL, pReq) - { - if (m_pL) - { - m_pL->OnStreamBeginInflate(m_pReq); - m_bInProgress = true; - } - } - ~NotifyListenerInflate() - { - End(); - } - void End() - { - if (m_bInProgress) - { - m_pL->OnStreamEndInflate(m_pReq); - m_bInProgress = false; - } - } -}; -#endif - -#if defined(STREAMENGINE_ENABLE_STATS) -#define STREAMENGINE_ENABLE_TIMING -#endif - -//#define STREAM_DECOMPRESS_TRACE(...) OutputDebugString(AZStd::string::format(__VA_ARGS__).c_str()); -#define STREAM_DECOMPRESS_TRACE(...) - -void SStreamJobQueue::Flush(SStreamEngineTempMemStats& tms) -{ - extern CMTSafeHeap* g_pPakHeap; - - for (int c = m_nQueueLen, i = m_nPop % MaxJobs; c; --c, i = (i + 1) % MaxJobs) - { - Job& j = m_jobs[i]; - if (j.pSrcHdr && CryInterlockedDecrement(&j.pSrcHdr->nRefs) == 0) - { - tms.TempFree(g_pPakHeap, j.pSrc, j.pSrcHdr->nSize); - } - j.pSrc = NULL; - } -} - -int SStreamJobQueue::Push(void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nOffs, uint32 nBytes, bool bLast) -{ - m_sema.Acquire(); - - int nSlot = (m_nPush++) % MaxJobs; - - Job& j = m_jobs[nSlot]; - j.pSrc = pSrc; - j.pSrcHdr = pSrcHdr; - j.nOffs = nOffs; - j.nBytes = nBytes; - j.bLast = (uint32)bLast; - - bool bStartNext = CryInterlockedIncrement(&m_nQueueLen) == 1; - return bStartNext ? nSlot : -1; -} - -int SStreamJobQueue::Pop() -{ - int nSlot = (++m_nPop) % MaxJobs; - bool bStartNext = CryInterlockedDecrement(&m_nQueueLen) > 0; - - m_sema.Release(); - - return bStartNext ? nSlot : -1; -} - -void CAsyncIOFileRequest::AddRef() -{ - //int nRef = - CryInterlockedIncrement(&m_nRefCount); - STREAM_DECOMPRESS_TRACE("[StreamDecompress],AddRef,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), m_strFileName.c_str(), this, nRef); -} - -int CAsyncIOFileRequest::Release() -{ - int nRef = CryInterlockedDecrement(&m_nRefCount); - STREAM_DECOMPRESS_TRACE("[StreamDecompress],Release,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), m_strFileName.c_str(), this, nRef); - -#ifndef _RELEASE - if (nRef < 0) - { - __debugbreak(); - } -#endif - - if (nRef == 0) - { - Finalize(); - - CryInterlockedPushEntrySList(s_freeRequests, m_nextFree); - } - - return nRef; -} - -void CAsyncIOFileRequest::DecompressBlockEntry(SStreamJobEngineState engineState, int nJob) -{ - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::System); - - STREAM_DECOMPRESS_TRACE("[StreamDecompress],DecompressBlockEntry,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), m_strFileName.c_str(), this, nJob); - - CAsyncIOFileRequest_TransferPtr pSelf(this); - - SStreamJobQueue::Job& job = m_pDecompQueue->m_jobs[nJob]; - - void* pSrc = job.pSrc; - SStreamPageHdr* const pSrcHdr = job.pSrcHdr; - const uint32 nOffs = job.nOffs; - const uint32 nBytes = job.nBytes; - const bool bLast = job.bLast; - const bool bFailed = HasFailed(); - - if (!bFailed) - { -#if defined(STREAMENGINE_ENABLE_TIMING) - LARGE_INTEGER liStart; - QueryPerformanceCounter(&liStart); -#endif - - //printf("Inflate: %s Avail in: %d, Avail Out: %d, Next In: 0x%p, Next Out: 0x%p\n", m_strFileName.c_str(), m_pZlibStream->avail_in, m_pZlibStream->avail_out, m_pZlibStream->next_in, m_pZlibStream->next_out); - -#ifdef STREAMENGINE_ENABLE_LISTENER - NotifyListenerInflate inflateListener(gEnv->pSystem->GetStreamEngine()->GetListener(), this); -#endif - - size_t nBytesDecomped = m_nBytesDecompressed; - - STREAM_DECOMPRESS_TRACE ("[StreamDecompress],ZlibInflateElementPartial_Impl,0x%x,%s,0x%p,%i,0x%p,%i,%i\n", - CryGetCurrentThreadId(), - m_strFileName.c_str(), - (uint8_t*)m_pReadMemoryBuffer + nBytesDecomped, - m_nFileSize - nBytesDecomped, - (uint8_t*)pSrc + nOffs, - nBytes, - nBytesDecomped); - - int readStatus = Z_OK; - - { - CryOptionalAutoLock decompLock(m_externalBufferLockDecompress, m_pExternalMemoryBuffer != NULL); - - AZ::IO::ZipDir::ZipDirStructuresInternal::ZlibInflateElementPartial_Impl( - &readStatus, - m_pZlibStream, - m_pLookahead, - (uint8_t*)m_pReadMemoryBuffer + nBytesDecomped, - m_nFileSize - nBytesDecomped, - m_bWriteOnlyExternal, - (uint8_t*)pSrc + nOffs, - nBytes, - &nBytesDecomped - ); - } - - m_nBytesDecompressed = nBytesDecomped; - - //inform listen, so aysnc callback does not overlap -#ifdef STREAMENGINE_ENABLE_LISTENER - inflateListener.End(); -#endif - - if (readStatus == Z_OK || readStatus == Z_STREAM_END) - { -#if defined(STREAMENGINE_ENABLE_TIMING) - LARGE_INTEGER liEnd, liFreq; - QueryPerformanceCounter(&liEnd); - QueryPerformanceFrequency(&liFreq); - - m_unzipTime += CTimeValue((int64)((liEnd.QuadPart - liStart.QuadPart) * CTimeValue::TIMEVALUE_PRECISION / liFreq.QuadPart)); -#endif - } - else - { -#ifndef _RELEASE - AZ_Assert(false, "Decomp Error: %s : %s\n", m_strFileName.c_str(), m_pZlibStream ? m_pZlibStream->msg : "m_pZlibStream == NULL, no message available"); -#endif - Failed(ERROR_DECOMPRESSION_FAIL); - } - } - - if (pSrcHdr) - { - if (CryInterlockedDecrement(&pSrcHdr->nRefs) == 0) - { - engineState.pTempMem->TempFree(engineState.pHeap, pSrc, pSrcHdr->nSize); - } - } - - job.pSrc = NULL; - - int nPopSlot = m_pDecompQueue->Pop(); - - // job is no longer valid - - if (HasFailed() || bLast) - { - JobFinalize_Decompress(pSelf, engineState); - } - else if (nPopSlot >= 0) - { - // Chain start the next job, we're responsible for it. - STREAM_DECOMPRESS_TRACE("[StreamDecompress],Chaining,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), m_strFileName.c_str(), this, nPopSlot); - JobStart_Decompress(pSelf, engineState, nPopSlot); - } - -#if defined(STREAMENGINE_ENABLE_STATS) - CryInterlockedDecrement(&engineState.pStats->nCurrentDecompressCount); -#endif -} - -////////////////////////////////////////////////////////////////////////// - -uint32 CAsyncIOFileRequest::PushDecompressPage(const SStreamJobEngineState& engineState, void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nBytes, bool bLast) -{ - uint32 nError = 0; - - for (uint32 nBlockPos = 0; !nError && (nBlockPos < nBytes); nBlockPos += STREAMING_BLOCK_SIZE) - { - bool bLastBlock = (nBlockPos + STREAMING_BLOCK_SIZE) >= nBytes; - uint32 nBlockSize = min(nBytes - nBlockPos, (uint32)STREAMING_BLOCK_SIZE); - - nError = PushDecompressBlock(engineState, pSrc, pSrcHdr, nBlockPos, nBlockSize, bLast && bLastBlock); - } - - return nError; -} - -uint32 CAsyncIOFileRequest::PushDecompressBlock(const SStreamJobEngineState& engineState, void* pSrc, SStreamPageHdr* pSrcHdr, uint32 nOffs, uint32 nBytes, bool bLast) -{ - uint32 nError = m_nError; - - if (!nError) - { - if (pSrcHdr) - { - CryInterlockedIncrement(&pSrcHdr->nRefs); - } - - int nPushJob = m_pDecompQueue->Push(pSrc, pSrcHdr, nOffs, nBytes, bLast); - if (nPushJob >= 0) - { - STREAM_DECOMPRESS_TRACE("[StreamDecompress],PushDecompressBlock,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), m_strFileName.c_str(), this, nPushJob); - - AddRef(); - CAsyncIOFileRequest_TransferPtr pSelf(this); - JobStart_Decompress(pSelf, engineState, nPushJob); - } - } - - return nError; -} - -void CAsyncIOFileRequest::JobStart_Decompress(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState, int nJob) -{ - STREAM_DECOMPRESS_TRACE("[StreamDecompress],QueueDecompressBlockAppend,0x%x,%s,0x%p,%i\n", CryGetCurrentThreadId(), pSelf->m_strFileName.c_str(), &pSelf, nJob); - -#if defined(STREAMENGINE_ENABLE_STATS) - CryInterlockedIncrement(&engineState.pStats->nCurrentDecompressCount); -#endif - - CAsyncIOFileRequest* request = pSelf.Relinquish(); - if (!request->m_decompJobExecutor) - { - request->m_decompJobExecutor = AZStd::make_unique(); - } - request->m_decompJobExecutor->StartJob([request, engineState, nJob]() - { - request->DecompressBlockEntry(engineState, nJob); - }); // Legacy JobManager priority: eStreamPriority -} - -////////////////////////////////////////////////////////////////////////// -void CAsyncIOFileRequest::JobFinalize_Read(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState) -{ - if (!pSelf->m_bCompressedBuffer || pSelf->HasFailed()) - { - JobFinalize_Transfer(pSelf, engineState); - } -} - -void CAsyncIOFileRequest::JobFinalize_Decompress(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState) -{ - STREAM_DECOMPRESS_TRACE("[StreamDecompress],FinalizeDecompress,0x%x,%s,0x%p,0x%p,0x%p,0x%p\n", CryGetCurrentThreadId(), pSelf->m_strFileName.c_str(), &pSelf, &engineState, engineState.pStats, engineState.pDecompressStats); - - CAsyncIOFileRequest* pReq = &*pSelf; - - if (!pReq->HasFailed()) - { - // Handle reads of subsections of a compressed file, by copying the section to the output - uint8_t* pDst = (uint8_t*)pReq->m_pOutputMemoryBuffer; - uint8_t* pSrc = (uint8_t*)pReq->m_pReadMemoryBuffer + pReq->m_nRequestedOffset; - - if (pDst != pSrc) - { - memmove(pReq->m_pOutputMemoryBuffer, pSrc, pReq->m_nRequestedSize); - } - - pReq->JobFinalize_Validate(engineState); - } - - pReq->JobFinalize_Buffer(engineState); - -#if defined(STREAMENGINE_ENABLE_STATS) && defined(STREAMENGINE_ENABLE_TIMING) - if (pReq->m_unzipTime.GetValue() != 0) - { - engineState.pDecompressStats->m_nTotalBytesUnziped += pReq->m_nFileSize; - engineState.pDecompressStats->m_totalUnzipTime += pReq->m_unzipTime; - - engineState.pDecompressStats->m_nTempBytesUnziped += pReq->m_nFileSize; - engineState.pDecompressStats->m_tempUnzipTime += pReq->m_unzipTime; - } -#endif - - JobFinalize_Transfer(pSelf, engineState); -} - -void CAsyncIOFileRequest::JobFinalize_Buffer(const SStreamJobEngineState& engineState) -{ - if (CryInterlockedDecrement(&m_nMemoryBufferUsers) == 0) - { - z_stream_s* pZlib = m_pZlibStream; - - if (pZlib) - { - //if the stream was cancelled in flight, inform zlib to free internal allocs - if (pZlib->state) - { - inflateEnd(pZlib); - } - - m_pZlibStream = NULL; - } - - if (m_pMemoryBuffer) - { - engineState.pTempMem->TempFree(engineState.pHeap, m_pMemoryBuffer, m_nMemoryBufferSize); - - m_pMemoryBuffer = NULL; - m_nMemoryBufferSize = 0; - } - } -} - -void CAsyncIOFileRequest::JobFinalize_Validate([[maybe_unused]] const SStreamJobEngineState& engineState) -{ -#if defined(SKIP_CHECKSUM_FROM_OPTICAL_MEDIA) - if (m_eMediaType != eStreamSourceTypeDisc) -#endif //SKIP_CHECKSUM_FROM_OPTICAL_MEDIA - { - CryOptionalAutoLock readLock(m_externalBufferLockRead, m_pExternalMemoryBuffer != NULL); - if (!HasFailed()) - { - if (m_crc32FromHeader != 0 && m_nPageReadStart == 0 && m_nRequestedSize == m_nFileSize) //Compute the CRC32 if appropriate. - { -#if defined(STREAMENGINE_ENABLE_TIMING) - LARGE_INTEGER liStart, liEnd, liFreq; - QueryPerformanceCounter(&liStart); -#endif //STREAMENGINE_ENABLE_TIMING - - uint32 nCRC32 = crc32(0, (uint8_t*)m_pReadMemoryBuffer + m_nPageReadStart, m_nRequestedSize); - -#if defined(STREAMENGINE_ENABLE_TIMING) - QueryPerformanceCounter(&liEnd); - QueryPerformanceFrequency(&liFreq); - - m_verifyTime += CTimeValue((int64)((liEnd.QuadPart - liStart.QuadPart) * CTimeValue::TIMEVALUE_PRECISION / liFreq.QuadPart)); - - engineState.pDecompressStats->m_nTotalBytesVerified += m_nFileSize; - engineState.pDecompressStats->m_totalVerifyTime += m_verifyTime; - engineState.pDecompressStats->m_nTempBytesVerified += m_nFileSize; - engineState.pDecompressStats->m_tempVerifyTime += m_verifyTime; -#endif //STREAMENGINE_ENABLE_TIMING - - if (m_crc32FromHeader != nCRC32) - { - //The contents of this file don't match what the header expects -#if !defined(_RELEASE) - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR_DBGBRK, "Streaming Engine Failed to verify a file (%s). Computed CRC32 %d does not match stored CRC32 %d", m_strFileName.c_str(), nCRC32, m_crc32FromHeader); -#endif //!_RELEASE - Failed(ERROR_VERIFICATION_FAIL); - } - } - } - } -} - -void CAsyncIOFileRequest::JobFinalize_Transfer(CAsyncIOFileRequest_TransferPtr& pSelf, const SStreamJobEngineState& engineState) -{ - STREAM_DECOMPRESS_TRACE("[StreamDecompress],FinalizeTransform,0x%x,%s,0x%p,0x%p,0x%p,0x%p\n", CryGetCurrentThreadId(), pSelf->m_strFileName.c_str(), &pSelf, &engineState, engineState.pStats, engineState.pDecompressStats); - - if (CryInterlockedCompareExchange(&pSelf->m_nFinalised, 1, 0) == 0) - { -#if defined(STREAMENGINE_ENABLE_STATS) - CryInterlockedIncrement(&engineState.pStats->nCurrentAsyncCount); -#endif - -#if defined(STREAMENGINE_ENABLE_TIMING) - pSelf->m_completionTime = gEnv->pTimer->GetAsyncTime(); -#endif - - int nCallbackThreads = engineState.pReportQueues->size(); - - EStreamTaskType eType = pSelf->m_eType; - if (nCallbackThreads > 1 && eType == eStreamTaskTypeGeometry) - { - // If we have more then 1 call back threads, use this one for geometry only. - (*engineState.pReportQueues)[1]->TransferRequest(pSelf); - } - else if (nCallbackThreads > 2 && eType == eStreamTaskTypeTexture) - { - // If we have more then 1 call back threads, use this one for textures only. - (*engineState.pReportQueues)[2]->TransferRequest(pSelf); - } - else if (nCallbackThreads > 3 && eType == eStreamTaskTypeMergedMesh) - { - // If we have more then 3 call back threads, use this one for merged meshes only. - (*engineState.pReportQueues)[3]->TransferRequest(pSelf); - } - else if (nCallbackThreads > 0) - { - (*engineState.pReportQueues)[0]->TransferRequest(pSelf); - } - else - { - __debugbreak(); - } - } -} - -////////////////////////////////////////////////////////////////////////// -void SStreamRequestQueue::TransferRequest(CAsyncIOFileRequest_TransferPtr& pRequest) -{ - { - CryAutoLock l(m_lock); - - m_requests.push_back(pRequest.Relinquish()); - } - - m_awakeEvent.Set(); -} - -////////////////////////////////////////////////////////////////////////// -void SStreamEngineTempMemStats::TempFree(CMTSafeHeap* pHeap, const void* p, size_t nSize) -{ -#if MTSAFE_USE_GENERAL_HEAP - bool bInGenHeap = pHeap->IsInGeneralHeap(p); -#else - bool bInGenHeap = false; -#endif - pHeap->FreeTemporary(const_cast(p)); - ReportTempMemAlloc(0, bInGenHeap ? 0 : nSize, true); -} - -void SStreamEngineTempMemStats::ReportTempMemAlloc(uint32 nSizeAlloc, uint32 nSizeFree, bool bTriggerWake) -{ - int nAdd = (int)nSizeAlloc - (int)nSizeFree; - int const nOldSize = CryInterlockedExchangeAdd(&m_nTempAllocatedMemory, nAdd); - int const nNewSize = nOldSize + nAdd; - - LONG nNewMax = 0; - LONG nOldMax = 0; - do - { - nOldMax = m_nTempAllocatedMemoryFrameMax; - nNewMax = (LONG)max((int)nNewSize, (int)nOldMax); - } - while (CryInterlockedCompareExchange(&m_nTempAllocatedMemoryFrameMax, nNewMax, nOldMax) != nOldMax); - - if (bTriggerWake) - { - for (int i = 0, c = m_nWakeEvents; i != c; ++i) - { - m_wakeEvents[i]->Set(); - } - } -} diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp b/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp deleted file mode 100644 index 7f8c75b2a8..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.cpp +++ /dev/null @@ -1,1698 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Streaming Engine implementation - - -#include "CrySystem_precompiled.h" -#include "StreamEngine.h" - -//CReadStream is 99% unused since the introduction of AZRequestReadStream. -//In the near future CReadStream will disappear altogether and StreamReadStream cpp/h -// won't be needed anymore. -#include "StreamReadStream.h" - -#include "AZRequestReadStream.h" -#include "Pak/CryPakUtils.h" - -#include "../System.h" - -#include -#include - -#include -#include - -#define MAX_HEAVY_ASSETS 20 - -#if defined(STREAMENGINE_ENABLE_STATS) -SStreamEngineStatistics* g_pStreamingStatistics = 0; -#endif - -SStreamEngineOpenStats* g_pStreamingOpenStatistics = 0; - -extern CMTSafeHeap* g_pPakHeap; - -////////////////////////////////////////////////////////////////////////// -CStreamEngine::CStreamEngine() - : AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDebug()) -{ - m_nBatchMode = 0; - m_bShutDown = false; - m_bUseOpticalDriveThread = g_cvars.sys_streaming_use_optical_drive_thread != 0; - m_nPausedDataTypesMask = 0; - m_bStreamDataOnHDD = gEnv->pCryPak->IsInstalledToHDD(); - -#ifdef STREAMENGINE_ENABLE_STATS - g_pStreamingStatistics = &m_Statistics; - m_Statistics.nPendingReadBytes = 0; - - m_Statistics.nCurrentAsyncCount = 0; - m_Statistics.nCurrentDecompressCount = 0; - m_Statistics.nCurrentFinishedCount = 0; - - memset(&m_decompressStats, 0, sizeof(m_decompressStats)); - - m_nUnzipBandwidth = 0; - m_nUnzipBandwidthAverage = 0; - m_bStreamingStatsPaused = false; - m_bInputCallback = false; - m_bTempMemOutOfBudget = false; - - ClearStatistics(); -#endif - - memset(&m_OpenStatistics, 0, sizeof(m_OpenStatistics)); - g_pStreamingOpenStatistics = &m_OpenStatistics; - -#ifdef STREAMENGINE_ENABLE_LISTENER - m_pListener = NULL; -#endif - - StartThreads(); - - // register system listener - GetISystem()->GetISystemEventDispatcher()->RegisterListener(this); -} - -////////////////////////////////////////////////////////////////////////// -// MT: Main thread only -CStreamEngine::~CStreamEngine() -{ -#ifdef STREAMENGINE_ENABLE_STATS - g_pStreamingStatistics = 0; - if (m_bInputCallback) - { - AzFramework::InputChannelEventListener::Disconnect(); - } -#endif - g_pStreamingOpenStatistics = NULL; - Shutdown(); -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::BeginReadGroup() -{ - CryInterlockedIncrement(&m_nBatchMode); -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::EndReadGroup() -{ - CryInterlockedDecrement(&m_nBatchMode); - - for (int i = 0; i < eIOThread_Last; i++) - { - if (m_pThreadIO[i]) - { - // New requests accomulated untill all Start stream requests are submitted and can be properly sorted. - m_pThreadIO[i]->SignalStartWork(false); - } - } -} - -AZ::IO::IStreamerTypes::Priority CStreamEngine::CryStreamPriorityToAZStreamPriority(EStreamTaskPriority cryPriority) -{ - switch (cryPriority) - { - case estpUrgent: - return AZ::IO::IStreamerTypes::s_priorityHighest; - // estpPreempted = 1, //For internal use only - case estpAboveNormal: - return AZ::IO::IStreamerTypes::s_priorityHigh; - case estpNormal: - return AZ::IO::IStreamerTypes::s_priorityMedium; - case estpBelowNormal: - return AZ::IO::IStreamerTypes::s_priorityLow; - case estpIdle: - [[fallthrough]]; - default: - return AZ::IO::IStreamerTypes::s_priorityLowest; - } -} - -AZStd::chrono::milliseconds CStreamEngine::AZDeadlineFromReadParams(const StreamReadParams& params) -{ - - if (params.nLoadTime == 0) - { - // File should be loaded right away. - return AZStd::chrono::milliseconds(0); - } - else - { - return AZStd::chrono::milliseconds(AZStd::max(params.nLoadTime, params.nMaxLoadTime)); - } -} - -////////////////////////////////////////////////////////////////////////// -// Starts asynchronous read from the specified file -// It is expected that the callbacks are called from Main Thread only when -// the async data loading is finished. -IReadStreamPtr CStreamEngine::StartRead (const EStreamTaskType tSource, const char* szFilePath, IStreamCallback* pCallback, const StreamReadParams* pParams) -{ - using namespace AZ::IO; - - if (!szFilePath) - { - CryFatalError("Use of the stream engine without a file is deprecated! Use the job system."); - return NULL; - } - - if (gEnv->IsDedicated()) - { - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Attempting to use the stream engine on a dedicated server! Don't do that!"); - return NULL; - } - - if (!m_bShutDown) - { - AZRequestReadStream* pStream = AZRequestReadStream::Allocate(tSource, szFilePath, pCallback, pParams); - if (!pStream) - { - CryFatalError("Failed to create Request Stream for %s", szFilePath); - return nullptr; - } - - size_t offset = pParams ? pParams->nOffset : 0; - AZStd::chrono::microseconds deadline = pParams - ? AZStd::chrono::duration_cast(AZDeadlineFromReadParams(*pParams)) - : AZStd::chrono::microseconds(0); - AZ::IO::IStreamerTypes::Priority priority = pParams - ? CryStreamPriorityToAZStreamPriority(pParams->ePriority) - : AZ::IO::IStreamerTypes::s_priorityHighest; - - // Add a ref to stream before binding to the callback. Callback will release the reference when it's invoked. - pStream->AddRef(); - - auto callback = [this, pStream](FileRequestHandle request) - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRenderDetailed); - auto streamer = AZ::Interface::Get(); - void* buffer = nullptr; - AZ::u64 bytesRead = 0; - [[maybe_unused]] bool result = streamer->GetReadRequestResult(request, buffer, bytesRead); - AZ_Assert(result, "Cry Stream Engine requested a callback on reading, but couldn't retrieve result."); - QueueRequestCompleteJob(pStream, bytesRead, buffer, streamer->GetRequestStatus(request)); - // Release reference that was taken above in order to hold onto stream while job is queued - pStream->Release(); - }; - - // Register stream and start file request. - IReadStreamPtr result = static_cast(pStream); - - auto streamer = AZ::Interface::Get(); - FileRequestPtr azRequest = streamer->Read(szFilePath, pStream->GetFileReadBuffer(), pStream->GetFileSize(), - pStream->GetFileSize(), deadline, priority, offset); - streamer->SetRequestCompleteCallback(azRequest, callback); - pStream->SetFileRequest(azRequest); - streamer->QueueRequest(azRequest); - - return result; - } - - return NULL; -} - -//It is NOT necessary to schedule the callbacks on the main thread. -//Regular async calls is OK. -size_t CStreamEngine::StartBatchRead(IReadStreamPtr* pStreamsOut, const StreamReadBatchParams* pReqs, size_t numReqs, AZStd::function* preRequestCallback) -{ - using namespace AZ::IO; - - FUNCTION_PROFILER(GetISystem(), PROFILE_SYSTEM); - - size_t nValidStreams = 0; - - if (!m_bShutDown) - { - enum - { - MaxStreamsPerBatch = 32 - }; - - size_t nReqIdx = 0; - - // we have requests to evaluate, call the callback before enqueing the requests - if (numReqs > 0 && preRequestCallback != nullptr) - { - (*preRequestCallback)(); - } - - if (numReqs > 0) - { - numReqs = AZStd::min(numReqs, aznumeric_cast(MaxStreamsPerBatch)); - AZStd::vector batch; - - auto streamer = AZ::Interface::Get(); - streamer->CreateRequestBatch(batch, numReqs); - - while (numReqs > 0) - { - const StreamReadBatchParams& args = pReqs[nReqIdx]; - - if (!args.szFile) - { - CryFatalError("Use of the stream engine without a file is deprecated! Use the job system."); - } - - AZRequestReadStream* pStream; - - { - FRAME_PROFILER_FAST("CStreamEngine::StartBatchRead_AllocReadStream", gEnv->pSystem, PROFILE_SYSTEM, gEnv->bProfilerEnabled); - pStream = AZRequestReadStream::Allocate(args.tSource, args.szFile, args.pCallback, &args.params); - } - - if (pStream) - { - FileRequestPtr& request = batch[nValidStreams]; - pStreamsOut[nValidStreams++] = pStream; - - // Add a ref to stream before binding to the callback. Callback will release the reference when it's invoked. - pStream->AddRef(); - auto callback = [this, pStream](FileRequestHandle request) - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRenderDetailed); - auto streamer = AZ::Interface::Get(); - void* buffer = nullptr; - AZ::u64 bytesRead = 0; - [[maybe_unused]] bool result = streamer->GetReadRequestResult(request, buffer, bytesRead); - AZ_Assert(result, "Cry Stream Engine requested a callback on reading, but couldn't retrieve result."); - QueueRequestCompleteJob(pStream, bytesRead, buffer, streamer->GetRequestStatus(request)); - // Release reference that was taken above in order to hold onto stream while job is queued - pStream->Release(); - }; - - streamer->Read(request, args.szFile, pStream->GetFileReadBuffer(), pStream->GetFileSize(), - pStream->GetFileSize(), AZDeadlineFromReadParams(args.params), - CryStreamPriorityToAZStreamPriority(args.params.ePriority), args.params.nOffset); - streamer->SetRequestCompleteCallback(request, callback); - pStream->SetFileRequest(request); - } - else - { - CryFatalError("Failed to create Request Stream for %s at mip number %d", args.szFile, (int)nReqIdx); - } - - --numReqs; - ++nReqIdx; - } - - streamer->QueueRequestBatch(AZStd::move(batch)); - } - } - - return nValidStreams; -} - -void CStreamEngine::QueueRequestCompleteJob(AZRequestReadStream* stream, AZ::IO::SizeType numBytesRead, void* buffer, - AZ::IO::IStreamerTypes::RequestStatus requestState) -{ - // Some graphics APIs don't support multiple threads instancing resources such as textures. To work around this limitation - // the jobs that complete a streaming request are queued and a previous request will kick off the next one. This will cause - // only one job that finishes a streaming request to ever be active without causing mutexes to cause stalls in the job system. - - // Add a ref to stream before binding to the callback. Callback will release the reference when it's invoked. - stream->AddRef(); - auto jobFunction = [this, stream, numBytesRead, buffer, requestState]() - { - stream->OnRequestComplete(numBytesRead, buffer, requestState); - // Release reference that was taken above in order to hold onto stream while job is queued - stream->Release(); - - CryAutoLock lock(m_pendingRequestCompletionsLock); - AZ_Assert(!m_pendingRequestCompletions.empty(), - "CStreamEngine::QueueRequestCompleteJob expects at least one job in the queue as this is this is the job ran from the callback.") - // The top request is always the one that's running, so pop that one of the queue and start any other pending jobs. - m_pendingRequestCompletions.pop(); - if (!m_pendingRequestCompletions.empty()) - { - m_pendingRequestCompletions.front()->Start(); - } - }; - - AZ::Job* job = AZ::CreateJobFunction(jobFunction, true, AZ::JobContext::GetGlobalContext()); - - CryAutoLock lock(m_pendingRequestCompletionsLock); - if (m_pendingRequestCompletions.empty()) - { - m_pendingRequestCompletions.push(job); - job->Start(); - } - else - { - m_pendingRequestCompletions.push(job); - } -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::ResumePausedStreams_PauseLocked() -{ - for (size_t i = 0; i < (size_t)m_pausedStreams.size(); ) - { - CReadStream* pStream = (CReadStream*)(IReadStream*)m_pausedStreams[i]; - int nStreamMask = 1 << (uint32)pStream->m_Type; - if (0 == (nStreamMask & m_nPausedDataTypesMask)) - { - if (pStream->GetError() == 0) // If was not aborted - { - // This stream must be resumed - m_streams.insert(pStream); - CAsyncIOFileRequest* pFileRequest = pStream->CreateFileRequest(); - if (!StartFileRequest(pFileRequest)) - { - pFileRequest->Release(); - } - } - m_pausedStreams.erase(m_pausedStreams.begin() + i); - } - else - { - i++; - } - } -} - -////////////////////////////////////////////////////////////////////////// -bool CStreamEngine::StartFileRequest(CAsyncIOFileRequest* pFileRequest) -{ - bool bStartImmidietly = m_nBatchMode == 0; - - EStreamSourceMediaType eMediaType = pFileRequest->GetMediaType(); - bool bQueued = false; - - CStreamingIOThread* pIO = m_pThreadIO[0]; - - for (size_t i = 1; i < eIOThread_Last; ++i) - { - CStreamingIOThread* pAltIO = m_pThreadIO[i]; - - if (pAltIO && pAltIO->GetMediaType() == eMediaType) - { - pIO = pAltIO; - break; - } - } - - if (pIO) - { -#ifdef STREAMENGINE_ENABLE_LISTENER - if (m_pListener) - { - m_pListener->OnStreamEnqueue(pFileRequest, pFileRequest->m_strFileName.c_str(), pFileRequest->m_pReadStream->GetCallerType(), pFileRequest->m_pReadStream->GetParams()); - } -#endif - - pIO->AddRequest(pFileRequest, bStartImmidietly); - bQueued = true; - } - - if (!bQueued) - { - assert(0); // No IO thread. - return false; - } - -#ifdef STREAMENGINE_ENABLE_STATS - m_Statistics.typeInfo[pFileRequest->m_eType].nTotalStreamingRequestCount++; - - if (g_cvars.sys_streaming_debug == 3) - { - const char* const sFileFilter = g_cvars.sys_streaming_debug_filter_file_name->GetString(); - - if (!pFileRequest->m_strFileName.empty() && !m_bStreamingStatsPaused) - { - if (!sFileFilter || !sFileFilter[0] || strstr(pFileRequest->m_strFileName.c_str(), sFileFilter)) - { - CryAutoCriticalSection lock(m_csStats); - m_statsRequestList.insert(m_statsRequestList.begin(), pFileRequest); - } - } - } -#endif - - return true; -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::SignalToStartWork(EIOThread e, bool bForce) -{ - if ((e >= 0) && (e < eIOThread_Last)) - { - if (m_pThreadIO[e]) - { - m_pThreadIO[e]->SignalStartWork(bForce); - } - } -} - -////////////////////////////////////////////////////////////////////////// - -#ifdef STREAMENGINE_ENABLE_STATS -void UpdateIOThreadStats( - SStreamEngineStatistics::SMediaTypeInfo* pNotInMemoryInfo, - SStreamEngineStatistics::SMediaTypeInfo* pInMemoryInfo, - CStreamingIOThread* pIOThread, - float fSecSinceLastReset) -{ - if (pNotInMemoryInfo == 0 || pIOThread == 0) - { - return; - } - - // not in memory reading - pNotInMemoryInfo->fActiveDuringLastSecond = pIOThread->m_NotInMemoryStats.m_fReadingDuringLastSecond; - pNotInMemoryInfo->fAverageActiveTime = - pIOThread->m_NotInMemoryStats.m_TotalReadTime.GetSeconds() / fSecSinceLastReset * 100; - - pNotInMemoryInfo->nBytesRead = pIOThread->m_NotInMemoryStats.m_nReadBytesInLastSecond; - pNotInMemoryInfo->nRequestCount = pIOThread->m_NotInMemoryStats.m_nRequestCountInLastSecond; - pNotInMemoryInfo->nTotalBytesRead = pIOThread->m_NotInMemoryStats.m_nTotalReadBytes; - pNotInMemoryInfo->nTotalRequestCount = pIOThread->m_NotInMemoryStats.m_nTotalRequestCount; - - pNotInMemoryInfo->nSeekOffsetLastSecond = pIOThread->m_NotInMemoryStats.m_nReadOffsetInLastSecond; - if (pIOThread->m_NotInMemoryStats.m_nTotalRequestCount > 0) - { - pNotInMemoryInfo->nAverageSeekOffset = pIOThread->m_NotInMemoryStats.m_nTotalReadOffset / - pIOThread->m_NotInMemoryStats.m_nTotalRequestCount; - } - else - { - pNotInMemoryInfo->nAverageSeekOffset = 0; - } - - pNotInMemoryInfo->nCurrentReadBandwidth = pIOThread->m_NotInMemoryStats.m_nCurrentReadBandwith; - pNotInMemoryInfo->nSessionReadBandwidth = (uint32)(pNotInMemoryInfo->nTotalBytesRead / fSecSinceLastReset); - - pNotInMemoryInfo->nActualReadBandwidth = pIOThread->m_NotInMemoryStats.m_nActualReadBandwith; - float fTotalReadTime = pIOThread->m_NotInMemoryStats.m_TotalReadTime.GetSeconds(); - if (fTotalReadTime > 0.0f) - { - pNotInMemoryInfo->nAverageActualReadBandwidth = (uint32)(pNotInMemoryInfo->nTotalBytesRead / fTotalReadTime); - } - - // in memory reading - if (pInMemoryInfo) - { - pInMemoryInfo->nBytesRead = pIOThread->m_InMemoryStats.m_nReadBytesInLastSecond; - pInMemoryInfo->nRequestCount = pIOThread->m_InMemoryStats.m_nRequestCountInLastSecond; - pInMemoryInfo->nTotalBytesRead = pIOThread->m_InMemoryStats.m_nTotalReadBytes; - pInMemoryInfo->nTotalRequestCount = pIOThread->m_InMemoryStats.m_nTotalRequestCount; - } -} -#endif - -void CStreamEngine::Update(uint32 nUpdateTypesBitmask) -{ - FUNCTION_PROFILER_LEGACYONLY(GetISystem(), PROFILE_SYSTEM); - AZ_TRACE_METHOD(); - LOADING_TIME_PROFILE_SECTION(gEnv->pSystem); - - // Dispatch completed callbacks. - MainThread_FinalizeIOJobs(nUpdateTypesBitmask); -} - -// Gets called regularly, to finalize those proxies whose jobs have -// already been executed (e.g. to call the callbacks) -// - to be called from the main thread only -// - starts new jobs in the single-threaded model -void CStreamEngine::Update() -{ - FUNCTION_PROFILER(GetISystem(), PROFILE_SYSTEM); - LOADING_TIME_PROFILE_SECTION(gEnv->pSystem); - - // Dispatch completed callbacks. - MainThread_FinalizeIOJobs(); - -#ifdef STREAMENGINE_ENABLE_STATS - if (g_cvars.sys_streaming_resetstats) - { - ClearStatistics(); - g_cvars.sys_streaming_resetstats = 0; - } - - CTimeValue t = gEnv->pTimer->GetAsyncTime(); - if ((t - m_nLastBandwidthUpdateTime).GetMilliSecondsAsInt64() > 1000) - { - // Repeat every second. - m_nUnzipBandwidth = m_decompressStats.m_tempUnzipTime.GetValue() == 0 ? 0 : (uint32)(m_decompressStats.m_nTempBytesUnziped / m_decompressStats.m_tempUnzipTime.GetSeconds()); - m_nVerifyBandwidth = m_decompressStats.m_tempVerifyTime.GetValue() == 0 ? 0 : (uint32)(m_decompressStats.m_nTempBytesVerified / m_decompressStats.m_tempVerifyTime.GetSeconds()); - - m_decompressStats.m_tempUnzipTime.SetValue(0); - m_decompressStats.m_nTempBytesUnziped = 0; - m_decompressStats.m_tempVerifyTime.SetValue(0); - m_decompressStats.m_nTempBytesVerified = 0; - - m_nLastBandwidthUpdateTime = t; - } - if (m_decompressStats.m_totalUnzipTime.GetValue() != 0) - { - m_nUnzipBandwidthAverage = (uint32)(m_decompressStats.m_nTotalBytesUnziped / m_decompressStats.m_totalUnzipTime.GetSeconds()); - } - if (m_decompressStats.m_totalVerifyTime.GetValue() != 0) - { - m_nVerifyBandwidthAverage = (uint32)(m_decompressStats.m_nTotalBytesVerified / m_decompressStats.m_totalVerifyTime.GetSeconds()); - } - - m_Statistics.nDecompressBandwidth = m_nUnzipBandwidth; - m_Statistics.nVerifyBandwidth = m_nVerifyBandwidth; - m_Statistics.nDecompressBandwidthAverage = m_nUnzipBandwidthAverage; - m_Statistics.nVerifyBandwidthAverage = m_nVerifyBandwidthAverage; - - CTimeValue currentTime = gEnv->pTimer->GetAsyncTime(); - - CTimeValue timeSinceLastReset = currentTime - m_TimeOfLastReset; - float fSecSinceLastReset = timeSinceLastReset.GetSeconds(); - - CTimeValue timeSinceLastUpdate = currentTime - m_TimeOfLastUpdate; - - // update the stats every second - if (timeSinceLastUpdate.GetMilliSecondsAsInt64() > 1000) - { - UpdateIOThreadStats(&m_Statistics.hddInfo, &m_Statistics.memoryInfo, m_pThreadIO[eIOThread_HDD], fSecSinceLastReset); - UpdateIOThreadStats(&m_Statistics.discInfo, 0, m_pThreadIO[eIOThread_Optical], fSecSinceLastReset); - UpdateIOThreadStats(&m_Statistics.memoryInfo, 0, m_pThreadIO[eIOThread_InMemory], fSecSinceLastReset); - - SStreamEngineStatistics::SRequestTypeInfo totals; - - // update stats on all types - for (int i = 0; i < eStreamTaskTypeCount; i++) - { - SStreamEngineStatistics::SRequestTypeInfo& info = m_Statistics.typeInfo[i]; - - if (info.nTotalStreamingRequestCount) - { - info.fAverageCompletionTime = info.fTotalCompletionTime / info.nTotalStreamingRequestCount; - } - else - { - info.fAverageCompletionTime = 0; - } - info.nSessionReadBandwidth = (uint32)(info.nTotalReadBytes / fSecSinceLastReset); - info.nCurrentReadBandwidth = (uint32)(info.nTmpReadBytes / timeSinceLastUpdate.GetSeconds()); - - info.fAverageRequestCount = info.nTotalStreamingRequestCount / fSecSinceLastReset; - - totals.Merge(info); - - info.nTmpReadBytes = 0; - } - - if (totals.nTotalStreamingRequestCount > 0) - { - m_Statistics.fAverageCompletionTime = totals.fTotalCompletionTime / totals.nTotalStreamingRequestCount; - } - - m_Statistics.nTotalSessionReadBandwidth = (uint32)(totals.nTotalReadBytes / fSecSinceLastReset); - m_Statistics.nTotalCurrentReadBandwidth = (uint32)(totals.nTmpReadBytes / timeSinceLastUpdate.GetSeconds()); - m_Statistics.fAverageRequestCount = totals.nTotalStreamingRequestCount / fSecSinceLastReset; - - m_Statistics.nTotalRequestCount = totals.nTotalRequestCount; - m_Statistics.nTotalStreamingRequestCount = totals.nTotalStreamingRequestCount; - m_Statistics.nTotalBytesRead = totals.nTotalReadBytes; - - // update this flag only once a second to be sure it's visible in display info - m_Statistics.bTempMemOutOfBudget = m_bTempMemOutOfBudget; - m_bTempMemOutOfBudget = false; - - m_TimeOfLastUpdate = currentTime; - } - - int nTmpAllocated = m_tempMem.m_nTempAllocatedMemoryFrameMax; - m_Statistics.nMaxTempMemory = max(m_Statistics.nMaxTempMemory, nTmpAllocated); - m_Statistics.nTempMemory = nTmpAllocated; - - m_tempMem.m_nTempAllocatedMemoryFrameMax = m_tempMem.m_nTempAllocatedMemory; - - if (m_Statistics.vecHeavyAssets.size() > MAX_HEAVY_ASSETS) - { - AZStd::sort(m_Statistics.vecHeavyAssets.begin(), m_Statistics.vecHeavyAssets.end()); - m_Statistics.vecHeavyAssets.resize(MAX_HEAVY_ASSETS); - } - - if (g_cvars.sys_streaming_debug) - { - DrawStatistics(); - - if (!m_bInputCallback) - { - AzFramework::InputChannelEventListener::Connect(); - m_bInputCallback = true; - } - } -#endif -} - -////////////////////////////////////////////////////////////////////////// -// Only waits at most the specified amount of time for some IO to complete -void CStreamEngine::UpdateAndWait(bool bAbortAll) -{ - // for stream->Wait sync - LOADING_TIME_PROFILE_SECTION(gEnv->pSystem); - - if (bAbortAll) - { - for (int i = 0; i < eIOThread_Last; i++) - { - if (m_pThreadIO[i]) - { - m_pThreadIO[i]->AbortAll(bAbortAll); - } - } - } - - while (!m_finishedStreams.empty() || !m_streams.empty()) - { - Update(); - // In case we still have cancelled or aborted streams in the queue, - // we wake the io threads here to ensure they are removed correctly; - for (uint32 i = 0; i < (uint32)eIOThread_Last; ++i) - { - SignalToStartWork((EIOThread)i, true); - } - CrySleep(10); - } - - if (bAbortAll) - { - for (int i = 0; i < eIOThread_Last; i++) - { - if (m_pThreadIO[i]) - { - m_pThreadIO[i]->AbortAll(false); - } - } - } -} - -// In the Multi-Threaded model (with the IO Worker thread) -// removes the proxies from the IO Queue as needed, and the proxies may call their callbacks -void CStreamEngine::MainThread_FinalizeIOJobs(uint32 type) -{ - static bool bNoReentrant = false; - - if (!bNoReentrant) - { - bNoReentrant = true; - - FUNCTION_PROFILER(GetISystem(), PROFILE_SYSTEM); - LOADING_TIME_PROFILE_SECTION(gEnv->pSystem); - -#ifdef STREAMENGINE_ENABLE_STATS - m_Statistics.nMainStreamingThreadWait = CryGetTicks(); -#endif - - int nCount = 0; - - CryMT::vector finishedStreams; - // Dispatch completed callbacks. - CReadStream_AutoPtr pStream(0); - while (m_finishedStreams.try_pop_front(pStream)) - { - if (pStream->m_Type & type) - { - pStream->MainThread_Finalize(); - -#ifdef STREAMENGINE_ENABLE_STATS - // update statistics - CryInterlockedDecrement(&m_Statistics.nCurrentFinishedCount); - UpdateStatistics(pStream); -#endif - - m_streams.erase(pStream); - - nCount++; - // perform time slicing if requested - if (g_cvars.sys_streaming_max_finalize_per_frame > 0 && - nCount > g_cvars.sys_streaming_max_finalize_per_frame) - { - break; - } - } - else - { - finishedStreams.push_back(pStream); - } - } - - bNoReentrant = false; - - while (finishedStreams.try_pop_front(pStream)) - { - m_finishedStreams.push_back(pStream); - } - -#ifdef STREAMENGINE_ENABLE_STATS - m_Statistics.nMainStreamingThreadWait = CryGetTicks() - m_Statistics.nMainStreamingThreadWait; -#endif - } -} - - -// In the Multi-Threaded model (with the IO Worker thread) -// removes the proxies from the IO Queue as needed, and the proxies may call their callbacks -void CStreamEngine::MainThread_FinalizeIOJobs() -{ - static bool bNoReentrant = false; - - if (!bNoReentrant) - { - bNoReentrant = true; - - FUNCTION_PROFILER(GetISystem(), PROFILE_SYSTEM); - LOADING_TIME_PROFILE_SECTION(gEnv->pSystem); - -#ifdef STREAMENGINE_ENABLE_STATS - m_Statistics.nMainStreamingThreadWait = CryGetTicks(); -#endif - - int nCount = 0; - - //Optim: swap finished streams out into a non MT vector - //avoid expensive push / pop operations. - m_tempFinishedStreams.clear(); - m_finishedStreams.swap(m_tempFinishedStreams); - - int numFinishedStreams = m_tempFinishedStreams.size(); - - // Dispatch completed callbacks. - for (int i = 0; i < numFinishedStreams; i++) - { - CReadStream_AutoPtr pStream = m_tempFinishedStreams[i]; - - //Check for a certain type of error that we need to handle in a TRC compliant way - if (pStream->GetError() == ERROR_VERIFICATION_FAIL) - { -#if !defined(_RELEASE) - CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_COMMENT, "Stream error detected."); -#endif //!_RELEASE - } - - pStream->MainThread_Finalize(); - -#ifdef STREAMENGINE_ENABLE_STATS - // update statistics - CryInterlockedDecrement(&m_Statistics.nCurrentFinishedCount); - UpdateStatistics(pStream); -#endif - - m_streams.erase(pStream); - - nCount++; - - // AM: Optim, no longer support this behavior - // perform time slicing if requested - if (g_cvars.sys_streaming_max_finalize_per_frame > 0 && - nCount > g_cvars.sys_streaming_max_finalize_per_frame) - { - CryLogAlways("sys_streaming_max_finalize_per_frame is now deprecated"); - //break; - } - } - - m_tempFinishedStreams.clear(); - - bNoReentrant = false; - -#ifdef STREAMENGINE_ENABLE_STATS - m_Statistics.nMainStreamingThreadWait = CryGetTicks() - m_Statistics.nMainStreamingThreadWait; -#endif - } -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::UpdateJobPriority(IReadStreamPtr pJobStream) -{ - for (int i = 0; i < eIOThread_Last; i++) - { - if (m_pThreadIO[i]) - { - m_pThreadIO[i]->NeedSorting(); - } - } -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::StopThreads() -{ - for (int i = 0; i < eIOThread_Last; i++) - { - m_pThreadIO[i] = 0; - } - - m_asyncCallbackThreads.clear(); - m_tempMem.m_nWakeEvents = 0; -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::StartThreads() -{ - StopThreads(); - - m_tempMem.m_nWakeEvents = 0; - - m_pThreadIO[eIOThread_HDD] = new CStreamingIOThread(this, eStreamSourceTypeHDD, "Streaming File IO HDD");//, 160); - m_tempMem.m_wakeEvents[m_tempMem.m_nWakeEvents++] = &m_pThreadIO[eIOThread_HDD]->GetWakeEvent(); - - if (!(gEnv->IsDedicated())) - { - if (m_bUseOpticalDriveThread) - { - m_pThreadIO[eIOThread_Optical] = new CStreamingIOThread(this, eStreamSourceTypeDisc, "Streaming File IO Optical"); - m_tempMem.m_wakeEvents[m_tempMem.m_nWakeEvents++] = &m_pThreadIO[eIOThread_Optical]->GetWakeEvent(); - } - - m_pThreadIO[eIOThread_InMemory] = new CStreamingIOThread(this, eStreamSourceTypeMemory, "Streaming File IO InMemory"); - m_tempMem.m_wakeEvents[m_tempMem.m_nWakeEvents++] = &m_pThreadIO[eIOThread_InMemory]->GetWakeEvent(); - } - - // Initialise fallback thread matrix, needed for rescheduling - for (int i = 0; i < eIOThread_Last; ++i) - { - if (!m_pThreadIO[i]) - { - continue; - } - - for (int j = 0; j < eIOThread_Last; ++j) - { - if (i == j) - { - continue; - } - if (!m_pThreadIO[j]) - { - continue; - } - - m_pThreadIO[i]->RegisterFallbackIOThread(m_pThreadIO[j]->GetMediaType(), m_pThreadIO[j]); - } - } - - // More decompress threads can be added here. - m_asyncCallbackQueues.push_back(new SStreamRequestQueue); - m_asyncCallbackThreads.push_back(new CStreamingWorkerThread(this, "Streaming AsyncCallback", CStreamingWorkerThread::eWorkerAsyncCallback, m_asyncCallbackQueues.back())); - - //m_asyncCallbackThreads.push_back( new CStreamingWorkerThread(this,"Streaming AsyncCallback Pak 1",CStreamingWorkerThread::eWorkerAsyncCallback, m_asyncCallbackQueues[eStreamTaskTypePak]) ); -} - -//! Puts the memory statistics into the given sizer object -//! According to the specifications in interface ICrySizer -void CStreamEngine::GetMemoryStatistics(ICrySizer* pSizer) -{ - SIZER_COMPONENT_NAME(pSizer, "CRefStreamEngine"); - - size_t nSize = sizeof(*this); - - pSizer->AddObject(this, nSize); -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::AbortJob(CReadStream* pStream) -{ - if (m_finishedStreams.try_remove((CReadStream*)pStream)) - { -#ifdef STREAMENGINE_ENABLE_STATS - CryInterlockedDecrement(&m_Statistics.nCurrentFinishedCount); -#endif - } - - { - CryAutoLock pausedLock(m_pausedLock); - if (!m_pausedStreams.empty()) - { - std::vector::iterator it = std::find(m_pausedStreams.begin(), m_pausedStreams.end(), pStream); - if (it != m_pausedStreams.end()) - { - m_pausedStreams.erase(it); - } - } - } - - m_streams.erase(pStream); -} - -#if defined(STREAMENGINE_ENABLE_STATS) -SStreamEngineStatistics& CStreamEngine::GetStreamingStatistics() -{ - return m_Statistics; -} -#endif - -#ifdef STREAMENGINE_ENABLE_STATS -void CStreamEngine::UpdateStatistics(CReadStream* pReadStream) -{ - uint32 nBytesRead = pReadStream->m_nBytesRead; - - SStreamEngineStatistics::SRequestTypeInfo& info = m_Statistics.typeInfo[pReadStream->m_Type]; - info.nTotalRequestCount++; - - // only add to stats if request was valid - const string& name = pReadStream->GetName(); - if (name.length() > 0) - { - info.nTotalReadBytes += nBytesRead; - info.nTmpReadBytes += nBytesRead; - info.nTotalRequestDataSize += pReadStream->m_Params.nSize; - - CTimeValue completionTime = gEnv->pTimer->GetAsyncTime() - pReadStream->GetRequestTime(); - float fCompletionTime = completionTime.GetMilliSeconds(); - info.fTotalCompletionTime += fCompletionTime; - - size_t splitter = name.find_last_of("."); - if (splitter != string::npos) - { - string extension = name.substr(splitter + 1); - TExtensionInfoMap::iterator findRes = m_PerExtensionInfo.find(extension); - if (findRes == m_PerExtensionInfo.end()) - { - m_PerExtensionInfo[extension] = SExtensionInfo(); - findRes = m_PerExtensionInfo.find(extension); - } - - SExtensionInfo& extensionInfo = findRes->second; - extensionInfo.m_fTotalReadTime += pReadStream->m_ReadTime.GetMilliSeconds(); - extensionInfo.m_nTotalRequests++; - extensionInfo.m_nTotalReadSize += nBytesRead; - extensionInfo.m_nTotalRequestSize += pReadStream->m_Params.nSize; - } - } - - if (nBytesRead > 64 * 1024) - { - m_Statistics.vecHeavyAssets.push_back(SStreamEngineStatistics::SAsset(pReadStream->m_strFileName, nBytesRead)); - } -} -#endif - -void CStreamEngine::Shutdown() -{ - m_bShutDown = true; - - // make sure we don't have queued paused streams during shutdown for the audio system - // or we can suffer from deadlocks - uint32 nPauseMask = GetPauseMask(); - uint32 nUnPauseMask = ~(nPauseMask & ~STREAM_TASK_TYPE_AUDIO_ALL); - PauseStreaming(false, nUnPauseMask); - PauseStreaming(true, nPauseMask); - - UpdateAndWait(true); - CancelAll(); - - StopThreads(); - - m_streams.clear(); - m_finishedStreams.clear(); - - // unregister system listener - GetISystem()->GetISystemEventDispatcher()->RemoveListener(this); -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::CancelAll() -{ - for (int i = 0; i < eIOThread_Last; i++) - { - if (m_pThreadIO[i]) - { - m_pThreadIO[i]->BeginReset(); - } - } - - for (int i = 0; i < eIOThread_Last; i++) - { - if (m_pThreadIO[i]) - { - m_pThreadIO[i]->EndReset(); - } - } - - for (size_t i = 0; i < m_asyncCallbackThreads.size(); ++i) - { - m_asyncCallbackThreads[i]->BeginReset(); - } - for (size_t i = 0; i < m_asyncCallbackThreads.size(); ++i) - { - m_asyncCallbackThreads[i]->EndReset(); - } - - // make sure we don't check for canceled tasks when destroying the m_finishedStreams container - m_streams.clear(); - stl::free_container(m_finishedStreams); - stl::free_container(m_tempFinishedStreams); - { - CryAutoLock lock(m_pausedLock); - - std::vector paused; - paused.swap(m_pausedStreams); - - for (std::vector::iterator it = paused.begin(), itEnd = paused.end(); it != itEnd; ++it) - { - CReadStream* pStream = &**it; - pStream->AbortShutdown(); - } - } - - CReadStream::Flush(); - CAsyncIOFileRequest::Flush(); -} - - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::ReportAsyncFileRequestComplete(CAsyncIOFileRequest_AutoPtr pFileRequest) -{ - if (!pFileRequest->IsCancelled()) - { -#ifdef STREAMENGINE_ENABLE_LISTENER - if (m_pListener) - { - m_pListener->OnStreamBeginAsyncCallback(&*pFileRequest); - } -#endif - - if (pFileRequest->m_pCallback) - { - pFileRequest->m_pCallback->OnAsyncFinished(pFileRequest); - } - if (pFileRequest->m_pReadStream) - { - CReadStream_AutoPtr pStream = (CReadStream*)(IReadStream*)pFileRequest->m_pReadStream; - pStream->OnAsyncFileRequestComplete(); - m_finishedStreams.push_back(pStream); - -#ifdef STREAMENGINE_ENABLE_STATS - CryInterlockedIncrement(&m_Statistics.nCurrentFinishedCount); -#endif - } - -#ifdef STREAMENGINE_ENABLE_LISTENER - if (m_pListener) - { - m_pListener->OnStreamEndAsyncCallback(&*pFileRequest); - } -#endif - -#ifdef STREAMENGINE_ENABLE_STATS - if (g_cvars.sys_streaming_debug != 0) - { - if (g_cvars.sys_streaming_debug == 2 || g_cvars.sys_streaming_debug == 4) - { - const char* const sFileFilter = g_cvars.sys_streaming_debug_filter_file_name->GetString(); - - if (!pFileRequest->m_strFileName.empty() && !m_bStreamingStatsPaused) - { - if (!sFileFilter || !sFileFilter[0] || strstr(pFileRequest->m_strFileName.c_str(), sFileFilter)) - { - CryAutoCriticalSection lock(m_csStats); - m_statsRequestList.insert(m_statsRequestList.begin(), pFileRequest); - } - } - } - } -#endif - } -} - -////////////////////////////////////////////////////////////////////////// -const char* CStreamEngine::GetStreamTaskTypeName(EStreamTaskType type) -{ - switch (type) - { - case eStreamTaskTypeMusic: - return "Music"; - case eStreamTaskTypeAnimation: - return "Animation"; - case eStreamTaskTypeGeometry: - return "Geometry"; - case eStreamTaskTypeSound: - return "Sound"; - case eStreamTaskTypeTexture: - return "Texture"; - case eStreamTaskTypeShader: - return "Shader"; - case eStreamTaskTypeTerrain: - return "Terrain"; - case eStreamTaskTypeVideo: - return "Video"; - case eStreamTaskTypeFlash: - return "Flash"; - case eStreamTaskTypePak: - return "Pak"; - case eStreamTaskTypeGeomCache: - return "GeomCache"; - case eStreamTaskTypeMergedMesh: - return "MergedMesh"; - } - return ""; -} - -SStreamJobEngineState CStreamEngine::GetJobEngineState() -{ - m_tempMem.m_nTempMemoryBudget = g_cvars.sys_streaming_memory_budget * 1024; - - SStreamJobEngineState state; - state.pReportQueues = &m_asyncCallbackQueues; -#ifdef STREAMENGINE_ENABLE_STATS - state.pStats = &m_Statistics; - state.pDecompressStats = &m_decompressStats; -#endif - state.pHeap = g_pPakHeap; - state.pTempMem = &m_tempMem; - return state; -} - -#ifdef STREAMENGINE_ENABLE_STATS -void CStreamEngine::GetBandwidthStats(EStreamTaskType type, float* bandwidth) -{ - *bandwidth = m_Statistics.typeInfo[type].nCurrentReadBandwidth / 1024.0f; -} -#endif - -void CStreamEngine::GetStreamingOpenStatistics(SStreamEngineOpenStats& openStatsOut) -{ - openStatsOut = m_OpenStatistics; -} - -#ifdef STREAMENGINE_ENABLE_LISTENER -void CStreamEngine::SetListener(IStreamEngineListener* pListener) -{ - m_pListener = pListener; -} -#endif - -#ifdef STREAMENGINE_ENABLE_LISTENER -IStreamEngineListener* CStreamEngine::GetListener() -{ - return m_pListener; -} -#endif - -////////////////////////////////////////////////////////////////////////// -void* CStreamEngine::TempAlloc(size_t nSize, const char* szDbgSource, bool bFallBackToMalloc, bool bUrgent, uint32 align) -{ - return m_tempMem.TempAlloc(g_pPakHeap, nSize, szDbgSource, bFallBackToMalloc, bUrgent, align); -} - -void CStreamEngine::TempFree(void* p, size_t nSize) -{ - m_tempMem.TempFree(g_pPakHeap, p, nSize); -} - -namespace -{ -#ifdef STREAMENGINE_ENABLE_STATS - void DrawText(const float, const float, ColorF, const char*, ...) - { - // ToDo: Remove whole file with SPEC-343, or update to draw with Atom? Likely the former as I think this whole system is dead. - } -#endif - - void WriteToStreamingLog([[maybe_unused]] const char* str) - { -#ifdef STREAMENGINE_ENABLE_STATS - if (g_cvars.sys_streaming_debug == 4) - { - // ignore invalid file access when logging steaming data - CDebugAllowFileAccess ignoreInvalidFileAccess; - - static string sFileName; - static bool bFirstTime = true; - if (bFirstTime) - { - char path[AZ::IO::IArchive::MaxPath]; - path[sizeof(path) - 1] = 0; - gEnv->pCryPak->AdjustFileName("@usercache@\\TestResults\\StreamingLog.txt", path, AZ_ARRAY_SIZE(path), AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FLAGS_FOR_WRITING); - sFileName = path; - } - AZ::IO::HandleType fileHandle = fxopen(sFileName, (bFirstTime) ? "wt" : "at"); - bFirstTime = false; - if (fileHandle != AZ::IO::InvalidHandle) - { - AZ::IO::Print(fileHandle, "%s\n", str); - gEnv->pFileIO->Close(fileHandle); - } - } -#endif - } -} - -#ifdef STREAMENGINE_ENABLE_STATS -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::DrawStatistics() -{ - std::vector tempRequests; - - if (g_cvars.sys_streaming_debug == 4) - { - float tx = 0; - float ty = 30; - float ystep = 12.0f; - ColorF clText(1, 0, 0, 1); - - DrawText(tx, ty += ystep, clText, "Recording streaming stats to file ..."); - - { - CryAutoCriticalSection lock(m_csStats); - tempRequests.swap(m_statsRequestList); - } - - const char* const sFileFilter = g_cvars.sys_streaming_debug_filter_file_name->GetString(); - - if (!tempRequests.empty()) - { - for (int i = (int)tempRequests.size() - 1; i >= 0; i--) - { - CAsyncIOFileRequest* pFileRequest = tempRequests[i]; - - if (g_cvars.sys_streaming_debug_filter > 0 && pFileRequest->m_eType != g_cvars.sys_streaming_debug_filter) - { - continue; - } - if (g_cvars.sys_streaming_debug_filter == -1 && pFileRequest->m_eMediaType == eStreamSourceTypeMemory) - { - continue; - } - if (g_cvars.sys_streaming_debug_filter_min_time && (pFileRequest->m_readTime.GetMilliSeconds() < (float)g_cvars.sys_streaming_debug_filter_min_time)) - { - continue; - } - if (sFileFilter && sFileFilter[0] && !strstr(pFileRequest->m_strFileName.c_str(), sFileFilter)) - { - continue; - } - - const char* sFlags = (pFileRequest->m_eMediaType == eStreamSourceTypeHDD) ? "HDD" : ((pFileRequest->m_eMediaType == eStreamSourceTypeMemory) ? "mem" : "DVD"); - const char* sPriority = ""; - switch (pFileRequest->m_ePriority) - { - case estpUrgent: - sPriority = " Urgent"; - break; - case estpNormal: - sPriority = " Normal"; - break; - case estpIdle: - sPriority = " Idle"; - break; - case estpPreempted: - sPriority = " Preempted"; - break; - case estpBelowNormal: - sPriority = "BelowNormal"; - break; - case estpAboveNormal: - sPriority = "AboveNormal"; - break; - default: - sPriority = " Unknown"; - break; - } - - string str; - str.Format("[N%6d] [%+8d] [%8d] [%6.2f ms] (%5d|%5d) [%5.3fs] <%3d> <%s> <%s> <%s> %s:", - pFileRequest->m_nReadCounter, - pFileRequest->m_nReadHeadOffsetKB, - pFileRequest->m_nDiskOffset >> 10, - pFileRequest->m_readTime.GetMilliSeconds(), - pFileRequest->m_nSizeOnMedia / 1024, - ((pFileRequest->m_nRequestedSize) ? pFileRequest->m_nRequestedSize : pFileRequest->m_nFileSize) / 1024, - (pFileRequest->m_completionTime - pFileRequest->m_startTime).GetSeconds(), - pFileRequest->m_nTimeGroup, - sPriority, - sFlags, - pFileRequest->m_pakFile.c_str(), - pFileRequest->m_strFileName.c_str()); - - WriteToStreamingLog(str.c_str()); - } - } - - return; - } - - - { - CryAutoCriticalSection lock(m_csStats); - tempRequests = m_statsRequestList; - - size_t nMaxRequests = g_cvars.sys_streaming_debug_filter_min_time ? 1000 : 100; - if (m_statsRequestList.size() > nMaxRequests) - { - m_statsRequestList.resize(nMaxRequests); - } - } - - std::vector& requests = tempRequests; - - stack_string temp; - float tx = 0; - float ty = 30; - float ystep = 12.0f; - float xColumn = 80; - ColorF clText(0, 1, 1, 1); - - SStreamEngineStatistics& stats = m_Statistics; - SStreamEngineOpenStats openStats = m_OpenStatistics; - - const char* sMediaType = m_bStreamDataOnHDD ? "HDD" : "DVD"; - const char* sStatus = (m_bStreamingStatsPaused) ? "Paused" : ""; - DrawText(tx, ty += ystep, clText, "Streaming IO: %.2f|%.2fMB/s, ACT: %3dmsec, Unzip: %.2fMB/s, Verify: %.2fMB/s, Jobs:%5d (%4d) %s %s", - (float)stats.nTotalCurrentReadBandwidth / (1024 * 1024), (float)stats.nTotalSessionReadBandwidth / (1024 * 1024), - (uint32)stats.fAverageCompletionTime, (float)stats.nDecompressBandwidth / (1024 * 1024), (float)stats.nVerifyBandwidth / (1024 * 1024), - (uint32)stats.nTotalStreamingRequestCount, (uint32)(stats.nTotalRequestCount - stats.nTotalStreamingRequestCount), - sMediaType, sStatus); - - DrawText(tx, ty += ystep, clText, "\t Request: Active:%2d (%2.1fMB) Live:%2d Decompress:%2d Async:%2d Finished:%2d Temp Pool Max:%2.1fMB", openStats.nOpenRequestCount, - (float)stats.nPendingReadBytes / (1024 * 1024), CAsyncIOFileRequest::s_nLiveRequests, stats.nCurrentDecompressCount, stats.nCurrentAsyncCount, stats.nCurrentFinishedCount, - (float)stats.nMaxTempMemory / (1024 * 1024)); - - ty += ystep; - - // HDD stats - if (stats.hddInfo.nTotalRequestCount > 0) - { - DrawText(tx, ty += ystep, clText, "HDD : Request: %3d|%5d (%4d MB|%3d KB) - BW: %1.2f|%1.2f Mb/s (Eff: %2.1f|%2.1f Mb/s) \n", - stats.hddInfo.nRequestCount, stats.hddInfo.nTotalRequestCount, (uint32)(stats.hddInfo.nTotalBytesRead / (1024 * 1024)), - (uint32)(stats.hddInfo.nTotalBytesRead / (1024 * stats.hddInfo.nTotalRequestCount)), - (float)stats.hddInfo.nCurrentReadBandwidth / (1024 * 1024), (float)stats.hddInfo.nSessionReadBandwidth / (1024 * 1024), - (float)stats.hddInfo.nActualReadBandwidth / (1024 * 1024), (float)stats.hddInfo.nAverageActualReadBandwidth / (1024 * 1024)); - DrawText(tx, ty += ystep, clText, "\t Seek: %1.2f GB - Active: %2.1f%%(%2.1f%%)", - (float)stats.hddInfo.nAverageSeekOffset / (1024 * 1024), - stats.hddInfo.fActiveDuringLastSecond, stats.hddInfo.fAverageActiveTime); - } - // Optical stats - if (stats.discInfo.nTotalRequestCount > 0) - { - DrawText(tx, ty += ystep, clText, "Disc: Request: %3d|%5d (%4d MB|%3d KB) - BW: %1.2f|%1.2f Mb/s (Eff: %2.1f|%2.1f Mb/s) \n", - stats.discInfo.nRequestCount, stats.discInfo.nTotalRequestCount, (uint32)(stats.discInfo.nTotalBytesRead / (1024 * 1024)), - (uint32)(stats.discInfo.nTotalBytesRead / (1024 * stats.discInfo.nTotalRequestCount)), - (float)stats.discInfo.nCurrentReadBandwidth / (1024 * 1024), (float)stats.discInfo.nSessionReadBandwidth / (1024 * 1024), - (float)stats.discInfo.nActualReadBandwidth / (1024 * 1024), (float)stats.discInfo.nAverageActualReadBandwidth / (1024 * 1024)); - DrawText(tx, ty += ystep, clText, "\t Seek: %1.2f GB - Active: %2.1f%%(%2.1f%%)", - (float)stats.discInfo.nAverageSeekOffset / (1024 * 1024), - stats.discInfo.fActiveDuringLastSecond, stats.discInfo.fAverageActiveTime); - } - DrawText(tx, ty += ystep, clText, "Mem : Request: %3d|%5d (%4d MB)", - stats.memoryInfo.nRequestCount, stats.memoryInfo.nTotalRequestCount, (stats.memoryInfo.nTotalBytesRead / (1024 * 1024))); - - ty += ystep; - - for (int i = eStreamTaskTypeCount - 1; i >= 1; i--) - { - EStreamTaskType eTaskType = (EStreamTaskType)i; - SStreamEngineStatistics::SRequestTypeInfo info = stats.typeInfo[eTaskType]; - - if (g_cvars.sys_streaming_debug > 1 || info.nTotalRequestCount > 0) - { - DrawText(tx, ty += ystep, clText, "%9s: BSize:%3dKb Read:%4dMb BW:%1.2f|%1.2f Mb/s ACT:%5dms %2d(%2.1fMB)|%5d", - gEnv->pSystem->GetStreamEngine()->GetStreamTaskTypeName(eTaskType), - (uint32)(info.nTotalReadBytes / max((uint32)1, info.nTotalStreamingRequestCount) / 1024), - (uint32)(info.nTotalReadBytes / (1024 * 1024)), (float)info.nCurrentReadBandwidth / (1024 * 1024), - (float)info.nSessionReadBandwidth / (1024 * 1024), (uint32)info.fAverageCompletionTime, - openStats.nOpenRequestCountByType[eTaskType], (float)info.nPendingReadBytes / (1024 * 1024), (uint32)info.nTotalStreamingRequestCount); - } - } - - if (g_cvars.sys_streaming_debug == 5) - { - ty += ystep; - ty += ystep; - - DrawText(tx, ty += ystep, clText, "Name | Time(s) | Size(Kb) | Read(Mb) | ReqS(Mb) | Count"); - - for (TExtensionInfoMap::iterator it = m_PerExtensionInfo.begin(); it != m_PerExtensionInfo.end(); ++it) - { - SExtensionInfo& extensionInfo = it->second; - DrawText(tx, ty += ystep, clText, "%4s | %7.3f | %8d | %8.3f | %8.3f | %5d", - it->first.c_str(), extensionInfo.m_fTotalReadTime / 1000, (uint32)(extensionInfo.m_nTotalReadSize / max((size_t)1, extensionInfo.m_nTotalRequests) / 1024), - extensionInfo.m_nTotalReadSize / (1024.0f * 1024.0f), extensionInfo.m_nTotalRequestSize / (1024.0f * 1024.0f), extensionInfo.m_nTotalRequests); - } - } - else if (g_cvars.sys_streaming_debug > 1) - { - ty += ystep; - - DrawText(tx, ty += ystep, clText, "[Offset KB]"); - DrawText(tx + xColumn, ty, clText, "[io ms]\t(read | size) [t sec] [Grp] < Priority> Filename"); - - ty += ystep; - - const char* const sFileFilter = g_cvars.sys_streaming_debug_filter_file_name->GetString(); - - for (size_t i = 0, nRequests = requests.size(); i < nRequests; i++) - { - CAsyncIOFileRequest* pFileRequest = requests[i]; - - if (g_cvars.sys_streaming_debug_filter > 0 && pFileRequest->m_eType != g_cvars.sys_streaming_debug_filter) - { - continue; - } - if (g_cvars.sys_streaming_debug_filter == -1 && pFileRequest->m_eMediaType == eStreamSourceTypeMemory) - { - continue; - } - if (g_cvars.sys_streaming_debug_filter_min_time && (pFileRequest->m_readTime.GetMilliSeconds() < (float)g_cvars.sys_streaming_debug_filter_min_time)) - { - continue; - } - if (sFileFilter != 0 && sFileFilter[0] && !strstr(pFileRequest->m_strFileName.c_str(), sFileFilter)) - { - continue; - } - - { - float fMillis = pFileRequest->m_readTime.GetMilliSeconds(); - const char* sFlags = ""; - switch (pFileRequest->m_eMediaType) - { - case eStreamSourceTypeHDD: - sFlags = "HDD"; - break; - case eStreamSourceTypeDisc: - sFlags = "DVD"; - break; - case eStreamSourceTypeMemory: - sFlags = "MEM"; - break; - } - const char* sPriority = ""; - switch (pFileRequest->m_ePriority) - { - case estpUrgent: - sPriority = " Urgent"; - break; - case estpNormal: - sPriority = " Normal"; - break; - case estpIdle: - sPriority = " Idle"; - break; - case estpPreempted: - sPriority = " Preempted"; - break; - case estpBelowNormal: - sPriority = "BelowNormal"; - break; - case estpAboveNormal: - sPriority = "AboveNormal"; - break; - default: - sPriority = " Unknown"; - break; - } - uint32 nRequestedSize = (pFileRequest->m_nRequestedSize != 0) ? pFileRequest->m_nRequestedSize : pFileRequest->m_nFileSize; - - ////////////////////////////////////////////////////////////////////////// - ColorF colOffset; - if (pFileRequest->m_nReadHeadOffsetKB >= 0) - { - colOffset = ColorF (0, 1, 0, 1); // Green - if (pFileRequest->m_nReadHeadOffsetKB > 32) - { - colOffset = ColorF (0.5f, 1.f, 0, 1.f); // Cyan - } - } - else - { - colOffset = ColorF (1, 0, 0, 1); // Red - } - if (pFileRequest->m_eMediaType != eStreamSourceTypeMemory) - { - DrawText(tx, ty, colOffset, "[%+d]", pFileRequest->m_nReadHeadOffsetKB); - } - ////////////////////////////////////////////////////////////////////////// - - DrawText(tx + xColumn, ty, clText, "[%6.2f]\t(%5d|%5d) [%5.2f] [%3d] <%s> <%s>\t%s", - fMillis, pFileRequest->m_nSizeOnMedia / 1024, nRequestedSize / 1024, (pFileRequest->m_completionTime - pFileRequest->m_startTime).GetSeconds(), - pFileRequest->m_nTimeGroup, sPriority, sFlags, pFileRequest->m_strFileName.c_str()); - - ty += ystep; - } - } - } -} -#endif //STREAMENGINE_ENABLE_STATS - -#ifdef STREAMENGINE_ENABLE_STATS -void CStreamEngine::ClearStatistics() -{ - m_TimeOfLastReset = gEnv->pTimer->GetAsyncTime(); - m_TimeOfLastUpdate = m_TimeOfLastReset; - - m_Statistics.hddInfo.ResetStats(); - m_Statistics.discInfo.ResetStats(); - - m_PerExtensionInfo.clear(); - - m_Statistics.nDecompressBandwidth = 0; - m_Statistics.nVerifyBandwidth = 0; - m_Statistics.nDecompressBandwidthAverage = 0; - m_Statistics.nVerifyBandwidthAverage = 0; - - m_Statistics.nTotalBytesRead = 0; - m_Statistics.nTotalRequestCount = 0; - m_Statistics.nTotalStreamingRequestCount = 0; - - m_Statistics.nMaxTempMemory = 0; - - m_Statistics.fAverageCompletionTime = 0; - - for (int i = 0; i < eStreamTaskTypeCount; i++) - { - m_Statistics.typeInfo[i].ResetStats(); - } - m_Statistics.vecHeavyAssets.clear(); - - for (int i = 0; i < eIOThread_Last; i++) - { - if (m_pThreadIO[i]) - { - m_pThreadIO[i]->m_InMemoryStats.Reset(); - m_pThreadIO[i]->m_NotInMemoryStats.Reset(); - } - } -} -#endif - -////////////////////////////////////////////////////////////////////////// -bool CStreamEngine::OnInputChannelEventFiltered([[maybe_unused]] const AzFramework::InputChannel& inputChannel) -{ -#ifdef STREAMENGINE_ENABLE_STATS - if (g_cvars.sys_streaming_debug) - { - if (inputChannel.GetInputChannelId() == AzFramework::InputDeviceKeyboard::Key::Function11) - { - m_bStreamingStatsPaused = true; - } - if (inputChannel.GetInputChannelId() == AzFramework::InputDeviceKeyboard::Key::Function12) - { - m_bStreamingStatsPaused = false; - } - } -#endif - return false; -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam) -{ - switch (event) - { - case ESYSTEM_EVENT_GAME_POST_INIT_DONE: - { - // unpause the streaming engine, when init phase is done - PauseStreaming(false, -1); - break; - } - case ESYSTEM_EVENT_LEVEL_LOAD_PREPARE: -#if defined(STREAMENGINE_ENABLE_STATS) - ClearStatistics(); -#endif - - WriteToStreamingLog("*LEVEL_LOAD_PREPARE"); - break; - - case ESYSTEM_EVENT_LEVEL_LOAD_START: - { - WriteToStreamingLog("*LEVEL_LOAD_START"); - break; - } - case ESYSTEM_EVENT_LEVEL_LOAD_END: - { - WriteToStreamingLog("*LEVEL_LOAD_END"); - break; - } - case ESYSTEM_EVENT_LEVEL_PRECACHE_START: - { - WriteToStreamingLog("*LEVEL_LOAD_PRECACHE_START"); - break; - } - case ESYSTEM_EVENT_LEVEL_PRECACHE_END: - { - WriteToStreamingLog("*LEVEL_LOAD_PRECACHE_END"); - break; - } - case ESYSTEM_EVENT_LEVEL_UNLOAD: - { - UpdateAndWait(true); - CancelAll(); - -#if defined(STREAMENGINE_ENABLE_STATS) - ClearStatistics(); -#endif - break; - } - case ESYSTEM_EVENT_LEVEL_POST_UNLOAD: - { - UpdateAndWait(true); - CancelAll(); - -#if defined(STREAMENGINE_ENABLE_STATS) - ClearStatistics(); -#endif - } - break; - case ESYSTEM_EVENT_FAST_SHUTDOWN: - { - Shutdown(); - break; - } - } -} - -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::PauseStreaming(bool bPause, uint32 nPauseTypesBitmask) -{ - CryAutoLock pausedLock(m_pausedLock); - if (bPause) - { - m_nPausedDataTypesMask |= nPauseTypesBitmask; - } - else - { - m_nPausedDataTypesMask &= ~nPauseTypesBitmask; - ResumePausedStreams_PauseLocked(); - } -} -////////////////////////////////////////////////////////////////////////// -void CStreamEngine::PauseIO(bool bPause) -{ - for (int i = 0; i < eIOThread_Last; i++) - { - if (m_pThreadIO[i]) - { - m_pThreadIO[i]->Pause(bPause); - } - } -} -////////////////////////////////////////////////////////////////////////// diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.h b/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.h deleted file mode 100644 index 57d47b8674..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamEngine.h +++ /dev/null @@ -1,239 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Streaming Engine - - -#ifndef CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMENGINE_H -#define CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMENGINE_H -#pragma once - - -#include "IStreamEngine.h" -#include "ISystem.h" -#include "TimeValue.h" - -#include -#include "StreamIOThread.h" -#include "StreamReadStream.h" - -#include -#include -#include -#include - -enum EIOThread -{ - eIOThread_HDD = 0, - eIOThread_Optical = 1, - eIOThread_InMemory = 2, - eIOThread_Last = 3, -}; - -////////////////////////////////////////////////////////////////////////// -class CStreamEngine - : public IStreamEngine - , public ISystemEventListener - , public AzFramework::InputChannelEventListener -{ -public: - CStreamEngine(); - ~CStreamEngine(); - - void Shutdown(); - // This is called to cancel all pending requests, without sending callbacks. - void CancelAll(); - - - //Helper added to aid in migration from Cry's CStreamEngine to AZ::IO::Streamer - static AZ::IO::IStreamerTypes::Priority CryStreamPriorityToAZStreamPriority(EStreamTaskPriority cryPriority); - static AZStd::chrono::milliseconds AZDeadlineFromReadParams(const StreamReadParams& params); - - ////////////////////////////////////////////////////////////////////////// - // IStreamEngine interface - ////////////////////////////////////////////////////////////////////////// - IReadStreamPtr StartRead (const EStreamTaskType tSource, const char* szFile, IStreamCallback* pCallback, const StreamReadParams* pParams = NULL); - size_t StartBatchRead(IReadStreamPtr* pStreamsOut, const StreamReadBatchParams* pReqs, size_t numReqs, AZStd::function* preRequestCallback = nullptr); - void BeginReadGroup(); - void EndReadGroup(); - - bool IsStreamDataOnHDD() const { return m_bStreamDataOnHDD; } - void SetStreamDataOnHDD(bool bFlag) { m_bStreamDataOnHDD = bFlag; } - - void Update(); - void UpdateAndWait(bool bAbortAll = false); - void Update(uint32 nUpdateTypesBitmask); - - void GetMemoryStatistics(ICrySizer* pSizer); - -#if defined(STREAMENGINE_ENABLE_STATS) - SStreamEngineStatistics& GetStreamingStatistics(); - void ClearStatistics(); - - void GetBandwidthStats(EStreamTaskType type, float* bandwidth); -#endif - - void GetStreamingOpenStatistics(SStreamEngineOpenStats& openStatsOut); - - const char* GetStreamTaskTypeName(EStreamTaskType type); - - SStreamJobEngineState GetJobEngineState(); - SStreamEngineTempMemStats& GetTempMemStats() { return m_tempMem; } - - // Will pause or unpause streaming of specified by mask data types - void PauseStreaming(bool bPause, uint32 nPauseTypesBitmask); - // Pause/resumes any IO active from the streaming engine - void PauseIO(bool bPause); - - uint32 GetPauseMask() const { return m_nPausedDataTypesMask; } - -#if defined(STREAMENGINE_ENABLE_LISTENER) - void SetListener(IStreamEngineListener* pListener); - IStreamEngineListener* GetListener(); -#endif - - ////////////////////////////////////////////////////////////////////////// - - // updates the job priority of an IO job into the IOQueue while maintaining order in the queue - void UpdateJobPriority(IReadStreamPtr pJobStream); - - void ReportAsyncFileRequestComplete(CAsyncIOFileRequest_AutoPtr pFileRequest); - void AbortJob(CReadStream* pStream); - - - // Dispatches synchrnous callbacks, free temporary memory hold for callbacks. - void MainThread_FinalizeIOJobs(); - void MainThread_FinalizeIOJobs(uint32 type); - - void* TempAlloc(size_t nSize, const char* szDbgSource, bool bFallBackToMalloc = true, bool bUrgent = false, uint32 align = 0); - void TempFree(void* p, size_t nSize); - - uint32 GetCurrentTempMemorySize() const { return m_tempMem.m_nTempAllocatedMemory; } - void FlagTempMemOutOfBudget() - { -#ifdef STREAMENGINE_ENABLE_STATS - m_bTempMemOutOfBudget = true; -#endif - } - - ////////////////////////////////////////////////////////////////////////// - // AzFramework::InputChannelEventListener - ////////////////////////////////////////////////////////////////////////// - bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override; - ////////////////////////////////////////////////////////////////////////// - - bool StartFileRequest(CAsyncIOFileRequest* pFileRequest); - void SignalToStartWork(EIOThread e, bool bForce); - -private: - void StartThreads(); - void StopThreads(); - - void ResumePausedStreams_PauseLocked(); - -#if defined(STREAMENGINE_ENABLE_STATS) - // add job to current statistics - void UpdateStatistics(CReadStream* pReadStream); - void DrawStatistics(); -#endif - - void QueueRequestCompleteJob(class AZRequestReadStream* stream, AZ::IO::SizeType numBytesRead, void* buffer, - AZ::IO::IStreamerTypes::RequestStatus requestState); - - ////////////////////////////////////////////////////////////////////////// - // ISystemEventListener - ////////////////////////////////////////////////////////////////////////// - virtual void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam); - ////////////////////////////////////////////////////////////////////////// - -private: - - ////////////////////////////////////////////////////////////////////////// - CryMT::set m_streams; - CryMT::vector m_finishedStreams; - std::vector m_tempFinishedStreams; - - CryCriticalSection m_pendingRequestCompletionsLock; - AZStd::queue m_pendingRequestCompletions; - - // 2 IO threads. - _smart_ptr m_pThreadIO[eIOThread_Last]; - std::vector<_smart_ptr > m_asyncCallbackThreads; - std::vector m_asyncCallbackQueues; - - CryCriticalSection m_pausedLock; - std::vector m_pausedStreams; - volatile uint32 m_nPausedDataTypesMask; - - bool m_bStreamDataOnHDD; - bool m_bUseOpticalDriveThread; - - ////////////////////////////////////////////////////////////////////////// - // Streaming statistics. - ////////////////////////////////////////////////////////////////////////// - -#ifdef STREAMENGINE_ENABLE_LISTENER - IStreamEngineListener* m_pListener; -#endif - -#ifdef STREAMENGINE_ENABLE_STATS - SStreamEngineStatistics m_Statistics; - SStreamEngineDecompressStats m_decompressStats; - CTimeValue m_TimeOfLastReset; - CTimeValue m_TimeOfLastUpdate; - - CryCriticalSection m_csStats; - std::vector m_statsRequestList; - - struct SExtensionInfo - { - SExtensionInfo() - : m_fTotalReadTime(0.0f) - , m_nTotalRequests(0) - , m_nTotalReadSize(0) - , m_nTotalRequestSize(0) - { - } - float m_fTotalReadTime; - size_t m_nTotalRequests; - uint64 m_nTotalReadSize; - uint64 m_nTotalRequestSize; - }; - typedef std::map TExtensionInfoMap; - TExtensionInfoMap m_PerExtensionInfo; - - ////////////////////////////////////////////////////////////////////////// - // Used to calculate unzip/verify bandwidth for statistics. - uint32 m_nUnzipBandwidth; - uint32 m_nUnzipBandwidthAverage; - uint32 m_nVerifyBandwidth; - uint32 m_nVerifyBandwidthAverage; - CTimeValue m_nLastBandwidthUpdateTime; - - bool m_bStreamingStatsPaused; - bool m_bInputCallback; - bool m_bTempMemOutOfBudget; - ////////////////////////////////////////////////////////////////////////// -#endif - - SStreamEngineOpenStats m_OpenStatistics; - - bool m_bShutDown; - - volatile int m_nBatchMode; - - // Memory currently allocated by streaming engine for temporary storage. - SStreamEngineTempMemStats m_tempMem; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMENGINE_H diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamIOThread.cpp b/Code/CryEngine/CrySystem/StreamEngine/StreamIOThread.cpp deleted file mode 100644 index e3d184fc31..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamIOThread.cpp +++ /dev/null @@ -1,819 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Streaming Thread for IO - - -#include "CrySystem_precompiled.h" -#include "StreamIOThread.h" -#include "StreamEngine.h" -#include "../System.h" - -extern SSystemCVars g_cvars; - -//#pragma("control %push O=0") // to disable optimization - -////////////////////////////////////////////////////////////////////////// -CStreamingIOThread::CStreamingIOThread(CStreamEngine* pStreamEngine, EStreamSourceMediaType mediaType, const char* name) -{ - m_pStreamEngine = pStreamEngine; - m_bCancelThreadRequest = false; - m_bNeedSorting = false; - m_bNeedReset = false; - m_bNewRequests = false; - m_name = name; - m_eMediaType = mediaType; - m_nFallbackMTs = 0; - - m_iUrgentRequests = 0; - - m_bPaused = false; - m_bAbortReads = false; - - m_nReadCounter = 0; - m_nStreamingCPU = -1; - - Start((unsigned)(1 << g_cvars.sys_streaming_cpu), name); -} - -CStreamingIOThread::~CStreamingIOThread() -{ - Cancel(); - Stop(); - WaitForThread(); -} - -////////////////////////////////////////////////////////////////////////// -void CStreamingIOThread::AddRequest(CAsyncIOFileRequest* pRequest, bool bStartImmidietly) -{ - pRequest->AddRef(); // Acquire ownership on file request. - pRequest->m_status = CAsyncIOFileRequest::eStatusInFileQueue; - if (pRequest->m_eMediaType != eStreamSourceTypeMemory) - { - pRequest->m_eMediaType = m_eMediaType; - } - // does this ignore the tmp out of memory - if (pRequest->IgnoreOutofTmpMem()) - { - CryInterlockedIncrement(&m_iUrgentRequests); - } - m_newFileRequests.push_back(pRequest); - - if (bStartImmidietly) - { - READ_WRITE_BARRIER - m_bNewRequests = true; - m_awakeEvent.Set(); - } -} - - -////////////////////////////////////////////////////////////////////////// -void CStreamingIOThread::SignalStartWork(bool bForce) -{ - if (!m_newFileRequests.empty() || bForce) - { - READ_WRITE_BARRIER - m_bNewRequests = true; - - m_awakeEvent.Set(); - } -} - -////////////////////////////////////////////////////////////////////////// - -void CStreamingIOThread::Pause(bool bPause) -{ - m_bPaused = bPause; -} - -////////////////////////////////////////////////////////////////////////// -void CStreamingIOThread::Run() -{ - SetName(m_name); - - CTimeValue t0 = gEnv->pTimer->GetAsyncTime(); - - m_nLastReadDiskOffset = 0; - - // - // Main thread loop - while (!m_bCancelThreadRequest) - { - if (m_nStreamingCPU != g_cvars.sys_streaming_cpu) - { - m_nStreamingCPU = g_cvars.sys_streaming_cpu; - -#if defined(AZ_RESTRICTED_PLATFORM) -#undef AZ_RESTRICTED_SECTION -#define STREAMIOTHREAD_CPP_SECTION_1 1 -#define STREAMIOTHREAD_CPP_SECTION_2 2 -#endif - -#if defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION STREAMIOTHREAD_CPP_SECTION_1 -#include AZ_RESTRICTED_FILE(StreamEngine/StreamIOThread_cpp) -#endif - } - - if (m_bNewRequests || !m_newFileRequests.empty()) - { - READ_WRITE_BARRIER - ProcessNewRequests(); - } - else - { -#if defined(_RELEASE) - m_awakeEvent.Wait(); -#elif defined(STREAMENGINE_ENABLE_STATS) - // compute max time to wait - revive thread every second at least once to update stats - bool bWaiting = true; - while (bWaiting) - { - CTimeValue t1 = gEnv->pTimer->GetAsyncTime(); - CTimeValue deltaT = t1 - t0; - uint64 msec = deltaT.GetMilliSecondsAsInt64(); - if (msec < 1000) - { - bWaiting = !m_awakeEvent.Wait(1000 - (uint32)msec); - } - - if (bWaiting) - { - // update the delta time again - t1 = gEnv->pTimer->GetAsyncTime(); - deltaT = t1 - t0; - - m_InMemoryStats.Update(deltaT); - m_NotInMemoryStats.Update(deltaT); - - t0 = t1; - } - } -#endif - } - - if (m_bNeedReset) - { - ProcessReset(); - } - - bool bIsOOM = false; - - while (!m_bCancelThreadRequest && !m_fileRequestQueue.empty()) - { - CAsyncIOFileRequest_TransferPtr pFileRequest(m_fileRequestQueue.back()); - m_fileRequestQueue.pop_back(); - - assert (&*pFileRequest); - - if (pFileRequest->HasFailed()) - { - // check if request was high prio, then decr open count - if (pFileRequest->IgnoreOutofTmpMem()) - { - CryInterlockedDecrement(&m_iUrgentRequests); - } - - CAsyncIOFileRequest::JobFinalize_Read(pFileRequest, m_pStreamEngine->GetJobEngineState()); - - continue; - } - - ////////////////////////////////////////////////////////////////////////// - // When temporary memory goes out of budget we must loop here and wait until previous file requests are finished and free up memory. - // Only allow processing of requests which are flagged for processing when out of tmp memory - ////////////////////////////////////////////////////////////////////////// - if (bIsOOM && !m_bCancelThreadRequest) - { - m_pStreamEngine->FlagTempMemOutOfBudget(); - if (m_iUrgentRequests > 0) - { - if (m_bNewRequests || !m_newFileRequests.empty()) - { - READ_WRITE_BARRIER - ProcessNewRequests(); - } - - // readd the current request - m_fileRequestQueue.push_back(pFileRequest.Relinquish()); - - // search for the first request which ignores the current out of mem state - // Search for next highest priority request - std::vector::reverse_iterator rit; - for (rit = m_fileRequestQueue.rbegin(); rit != m_fileRequestQueue.rend(); ++rit) - { - if ((*rit)->IgnoreOutofTmpMem()) - { - pFileRequest = *rit; - std::vector::iterator it(rit.base()); - --it; - m_fileRequestQueue.erase(it); - break; - } - } - } - else - { - // read the current request - m_fileRequestQueue.push_back(pFileRequest.Relinquish()); - } - } - - // Simply let the io thread sleep when paused before doing any actual IO - while (m_bPaused) - { - CrySleep(10); - } - - // If at this point, the filerequest is zero, the above prioritization of - // urgent requests couldn't find a new task to displace the current - // one. As the current one had been pushed back previously, we can safely - // assume that restarting the loop will grab it again (eventually). - if (!pFileRequest) - { - break; - } - - // check if request was high prio, then decr open count - if (pFileRequest->IgnoreOutofTmpMem()) - { - CryInterlockedDecrement(&m_iUrgentRequests); - } - - bIsOOM = false; - - uint32 nSizeOnMedia = pFileRequest->m_nSizeOnMedia; - uint32 nError = 0; - - // Handle file request. - if (m_bAbortReads) - { - nError = ERROR_ABORTED_ON_SHUTDOWN; - } - else if (pFileRequest->m_bReadBegun) - { - nError = pFileRequest->ReadFileResume(this); - } - else - { - nError = pFileRequest->ReadFile(this); - } - -#ifdef STREAMENGINE_ENABLE_STATS - pFileRequest->m_nReadCounter = m_nReadCounter++; -#endif - - if (nError == 0) - { - if (pFileRequest->m_eMediaType != eStreamSourceTypeMemory) - { - pFileRequest->m_nReadHeadOffsetKB = (int32)(((int64)pFileRequest->m_nDiskOffset - m_nLastReadDiskOffset) >> 10); // in KB - m_nLastReadDiskOffset = pFileRequest->m_nDiskOffset + nSizeOnMedia; - -#ifdef STREAMENGINE_ENABLE_STATS - m_NotInMemoryStats.m_nTempReadOffset += abs(pFileRequest->m_nReadHeadOffsetKB); - m_NotInMemoryStats.m_nTotalReadOffset += abs(pFileRequest->m_nReadHeadOffsetKB); - - m_NotInMemoryStats.m_nTempRequestCount++; - - // Calc IO bandwidth only for non memory files. - m_NotInMemoryStats.m_nTempBytesRead += nSizeOnMedia; - m_NotInMemoryStats.m_TempReadTime += pFileRequest->m_readTime; -#endif - } - else - { -#ifdef STREAMENGINE_ENABLE_STATS - m_InMemoryStats.m_nTempRequestCount++; - - // Calc IO bandwidth only for in memory files. - m_InMemoryStats.m_nTempBytesRead += nSizeOnMedia; - m_InMemoryStats.m_TempReadTime += pFileRequest->m_readTime; -#endif - } - - CAsyncIOFileRequest::JobFinalize_Read(pFileRequest, m_pStreamEngine->GetJobEngineState()); - } - else - { - switch (nError) - { - case ERROR_OUT_OF_MEMORY: - bIsOOM = true; - - pFileRequest->SetPriority(estpPreempted); - - if (pFileRequest->IgnoreOutofTmpMem()) - { - CryInterlockedIncrement(&m_iUrgentRequests); - } - - m_fileRequestQueue.push_back(pFileRequest.Relinquish()); - m_bNewRequests = true; - break; - - case ERROR_PREEMPTED: - pFileRequest->SetPriority(estpPreempted); - - if (pFileRequest->IgnoreOutofTmpMem()) - { - CryInterlockedIncrement(&m_iUrgentRequests); - } - - m_fileRequestQueue.push_back(pFileRequest.Relinquish()); - m_bNewRequests = true; - break; - - case ERROR_MISSCHEDULED: - // Request tried to read a file that has changed media type. Reset the sort key - // and reschedule. - pFileRequest->m_bSortKeyComputed = 0; - AddRequest(&*pFileRequest, false); - break; - - default: - pFileRequest->SyncWithDecompress(); - pFileRequest->Failed(nError); - - CAsyncIOFileRequest::JobFinalize_Read(pFileRequest, m_pStreamEngine->GetJobEngineState()); - break; - } - } - - ////////////////////////////////////////////////////////////////////////// - if (m_bNewRequests) - { - READ_WRITE_BARRIER - ProcessNewRequests(); - } - if (m_bNeedReset) - { - ProcessReset(); - } - if (m_bNeedSorting) - { - SortRequests(); - } - - ////////////////////////////////////////////////////////////////////////// -#ifdef STREAMENGINE_ENABLE_STATS - if (g_cvars.sys_streaming_max_bandwidth != 0) - { - CTimeValue t1 = gEnv->pTimer->GetAsyncTime(); - CTimeValue deltaT = t1 - t0; - - // Sleep in case we are streaming too fast. - const float fTheoreticalReadTime = float(nSizeOnMedia) / g_cvars.sys_streaming_max_bandwidth * 0.00000095367431640625f; // / (1024*1024) - - if (fTheoreticalReadTime - deltaT.GetSeconds() > FLT_EPSILON) - { - uint32 nSleepTime = uint32(1000.f * (fTheoreticalReadTime - deltaT.GetSeconds())); - CrySleep(nSleepTime); - } - } - - CTimeValue t1 = gEnv->pTimer->GetAsyncTime(); - CTimeValue deltaT = t1 - t0; - - // update the stats every second - if (deltaT.GetMilliSecondsAsInt64() > 1000) - { - m_InMemoryStats.Update(deltaT); - m_NotInMemoryStats.Update(deltaT); - - t0 = t1; - } -#endif - } - } -} - -#ifdef STREAMENGINE_ENABLE_STATS -void CStreamingIOThread::SStats::Update(const CTimeValue& deltaT) -{ - m_nReadBytesInLastSecond = (uint32)m_nTempBytesRead; - m_nRequestCountInLastSecond = m_nTempRequestCount; - m_nTotalReadBytes += (uint32)m_nTempBytesRead; - m_nTotalRequestCount += m_nTempRequestCount; - m_TotalReadTime += m_TempReadTime; - - if (m_TempReadTime.GetValue() != 0) - { - m_nActualReadBandwith = (uint32)(m_nTempBytesRead / m_TempReadTime.GetSeconds()); - } - else - { - m_nActualReadBandwith = 0; - } - m_nCurrentReadBandwith = (uint32)(m_nTempBytesRead / deltaT.GetSeconds()); - m_fReadingDuringLastSecond = m_TempReadTime.GetSeconds() / deltaT.GetSeconds() * 100; - - if (m_nTempRequestCount > 0) - { - m_nReadOffsetInLastSecond = m_nTempReadOffset / m_nTempRequestCount; - } - else - { - m_nReadOffsetInLastSecond = 0; - } - - m_TempReadTime.SetValue(0); - m_nTempBytesRead = 0; - m_nTempReadOffset = 0; - m_nTempRequestCount = 0; -} -#endif - -////////////////////////////////////////////////////////////////////////// -void CStreamingIOThread::Cancel() -{ - m_bCancelThreadRequest = true; - m_awakeEvent.Set(); -} - -////////////////////////////////////////////////////////////////////////// -struct SCompareAsyncFileRequest -{ - bool operator()(CAsyncIOFileRequest* pFile1, CAsyncIOFileRequest* pFile2) const - { - return pFile1->m_nSortKey > pFile2->m_nSortKey; - } -}; - -////////////////////////////////////////////////////////////////////////// -void CStreamingIOThread::SortRequests() -{ - FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM); - - std::sort(m_fileRequestQueue.begin(), m_fileRequestQueue.end(), SCompareAsyncFileRequest()); - - /* - int nStartOfQueue = 0; - int64 nDiskOffsetLimit = m_nLastReadDiskOffset - 32*1024; // 32KB less only - - int nCount = (int)m_fileRequestQueue.size(); - for (int i = nCount-1; i >= 0; i--) - { - if (m_fileRequestQueue[i]->m_nDiskOffset > nDiskOffsetLimit) - { - nStartOfQueue = i+1; - break; - } - } - if (nStartOfQueue < nCount && nStartOfQueue > 0) - { - int nElements = nCount - nStartOfQueue; - // Move all elements up to nStartOfQueue, from begining of the request array to the end. - m_temporaryArray.resize(0); - // Copy to temp array elements up to nStartOfQueue - m_temporaryArray.insert( m_temporaryArray.end(),m_fileRequestQueue.begin()+nStartOfQueue,m_fileRequestQueue.end() ); - // Remove elements up to nStartOfQueue from request list - m_fileRequestQueue.erase( m_fileRequestQueue.begin()+nStartOfQueue,m_fileRequestQueue.end() ); - // Add elemenets at the end from temp array. - m_fileRequestQueue.insert( m_fileRequestQueue.begin(),m_temporaryArray.begin(),m_temporaryArray.end() ); - } - */ - m_bNeedSorting = false; -} - -void CStreamingIOThread::NeedSorting() -{ - m_bNeedSorting = true; -} - -////////////////////////////////////////////////////////////////////////// -void CStreamingIOThread::ProcessNewRequests() -{ - m_bNewRequests = false; - - std::vector temporaryArray; - temporaryArray.reserve(m_newFileRequests.size()); - m_newFileRequests.swap(temporaryArray); - - std::vector& newFiles = temporaryArray; - - if (!newFiles.empty()) - { - uint64 nCurrentKeyInProgress = m_fileRequestQueue.size() ? m_fileRequestQueue.back()->m_nSortKey : 0; - - // Compute sorting key for new file entries. - int iWakeFallback(0); - const TFallbackIOVecConstIt itEnd = m_FallbackIOThreads.end(); - const size_t fallbackNum = m_FallbackIOThreads.size(); - PREFAST_SUPPRESS_WARNING(6255) - uint8 * pFallbackSignals = fallbackNum ? (uint8*)alloca(fallbackNum) : NULL; - for (uint32 fb = 0; fb < fallbackNum; ++fb) - { - pFallbackSignals[fb] = 0; - } - - for (size_t i = 0, num = newFiles.size(); i < num; i++) - { - CAsyncIOFileRequest* pFilepRequest = newFiles[i]; - - pFilepRequest->ComputeSortKey(nCurrentKeyInProgress); - static_cast(&*pFilepRequest->m_pReadStream)->ComputedMediaType(pFilepRequest->m_eMediaType); - -#ifdef STREAMENGINE_ENABLE_LISTENER - IStreamEngineListener* pListener = m_pStreamEngine->GetListener(); - if (pListener) - { - pListener->OnStreamComputedSortKey(pFilepRequest, pFilepRequest->m_nSortKey); - } -#endif - - bool bFallback = false; - int idx = -1; - for (TFallbackIOVecConstIt it = m_FallbackIOThreads.begin(); it != itEnd && !bFallback; ++it) - { - ++idx; - if (it->second == pFilepRequest->GetMediaType()) - { - if (pFilepRequest->IgnoreOutofTmpMem()) - { - CryInterlockedDecrement(&m_iUrgentRequests); - } - (it->first)->AddRequest(pFilepRequest, true); - pFilepRequest->Release(); // Release local ownership of request (moved to fallback IO thread) - iWakeFallback++; - bFallback = true; - pFallbackSignals[idx] = 1; - } - } - if (!bFallback) - { - m_fileRequestQueue.push_back(pFilepRequest); - } - } - - for (uint32 fb = 0; fb < fallbackNum; ++fb) - { - if (pFallbackSignals[fb] != 0) - { - (m_FallbackIOThreads[fb].first)->SignalStartWork(false); - } - } - - SortRequests(); - /* - if (m_fileRequestQueue.back() != pRequest && pRequest != 0) - { - // Highest priority changed. - if (m_fileRequestQueue.back()->m_nDiskOffset < (m_nLastReadDiskOffset-32*1024)) - { - //CryLog( "Bad Offset in Queue" ); - } - } - */ - } -} - -void CStreamingIOThread::ProcessReset() -{ - if (!m_fileRequestQueue.empty()) - { - for (std::vector::iterator it = m_fileRequestQueue.begin(), itEnd = m_fileRequestQueue.end(); it != itEnd; ++it) - { - (*it)->Release(); - } - } - - stl::free_container(m_fileRequestQueue); - - if (!m_temporaryArray.empty()) - { - for (std::vector::iterator it = m_temporaryArray.begin(), itEnd = m_temporaryArray.end(); it != itEnd; ++it) - { - (*it)->Release(); - } - } - - stl::free_container(m_temporaryArray); - - m_bNeedReset = false; - m_resetDoneEvent.Set(); -} - -////////////////////////////////////////////////////////////////////////// -void CStreamingIOThread::CancelAll() -{ - { - CryMT::vector::AutoLock lock(m_newFileRequests.get_lock()); - - if (!m_newFileRequests.empty()) - { - CAsyncIOFileRequest* const* it = &m_newFileRequests.front(); - CAsyncIOFileRequest* const* itEnd = it + m_newFileRequests.size(); - for (; it != itEnd; ++it) - { - (*it)->Release(); - } - } - } - - m_newFileRequests.free_memory(); - m_iUrgentRequests = 0; -} - -void CStreamingIOThread::AbortAll(bool bAbort) -{ - m_bAbortReads = bAbort; -} - -void CStreamingIOThread::BeginReset() -{ - CancelAll(); - - m_resetDoneEvent.Reset(); - m_bNeedReset = true; - m_awakeEvent.Set(); -} - -void CStreamingIOThread::EndReset() -{ - m_resetDoneEvent.Wait(); -} -////////////////////////////////////////////////////////////////////////// -void CStreamingIOThread::RegisterFallbackIOThread(EStreamSourceMediaType mediaType, CStreamingIOThread* pIOThread) -{ - //check if media has not yet been registered - if (!pIOThread) - { - return;//no need for NULL register anymore - } - const TFallbackIOVecConstIt itEnd = m_FallbackIOThreads.end(); - for (TFallbackIOVecConstIt it = m_FallbackIOThreads.begin(); it != itEnd; ++it) - { - if (it->second == mediaType) - { - return; - } - } - m_FallbackIOThreads.push_back(std::make_pair(pIOThread, mediaType)); - m_nFallbackMTs |= 1 << mediaType; -} - -bool CStreamingIOThread::HasUrgentRequests() -{ - bool ret = false; - - if (m_iUrgentRequests > 0) - { - //lock to prevent list modification whilst traversing - m_newFileRequests.get_lock().Lock(); - - int nRequests = m_newFileRequests.size(); - - if (nRequests) - { - for (int i = 0; i < nRequests; i++) - { - if (m_newFileRequests[i]->m_ePriority == estpUrgent) - { - //printf("Urgent task pending: %s\n", m_newFileRequests[i]->m_strFileName.c_str()); - ret = true; - break; - } - } - } - m_newFileRequests.get_lock().Unlock(); - } - return ret; -} - -bool CStreamingIOThread::IsMisscheduled(EStreamSourceMediaType mt) const -{ - if (mt == m_eMediaType) - { - return false; - } - - if (m_nFallbackMTs & (1 << mt)) - { - return true; - } - - return false; -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////// -CStreamingWorkerThread::CStreamingWorkerThread(CStreamEngine* pStreamEngine, const char* name, EWorkerType type, SStreamRequestQueue* pQueue) -{ - m_type = type; - m_name = name; - m_pStreamEngine = pStreamEngine; - m_pQueue = pQueue; - m_bCancelThreadRequest = false; - m_bNeedsReset = false; - - Start((unsigned)1 << g_cvars.sys_streaming_cpu_worker, name); -} - -CStreamingWorkerThread::~CStreamingWorkerThread() -{ - Cancel(); - Stop(); - WaitForThread(); -} - -////////////////////////////////////////////////////////////////////////// -void CStreamingWorkerThread::Run() -{ - SetName(m_name); - -#if defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION STREAMIOTHREAD_CPP_SECTION_2 -#include AZ_RESTRICTED_FILE(StreamEngine/StreamIOThread_cpp) -#endif - - // Main thread loop - while (!m_bCancelThreadRequest) - { - m_pQueue->m_awakeEvent.Wait(); - m_pQueue->m_awakeEvent.Reset(); - - CAsyncIOFileRequest_AutoPtr pFileRequest; - while (!m_bCancelThreadRequest && !m_bNeedsReset && m_pQueue->TryPopRequest(pFileRequest)) - { - switch (m_type) - { - case eWorkerAsyncCallback: - { -#ifndef _RELEASE - float fTime = gEnv->pTimer->GetAsyncCurTime(); -#endif - - m_pStreamEngine->ReportAsyncFileRequestComplete(pFileRequest); -#ifndef _RELEASE - float fTime1 = gEnv->pTimer->GetAsyncCurTime(); -#endif - -#ifdef STREAMENGINE_ENABLE_STATS - CryInterlockedDecrement(&m_pStreamEngine->GetStreamingStatistics().nCurrentAsyncCount); -#endif - -#ifndef _RELEASE - if ((fTime1 - fTime) > 1.f && !pFileRequest->m_strFileName.empty()) - { - string str; - str.Format("[ACALL] %s time=%.5f\n", pFileRequest->m_strFileName.c_str(), (fTime1 - fTime)); - if (gEnv && gEnv->pSystem && gEnv->pLog) - { - gEnv->pLog->Log(str.c_str()); - } - } -#endif - } - break; - } - } - - if (m_bNeedsReset) - { - m_pQueue->Reset(); - m_bNeedsReset = false; - m_resetDoneEvent.Set(); - } - } -} - -////////////////////////////////////////////////////////////////////////// -void CStreamingWorkerThread::Cancel() -{ - m_bCancelThreadRequest = true; - m_pQueue->m_awakeEvent.Set(); -} - -////////////////////////////////////////////////////////////////////////// -void CStreamingWorkerThread::CancelAll() -{ - m_pQueue->Reset(); -} - -void CStreamingWorkerThread::BeginReset() -{ - CancelAll(); - - m_resetDoneEvent.Reset(); - m_bNeedsReset = true; - m_pQueue->m_awakeEvent.Set(); -} - -void CStreamingWorkerThread::EndReset() -{ - m_resetDoneEvent.Wait(); -} diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamIOThread.h b/Code/CryEngine/CrySystem/StreamEngine/StreamIOThread.h deleted file mode 100644 index 14bac3a372..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamIOThread.h +++ /dev/null @@ -1,193 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Streaming Thread for IO - - -#ifndef CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMIOTHREAD_H -#define CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMIOTHREAD_H -#pragma once - -#include -#include "StreamAsyncFileRequest.h" - - -class CStreamEngine; - -////////////////////////////////////////////////////////////////////////// -// Thread that performs IO operations. -////////////////////////////////////////////////////////////////////////// -class CStreamingIOThread - : public CrySimpleThread - , public CMultiThreadRefCount -{ -public: - CStreamingIOThread(CStreamEngine* pStreamEngine, EStreamSourceMediaType mediaType, const char* name); - ~CStreamingIOThread(); - - void CancelAll(); - void AbortAll(bool bAbort); - - void BeginReset(); - void EndReset(); - - void AddRequest(CAsyncIOFileRequest* pRequest, bool bStartImmidietly); - int GetRequestCount() const { return m_fileRequestQueue.size(); }; - void SortRequests(); - void NeedSorting(); - void SignalStartWork(bool bForce); - bool HasUrgentRequests(); - EStreamSourceMediaType GetMediaType() const { return m_eMediaType; } - bool IsMisscheduled(EStreamSourceMediaType mt) const; - - void Pause(bool bPause); - - void RegisterFallbackIOThread(EStreamSourceMediaType mediaType, CStreamingIOThread* pIOThread); - - CStreamEngineWakeEvent& GetWakeEvent() { return m_awakeEvent; } - - ////////////////////////////////////////////////////////////////////////// - // CrySimpleThread - ////////////////////////////////////////////////////////////////////////// - virtual void Run(); - virtual void Cancel(); - ////////////////////////////////////////////////////////////////////////// - -protected: - - void ProcessNewRequests(); - void ProcessReset(); - -public: - -#ifdef STREAMENGINE_ENABLE_STATS - struct SStats - { - SStats() - : m_nTotalReadBytes(0) - , m_nCurrentReadBandwith(0) - , m_nReadBytesInLastSecond(0) - , m_fReadingDuringLastSecond(.0f) - , m_nTempBytesRead(0) - , m_nActualReadBandwith(0) - , m_nTempReadOffset(0) - , m_nTotalReadOffset(0) - , m_nReadOffsetInLastSecond(0) - , m_nTempRequestCount(0) - , m_nTotalRequestCount(0) - , m_nRequestCountInLastSecond(0) - {} - - void Update(const CTimeValue& deltaT); - - void Reset() - { - m_nTotalReadBytes = 0; - m_nTotalReadOffset = 0; - m_nTotalRequestCount = 0; - m_TotalReadTime.SetValue(0); - } - - float m_fReadingDuringLastSecond; - CTimeValue m_TotalReadTime; - uint64 m_nTotalReadBytes; - uint64 m_nTotalReadOffset; - uint32 m_nTotalRequestCount; - uint32 m_nCurrentReadBandwith; // Read bandwidth over one second - uint32 m_nActualReadBandwith; // Actual read bandwidth extrapolated over one second - uint32 m_nReadBytesInLastSecond; - uint32 m_nRequestCountInLastSecond; - uint64 m_nReadOffsetInLastSecond; - - uint32 m_nTempRequestCount; - uint64 m_nTempBytesRead; - uint64 m_nTempReadOffset; - CTimeValue m_TempReadTime; - }; - - SStats m_InMemoryStats; - SStats m_NotInMemoryStats; -#endif - - int64 m_nLastReadDiskOffset; - int m_nStreamingCPU; - -private: - CStreamEngine* m_pStreamEngine; - std::vector m_fileRequestQueue; - std::vector m_temporaryArray; - CryMT::vector m_newFileRequests; - - EStreamSourceMediaType m_eMediaType; - uint32 m_nFallbackMTs; - - typedef std::pair TFallbackIOPair; - typedef std::vector TFallbackIOVec; - typedef TFallbackIOVec::iterator TFallbackIOVecConstIt; - TFallbackIOVec m_FallbackIOThreads; - - volatile bool m_bCancelThreadRequest; - volatile bool m_bNeedSorting; - volatile bool m_bNewRequests; - volatile bool m_bPaused; - volatile bool m_bNeedReset; - volatile bool m_bAbortReads; - - volatile int m_iUrgentRequests; - - CStreamEngineWakeEvent m_awakeEvent; - CryEvent m_resetDoneEvent; - string m_name; - uint32 m_nReadCounter; -}; - -////////////////////////////////////////////////////////////////////////// -// Thread that performs IO operations. -////////////////////////////////////////////////////////////////////////// -class CStreamingWorkerThread - : public CrySimpleThread - , public CMultiThreadRefCount -{ -public: - enum EWorkerType - { - eWorkerAsyncCallback, - }; - CStreamingWorkerThread(CStreamEngine* pStreamEngine, const char* name, EWorkerType type, SStreamRequestQueue* pQueue); - ~CStreamingWorkerThread(); - - void BeginReset(); - void EndReset(); - - void CancelAll(); - - ////////////////////////////////////////////////////////////////////////// - // CrySimpleThread - ////////////////////////////////////////////////////////////////////////// - virtual void Run(); - virtual void Cancel(); - ////////////////////////////////////////////////////////////////////////// - -private: - EWorkerType m_type; - CStreamEngine* m_pStreamEngine; - SStreamRequestQueue* m_pQueue; - - volatile bool m_bCancelThreadRequest; - volatile bool m_bNeedsReset; - - CryEvent m_resetDoneEvent; - string m_name; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMIOTHREAD_H diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamReadStream.cpp b/Code/CryEngine/CrySystem/StreamEngine/StreamReadStream.cpp deleted file mode 100644 index 729f268d78..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamReadStream.cpp +++ /dev/null @@ -1,516 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Streaming Engine - - -#include "CrySystem_precompiled.h" -#include -#include - -#include "StreamReadStream.h" -#include "StreamEngine.h" -#include "MTSafeAllocator.h" - -extern CMTSafeHeap* g_pPakHeap; -SLockFreeSingleLinkedListHeader CReadStream::s_freeRequests; - -CReadStream* CReadStream::Allocate(CStreamEngine* pEngine, const EStreamTaskType tSource, const char* szFilename, IStreamCallback* pCallback, const StreamReadParams* pParams) -{ - char* pFree = reinterpret_cast(CryInterlockedPopEntrySList(s_freeRequests)); - - CReadStream* pReq; - IF_LIKELY (pFree) - { - AZ_PUSH_DISABLE_WARNING(,"-Winvalid-offsetof") - ptrdiff_t offs = offsetof(CReadStream, m_nextFree); - AZ_POP_DISABLE_WARNING - pReq = reinterpret_cast(pFree - offs); - } - else - { - pReq = new CReadStream; - } - - pReq->m_pEngine = pEngine; - pReq->m_Type = tSource; - pReq->m_strFileName = szFilename; - pReq->m_pCallback = pCallback; - if (pParams) - { - pReq->m_Params = *pParams; - } - pReq->m_pBuffer = pReq->m_Params.pBuffer; - -#ifdef STREAMENGINE_ENABLE_STATS - pReq->m_requestTime = gEnv->pTimer->GetAsyncTime(); -#endif - - return pReq; -} - -void CReadStream::Flush() -{ - AZ_PUSH_DISABLE_WARNING(, "-Winvalid-offsetof") - ptrdiff_t offs = offsetof(CReadStream, m_nextFree); - AZ_POP_DISABLE_WARNING - - for (char* pFree = reinterpret_cast(CryInterlockedPopEntrySList(s_freeRequests)); - pFree; - pFree = reinterpret_cast(CryInterlockedPopEntrySList(s_freeRequests))) - { - CReadStream* pReq = reinterpret_cast(pFree - offs); - delete pReq; - } -} - -////////////////////////////////////////////////////////////////////////// -CReadStream::CReadStream() -{ - Reset(); -} - -////////////////////////////////////////////////////////////////////////// -CReadStream::~CReadStream() -{ -} - -// returns true if the file read was completed (successfully or unsuccessfully) -// check IsError to check if the whole requested file (piece) was read -bool CReadStream::IsFinished() -{ - return m_bFinished; -} - -// returns the number of bytes read so far (the whole buffer size if IsFinished()) -unsigned int CReadStream::GetBytesRead ([[maybe_unused]] bool bWait) -{ - if (!m_bError) - { - return m_Params.nSize; - } - return 0; -} - - -// returns the buffer into which the data has been or will be read -// at least GetBytesRead() bytes in this buffer are guaranteed to be already read -const void* CReadStream::GetBuffer () -{ - return m_pBuffer; -} - -void CReadStream::AbortShutdown() -{ - { - CryAutoCriticalSection lock(m_callbackLock); - - m_bError = true; - m_nIOError = ERROR_ABORTED_ON_SHUTDOWN; - m_bFileRequestComplete = true; - - if (m_pFileRequest) - { - __debugbreak(); - } - } - - // lock this object to avoid preliminary destruction - CReadStream_AutoPtr pLock(this); - - { - CryAutoCriticalSection lock(m_callbackLock); - - // all the callbacks have to handle error cases and needs to be called anyway, even if the stream I/O is aborted - ExecuteAsyncCallback_CBLocked(); - ExecuteSyncCallback_CBLocked(); - - m_pCallback = NULL; - } -} - -// tries to stop reading the stream; this is advisory and may have no effect -// all the callbacks will be called after this. If you just destructing object, -// dereference this object and it will automatically abort and release all associated resources. -void CReadStream::Abort() -{ - { - CryAutoCriticalSection lock(m_callbackLock); - - m_bError = true; - m_nIOError = ERROR_USER_ABORT; - m_bFileRequestComplete = true; - - if (m_pFileRequest) - { - m_pFileRequest->Cancel(); - m_pFileRequest = 0; - } - } - - // lock this object to avoid preliminary destruction - CReadStream_AutoPtr pLock(this); - - { - CryAutoCriticalSection lock(m_callbackLock); - - // all the callbacks have to handle error cases and needs to be called anyway, even if the stream I/O is aborted - ExecuteAsyncCallback_CBLocked(); - ExecuteSyncCallback_CBLocked(); - - m_pCallback = NULL; - } - - m_pEngine->AbortJob(this); -} - -bool CReadStream::TryAbort() -{ - if (!m_callbackLock.TryLock()) - { - return false; - } - - if (m_pFileRequest && !m_pFileRequest->TryCancel()) - { - m_callbackLock.Unlock(); - return false; - } - - m_bError = true; - m_nIOError = ERROR_USER_ABORT; - m_bFileRequestComplete = true; - m_pFileRequest = 0; - - // lock this object to avoid preliminary destruction - CReadStream_AutoPtr pLock(this); - - // all the callbacks have to handle error cases and needs to be called anyway, even if the stream I/O is aborted - ExecuteAsyncCallback_CBLocked(); - ExecuteSyncCallback_CBLocked(); - - m_pCallback = NULL; - - m_callbackLock.Unlock(); - - m_pEngine->AbortJob(this); - - return true; -} - -// tries to raise the priority of the read; this is advisory and may have no effect -void CReadStream::SetPriority (EStreamTaskPriority ePriority) -{ - if (m_Params.ePriority != ePriority) - { - m_Params.ePriority = ePriority; - if (m_pFileRequest && m_pFileRequest->m_status == CAsyncIOFileRequest::eStatusInFileQueue) - { - m_pEngine->UpdateJobPriority(this); - } - } -} - -// unconditionally waits until the callback is called -// i.e. if the stream hasn't yet finish, it's guaranteed that the user-supplied callback -// is called before return from this function (unless no callback was specified) -void CReadStream::Wait(int nMaxWaitMillis) -{ - // lock this object to avoid preliminary destruction - CReadStream_AutoPtr pLock(this); - - bool bNeedFinalize = (m_Params.nFlags & IStreamEngine::FLAGS_NO_SYNC_CALLBACK) == 0; - - if (!m_bFinished && !m_bError && !m_pFileRequest) - { - assert(m_pFileRequest != NULL); // If we want to Wait for stream its file request must not be NULL. - // This will almost certainly cause Dead-Lock - CryFatalError("Waiting for stream when StreamingEngine is paused"); - } - - CTimeValue t0; - - if (nMaxWaitMillis > 0) - { - t0 = gEnv->pTimer->GetAsyncTime(); - } - - while (!m_bFinished && !m_bError) - { - if (bNeedFinalize) - { - m_pEngine->MainThread_FinalizeIOJobs(); - } - if (!m_bFileRequestComplete) - { - CrySleep(5); - } - - if (nMaxWaitMillis > 0) - { - CTimeValue t1 = gEnv->pTimer->GetAsyncTime(); - if (CTimeValue(t1 - t0).GetMilliSeconds() > nMaxWaitMillis) - { - // Break if we are waiting for too long. - break; - } - } - } -} - -////////////////////////////////////////////////////////////////////////// -uint64 CReadStream::GetPriority() const -{ - return 0; -} - -// this gets called upon the IO has been executed to call the callbacks -void CReadStream::MainThread_Finalize() -{ - FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM); - - // call asynchronous callback function if needed synchronously - { - CryAutoCriticalSection lock(m_callbackLock); - ExecuteSyncCallback_CBLocked(); - } - m_pFileRequest = 0; -} - -IStreamCallback* CReadStream::GetCallback() const -{ - return m_pCallback; -} - -unsigned CReadStream::GetError() const -{ - return m_nIOError; -} - -const char* CReadStream::GetErrorName() const -{ - switch (m_nIOError) - { - case ERROR_UNKNOWN_ERROR: - return "Unknown error"; - case ERROR_UNEXPECTED_DESTRUCTION: - return "Unexpected destruction"; - case ERROR_INVALID_CALL: - return "Invalid call"; - case ERROR_CANT_OPEN_FILE: - return "Cannot open the file"; - case ERROR_REFSTREAM_ERROR: - return "Refstream error"; - case ERROR_OFFSET_OUT_OF_RANGE: - return "Offset out of range"; - case ERROR_REGION_OUT_OF_RANGE: - return "Region out of range"; - case ERROR_SIZE_OUT_OF_RANGE: - return "Size out of range"; - case ERROR_CANT_START_READING: - return "Cannot start reading"; - case ERROR_OUT_OF_MEMORY: - return "Out of memory"; - case ERROR_ABORTED_ON_SHUTDOWN: - return "Aborted on shutdown"; - case ERROR_OUT_OF_MEMORY_QUOTA: - return "Out of memory quota"; - case ERROR_ZIP_CACHE_FAILURE: - return "ZIP cache failure"; - case ERROR_USER_ABORT: - return "User aborted"; - } - return "Unrecognized error"; -} - -int CReadStream::AddRef() -{ - return CryInterlockedIncrement(&m_nRefCount); -} - -int CReadStream::Release() -{ - int nRef = CryInterlockedDecrement(&m_nRefCount); - -#ifndef _RELEASE - if (nRef < 0) - { - __debugbreak(); - } -#endif - - if (nRef == 0) - { - Reset(); - CryInterlockedPushEntrySList(s_freeRequests, m_nextFree); - } - - return nRef; -} - -void CReadStream::Reset() -{ - m_strFileName.clear(); - m_pFileRequest = NULL; - m_Params = StreamReadParams(); - memset((void*)&m_nRefCount, 0, (char*)(this + 1) - (char*)(&m_nRefCount)); -} - -void CReadStream::SetUserData(DWORD_PTR dwUserData) -{ - m_Params.dwUserData = dwUserData; -} - -////////////////////////////////////////////////////////////////////////// -void CReadStream::ExecuteAsyncCallback_CBLocked() -{ - FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM); - - if (!m_bIsAsyncCallbackExecuted && m_pCallback) - { - m_bIsAsyncCallbackExecuted = true; - m_pCallback->StreamAsyncOnComplete(this, m_nIOError); - } -} - -void CReadStream::ExecuteSyncCallback_CBLocked() -{ - FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM); - - if (!m_bIsSyncCallbackExecuted && m_pCallback && (0 == (m_Params.nFlags & IStreamEngine::FLAGS_NO_SYNC_CALLBACK))) - { - m_bIsSyncCallbackExecuted = true; - - CReadStream_AutoPtr protectMe(this); // Stream can be freed inside the callback! - - m_pCallback->StreamOnComplete(this, m_nIOError); - - // We do not need FileRequest here anymore, and not its temporary memory. - m_pFileRequest = 0; - m_pBuffer = NULL; - m_bFinished = true; - } - else - { - m_pFileRequest = 0; - m_pBuffer = NULL; - m_bFinished = true; - } - -#ifdef STREAMENGINE_ENABLE_LISTENER - IStreamEngineListener* pListener = m_pEngine->GetListener(); - if (pListener) - { - pListener->OnStreamDone(this); - } -#endif -} - -void* CReadStream::operator new (size_t sz) -{ - return CryModuleMemalign(sz, alignof(CReadStream)); -} - -void CReadStream::operator delete(void* p) -{ - CryModuleMemalignFree(p); -} - -////////////////////////////////////////////////////////////////////////// -void CReadStream::FreeTemporaryMemory() -{ - // Free temporary block. - if (m_pFileRequest) - { - m_pFileRequest->SyncWithDecompress(); - m_pFileRequest->FreeBuffer(); - } - m_pBuffer = 0; -} - -////////////////////////////////////////////////////////////////////////// -bool CReadStream::IsReqReading() -{ - if (m_strFileName.empty()) - { - return false; - } - return true; -} - -////////////////////////////////////////////////////////////////////////// -CAsyncIOFileRequest* CReadStream::CreateFileRequest() -{ - m_pFileRequest = CAsyncIOFileRequest::Allocate(m_Type); - m_pFileRequest->m_nRequestedSize = m_Params.nSize; - m_pFileRequest->m_nRequestedOffset = m_Params.nOffset; - m_pFileRequest->m_pExternalMemoryBuffer = m_pBuffer; - m_pFileRequest->m_bWriteOnlyExternal = (m_Params.nFlags & IStreamEngine::FLAGS_WRITE_ONLY_EXTERNAL_BUFFER) != 0; - m_pFileRequest->m_pReadStream = this; - m_pFileRequest->m_strFileName = m_strFileName; - m_pFileRequest->m_ePriority = m_Params.ePriority; - m_pFileRequest->m_eMediaType = m_Params.eMediaType; - - m_bFileRequestComplete = false; - return m_pFileRequest; -} - -void* CReadStream::OnNeedStorage(size_t size, bool& bAbortOnFailToAlloc) -{ - CryAutoCriticalSection lock(m_callbackLock); - - if (m_pCallback) - { - return m_pCallback->StreamOnNeedStorage(this, size, bAbortOnFailToAlloc); - } - return NULL; -} - -////////////////////////////////////////////////////////////////////////// -void CReadStream::OnAsyncFileRequestComplete() -{ - CryAutoCriticalSection lock(m_callbackLock); - - if (!m_bFileRequestComplete) - { - if (m_pFileRequest) - { - m_Params.nSize = m_pFileRequest->m_nRequestedSize; - m_pBuffer = m_pFileRequest->m_pOutputMemoryBuffer; - m_nBytesRead = m_pFileRequest->m_nSizeOnMedia; - m_nIOError = m_pFileRequest->m_nError; - m_bError = m_nIOError != 0; - if (m_bError) - { - m_nBytesRead = 0; - } - -#ifdef STREAMENGINE_ENABLE_STATS - m_ReadTime = m_pFileRequest->m_readTime; -#endif - } - - ExecuteAsyncCallback_CBLocked(); - - if (m_Params.nFlags & IStreamEngine::FLAGS_NO_SYNC_CALLBACK) - { - // We do not need FileRequest here anymore, and not its temporary memory. - m_pFileRequest = 0; - m_bFinished = true; - } - - m_bFileRequestComplete = true; - } -} - - diff --git a/Code/CryEngine/CrySystem/StreamEngine/StreamReadStream.h b/Code/CryEngine/CrySystem/StreamEngine/StreamReadStream.h deleted file mode 100644 index cf6ee25d97..0000000000 --- a/Code/CryEngine/CrySystem/StreamEngine/StreamReadStream.h +++ /dev/null @@ -1,178 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Streaming Engine - - -#ifndef CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMREADSTREAM_H -#define CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMREADSTREAM_H -#pragma once - - -#include "IStreamEngine.h" -#include "StreamAsyncFileRequest.h" - -class CStreamEngine; - -class CReadStream - : public IReadStream -{ - friend class CStreamEngine; - -public: - static CReadStream* Allocate(CStreamEngine* pEngine, const EStreamTaskType tSource, const char* szFilename, IStreamCallback* pCallback, const StreamReadParams* pParams); - static void Flush(); - -public: - CReadStream(); - virtual ~CReadStream (); - - virtual int AddRef(); - virtual int Release(); - - virtual DWORD_PTR GetUserData() {return m_Params.dwUserData; } - - // set user defined data into stream's params - virtual void SetUserData(DWORD_PTR dwUserData); - - // returns true if the file read was not successful. - virtual bool IsError() { return m_bError; }; - - // returns true if the file read was completed (successfully or unsuccessfully) - // check IsError to check if the whole requested file (piece) was read - virtual bool IsFinished(); - - // returns the number of bytes read so far (the whole buffer size if IsFinished()) - virtual unsigned int GetBytesRead (bool bWait); - - // returns the buffer into which the data has been or will be read - // at least GetBytesRead() bytes in this buffer are guaranteed to be already read - virtual const void* GetBuffer (); - - void AbortShutdown(); - - // tries to stop reading the stream; this is advisory and may have no effect - // but the callback will not be called after this. If you just destructing object, - // dereference this object and it will automatically abort and release all associated resources. - virtual void Abort(); - virtual bool TryAbort(); - - // tries to raise the priority of the read; this is advisory and may have no effect - virtual void SetPriority (EStreamTaskPriority EPriority); - - // unconditionally waits until the callback is called - // i.e. if the stream hasn't yet finish, it's guaranteed that the user-supplied callback - // is called before return from this function (unless no callback was specified) - virtual void Wait(int nMaxWaitMillis = -1); - - virtual uint64 GetPriority() const; - - virtual const StreamReadParams& GetParams() const {return m_Params; } - - virtual const EStreamTaskType GetCallerType() const { return m_Type; } - - virtual EStreamSourceMediaType GetMediaType() const { return m_MediaType; } - - // return pointer to callback routine(can be NULL) - virtual IStreamCallback* GetCallback() const; - - // return IO error # - virtual unsigned GetError() const; - - // Returns IO error name - virtual const char* GetErrorName() const; - - // return stream name - virtual const char* GetName() const { return m_strFileName.c_str(); }; - - virtual void FreeTemporaryMemory(); - - // this gets called upon the IO has been executed to call the callbacks - void MainThread_Finalize(); - - bool IsReqReading(); - -#ifdef STREAMENGINE_ENABLE_STATS - void SetRequestTime(CTimeValue& time) { m_requestTime = time; } - const CTimeValue& GetRequestTime() { return m_requestTime; } -#endif - - // decompression of zip-compressed files with default behavior - CAsyncIOFileRequest* CreateFileRequest(); - void ComputedMediaType(EStreamSourceMediaType eMT) { m_MediaType = eMT; } - void* OnNeedStorage(size_t size, bool& bAbortOnFailToAlloc); - void OnAsyncFileRequestComplete(); - CAsyncIOFileRequest* GetFileRequest() { return m_pFileRequest; } - -private: - void Reset(); - - // call the async callback - void ExecuteAsyncCallback_CBLocked(); - - // call the sync callback - void ExecuteSyncCallback_CBLocked(); - -private: - void* operator new (size_t sz); - void operator delete(void* p); - -private: - static SLockFreeSingleLinkedListHeader s_freeRequests; - -private: - STREAMENGINE_LL_ALIGN SLockFreeSingleLinkedListEntry m_nextFree; - - CryStringLocal m_strFileName; - CryCriticalSection m_callbackLock; - CAsyncIOFileRequest_AutoPtr m_pFileRequest; - - StreamReadParams m_Params; - - // Only POD types must exist below here. They will be memset! - - volatile int m_nRefCount; - CStreamEngine* m_pEngine; - - // the type of the task - EStreamTaskType m_Type; - EStreamSourceMediaType m_MediaType; - // the initial data from the user - // the callback; may be NULL - IStreamCallback* m_pCallback; - - // Bytes actually read from media. - uint32 m_nBytesRead; - - volatile bool m_bIsAsyncCallbackExecuted; - volatile bool m_bIsSyncCallbackExecuted; - volatile bool m_bFileRequestComplete; - - // the actual buffer to read to - void* m_pBuffer; - - volatile bool m_bError; - volatile bool m_bFinished; - unsigned int m_nIOError; - -#ifdef STREAMENGINE_ENABLE_STATS - // time when request was made - CTimeValue m_requestTime; - // Time for actual reading - CTimeValue m_ReadTime; -#endif -}; - -TYPEDEF_AUTOPTR(CReadStream); - -#endif // CRYINCLUDE_CRYSYSTEM_STREAMENGINE_STREAMREADSTREAM_H diff --git a/Code/CryEngine/CrySystem/SyncLock.cpp b/Code/CryEngine/CrySystem/SyncLock.cpp deleted file mode 100644 index 4fb30e2ee2..0000000000 --- a/Code/CryEngine/CrySystem/SyncLock.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" - -#include "ProjectDefines.h" -#if defined(MAP_LOADING_SLICING) - -#include "SyncLock.h" - -SSyncLock::SSyncLock(const char* name, int id, bool own) -{ - stack_string ss; - ss.Format("%s_%d", name, id); - - Open(ss); - if (own) - { - if (!IsValid()) - { - Create(ss); - number = id; - } - else - { - Close(); - } - } - else - { - number = id; - } -} - -SSyncLock::SSyncLock(const char* name, int minId, int maxId) -{ - ev = 0; - stack_string ss; - for (int i = minId; i < maxId; ++i) - { - ss.Format("%s_%d", name, i); - if (Open(ss)) - { - Close(); - continue; - } - if (Create(ss)) - { - number = i; - } - break; - } -} - -SSyncLock::~SSyncLock() -{ - Close(); -} - -void SSyncLock::Own(const char* name) -{ - o_name.Format("%s_%d", name, number); -} - -#if defined(LINUX) || defined(APPLE) - -bool SSyncLock::Open(const char* name) -{ - ev = sem_open(name, 0); - if (ev != SEM_FAILED) - { - CryLogAlways("Opened semaphore %p %s", ev, name); - } - return IsValid(); -} - -bool SSyncLock::Create(const char* name) -{ - ev = sem_open(name, O_CREAT | O_EXCL, 0777, 0); - if (ev != SEM_FAILED) - { - CryLogAlways("Created semaphore %p %s", ev, name); - } - else - { - CryLogAlways("Failed to create semaphore %s %d", name, errno); - } - return IsValid(); -} - -void SSyncLock::Signal() -{ - if (ev) - { - sem_post(ev); - } -} - -bool SSyncLock::Wait(int ms) -{ - if (!ev) - { - return false; - } - - timespec t = { 0 }; -#if defined(LINUX) - clock_gettime(CLOCK_REALTIME, &t); -#elif defined(APPLE) - // On OSX/iOS there is no sem_timedwait() - // We use repeated sem_trywait() instead - if (sem_trywait(ev) == 0) - { - return true; - } -#endif - - static const long NANOSECS_IN_MSEC = 1000000L; - static const long NANOSECS_IN_SEC = 1000000000L; - - t.tv_sec += ms / 1000; - t.tv_nsec += (ms % 1000) * NANOSECS_IN_MSEC; - if (t.tv_nsec > NANOSECS_IN_SEC) - { - t.tv_nsec -= NANOSECS_IN_SEC; - ++t.tv_sec; - } -#if defined(LINUX) - return sem_timedwait(ev, &t) == 0; //ETIMEDOUT for timeout -#elif defined (APPLE) - // t = time left, interval = max time between tries, elapsed = actual time elapsed during a try - const int num_ms_interval = 50; // poll time, in ms - const timespec interval = { 0, NANOSECS_IN_MSEC * num_ms_interval }; - while (t.tv_sec >= 0 || t.tv_nsec > interval.tv_nsec) - { - timespec remaining; - timespec elapsed = interval; - if (nanosleep(&interval, &remaining) == -1) - { - elapsed.tv_nsec -= remaining.tv_nsec; - } - t.tv_nsec -= elapsed.tv_nsec; - if (t.tv_nsec < 0L) - { - t.tv_nsec += NANOSECS_IN_SEC; - t.tv_sec -= 1; - } - if (sem_trywait(ev) == 0) - { - return true; - } - } - nanosleep(&t, NULL); - return sem_trywait(ev) == 0; -#else -#error Not implemented -#endif -} - -void SSyncLock::Close() -{ - if (ev) - { - sem_close(ev); - ev = nullptr; - if (!o_name.empty()) - { - sem_unlink(o_name); - } - } -} - -#else // defined(LINUX) || defined(APPLE) - -bool SSyncLock::Open(const char* name) -{ - ev = OpenEvent(SYNCHRONIZE, FALSE, name); - if (ev) - { - CryLogAlways("Opened event %p %s", ev, name); - } - return IsValid(); -} - -bool SSyncLock::Create(const char* name) -{ - ev = CreateEvent(NULL, FALSE, FALSE, name); - if (ev) - { - CryLogAlways("Created event %p %s", ev, name); - } - else - { - CryLogAlways("Failed to create event %s", name); - } - return IsValid(); -} - -bool SSyncLock::Wait(int ms) -{ - // CryLogAlways("Waiting %p", ev); - DWORD res = WaitForSingleObject(ev, ms); - if (res != WAIT_OBJECT_0) - { - CryLogAlways("WFS result %d", res); - } - return res == WAIT_OBJECT_0; -} - -void SSyncLock::Signal() -{ - //CryLogAlways("Signaled %p", ev); - if (!SetEvent(ev)) - { - CryLogAlways("Error signalling!"); - } -} - -void SSyncLock::Close() -{ - if (ev) - { - CryLogAlways("Closed event %p", ev); - CloseHandle(ev); - ev = 0; - } -} - -#endif // defined(LINUX) || defined(APPLE) - -bool SSyncLock::IsValid() const -{ - return ev != 0; -} - -#endif // defined(MAP_LOADING_SLICING) diff --git a/Code/CryEngine/CrySystem/SyncLock.h b/Code/CryEngine/CrySystem/SyncLock.h deleted file mode 100644 index 5e22797a6b..0000000000 --- a/Code/CryEngine/CrySystem/SyncLock.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_SYNCLOCK_H -#define CRYINCLUDE_CRYSYSTEM_SYNCLOCK_H - -#pragma once - -#if defined(LINUX) || defined(APPLE) -#include -#endif - -struct SSyncLock -{ -#if defined(LINUX) || defined(APPLE) - typedef sem_t* HandleType; -#else - typedef HANDLE HandleType; -#endif - - SSyncLock(const char* name, int id, bool own); - SSyncLock(const char* name, int minId, int maxId); - ~SSyncLock(); - - void Own(const char* name); - bool Open(const char* name); - bool Create(const char* name); - void Signal(); - bool Wait(int ms); - void Close(); - bool IsValid() const; - - HandleType ev; - int number; - string o_name; -}; - -#endif // CRYINCLUDE_CRYSYSTEM_SYNCLOCK_H diff --git a/Code/CryEngine/CrySystem/System.cpp b/Code/CryEngine/CrySystem/System.cpp index 9016ea99f1..6fcbc32b72 100644 --- a/Code/CryEngine/CrySystem/System.cpp +++ b/Code/CryEngine/CrySystem/System.cpp @@ -135,29 +135,17 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #include "XML/xml.h" #include "XML/ReadWriteXMLSink.h" -#include "StreamEngine/StreamEngine.h" -#include "PhysRenderer.h" - #include "LocalizedStringManager.h" #include "XML/XmlUtils.h" #include "SystemEventDispatcher.h" -#include "ServerThrottle.h" -#include "ResourceManager.h" #include "HMDBus.h" -#include "IZLibCompressor.h" -#include "IZlibDecompressor.h" -#include "ILZ4Decompressor.h" -#include "IZStdDecompressor.h" #include "zlib.h" #include "RemoteConsole/RemoteConsole.h" #include #include -#include "CryWaterMark.h" -WATERMARKDATA(_m); -#include "ImageHandler.h" #include #include #include @@ -173,13 +161,8 @@ WATERMARKDATA(_m); #include #endif -#if USE_STEAM -#include "Steamworks/public/steam/steam_api.h" -#endif - #include -#include #include // profilers api. @@ -189,19 +172,6 @@ VTuneFunction VTPause = NULL; // Define global cvars. SSystemCVars g_cvars; -#include "ITextModeConsole.h" - -extern int CryMemoryGetAllocatedSize(); - -// these heaps are used by underlying System structures -// to allocate, accordingly, small (like elements of std::set<..*>) and big (like memory for reading files) objects -// hopefully someday we'll have standard MT-safe heap -//CMTSafeHeap g_pakHeap; -CMTSafeHeap* g_pPakHeap = 0;// = &g_pakHeap; - -////////////////////////////////////////////////////////////////////////// -#include "Validator.h" - #include #include @@ -266,7 +236,6 @@ namespace // System Implementation. ////////////////////////////////////////////////////////////////////////// CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) - : m_imageHandler(std::make_unique()) { CrySystemRequestBus::Handler::BusConnect(); @@ -307,8 +276,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_env.pSharedEnvironment = pSharedEnvironment; ////////////////////////////////////////////////////////////////////////// - m_pStreamEngine = NULL; - m_pIFont = NULL; m_pIFontUi = NULL; m_rWidth = NULL; @@ -322,18 +289,10 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_rStencilBits = NULL; m_rFullscreen = NULL; m_sysNoUpdate = NULL; - m_pMemoryManager = NULL; m_pProcess = NULL; - - m_pValidator = NULL; m_pCmdLine = NULL; - m_pDefaultValidator = NULL; m_pLevelSystem = NULL; m_pViewSystem = NULL; - m_pIZLibCompressor = NULL; - m_pIZLibDecompressor = NULL; - m_pILZ4Decompressor = NULL; - m_pIZStdDecompressor = nullptr; m_pLocalizationManager = NULL; #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEM_CPP_SECTION_2 @@ -348,14 +307,12 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_sys_memory_debug = NULL; m_sysWarnings = NULL; m_sysKeyboard = NULL; - m_sys_GraphicsQuality = NULL; m_sys_firstlaunch = NULL; m_sys_enable_budgetmonitoring = NULL; m_sys_preload = NULL; // m_sys_filecache = NULL; m_gpu_particle_physics = NULL; - m_pCpu = NULL; m_bInitializedSuccessfully = false; m_bRelaunch = false; @@ -387,11 +344,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_pXMLUtils = new CXmlUtils(this); - m_pMemoryManager = CryGetIMemoryManager(); - m_pResourceManager = new CResourceManager; - m_pTextModeConsole = NULL; - - g_pPakHeap = new CMTSafeHeap; if (!AZ::AllocatorInstance::IsReady()) { @@ -410,7 +362,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment) m_eRuntimeState = ESYSTEM_EVENT_LEVEL_UNLOAD; m_bHasRenderedErrorMessage = false; - m_bIsSteamInitialized = false; m_pDataProbe = nullptr; #if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_MESSAGE_HANDLER @@ -433,11 +384,8 @@ CSystem::~CSystem() CRY_ASSERT(m_windowMessageHandlers.empty() && "There exists a dangling window message handler somewhere"); SAFE_DELETE(m_pXMLUtils); - SAFE_DELETE(m_pResourceManager); SAFE_DELETE(m_pSystemEventDispatcher); - SAFE_DELETE(g_pPakHeap); - AZCoreLogSink::Disconnect(); if (m_initedSysAllocator) { @@ -477,12 +425,6 @@ void CSystem::FreeLib(AZStd::unique_ptr& hLibModule) } } -////////////////////////////////////////////////////////////////////////// -IStreamEngine* CSystem::GetStreamEngine() -{ - return m_pStreamEngine; -} - ////////////////////////////////////////////////////////////////////////// IRemoteConsole* CSystem::GetIRemoteConsole() { @@ -538,14 +480,6 @@ void CSystem::ShutDown() GetIRemoteConsole()->Stop(); } - // clean up properly the console - if (m_pTextModeConsole) - { - m_pTextModeConsole->OnShutdown(); - } - - SAFE_DELETE(m_pTextModeConsole); - if (m_sys_firstlaunch) { m_sys_firstlaunch->Set("0"); @@ -582,9 +516,6 @@ void CSystem::ShutDown() // Shutdown any running VR devices. EBUS_EVENT(AZ::VR::HMDInitRequestBus, Shutdown); - // Shutdown resource manager. - m_pResourceManager->Shutdown(); - if (gEnv && gEnv->pLyShine) { gEnv->pLyShine->Release(); @@ -598,10 +529,6 @@ void CSystem::ShutDown() { ((CXConsole*)m_env.pConsole)->FreeRenderResources(); } - SAFE_RELEASE(m_pIZLibCompressor); - SAFE_RELEASE(m_pIZLibDecompressor); - SAFE_RELEASE(m_pILZ4Decompressor); - SAFE_RELEASE(m_pIZStdDecompressor); SAFE_RELEASE(m_pViewSystem); SAFE_RELEASE(m_pLevelSystem); @@ -628,7 +555,6 @@ void CSystem::ShutDown() SAFE_RELEASE(m_sysWarnings); SAFE_RELEASE(m_sysKeyboard); - SAFE_RELEASE(m_sys_GraphicsQuality); SAFE_RELEASE(m_sys_firstlaunch); SAFE_RELEASE(m_sys_enable_budgetmonitoring); @@ -640,18 +566,8 @@ void CSystem::ShutDown() SAFE_RELEASE(m_sys_min_step); SAFE_RELEASE(m_sys_max_step); - SAFE_DELETE(m_pDefaultValidator); - m_pValidator = nullptr; - SAFE_DELETE(m_pLocalizationManager); - //DebugStats(false, false);//true); - //CryLogAlways(""); - //CryLogAlways("release mode memory manager stats:"); - //DumpMMStats(true); - - SAFE_DELETE(m_pCpu); - delete m_pCmdLine; m_pCmdLine = 0; @@ -659,8 +575,7 @@ void CSystem::ShutDown() // Shut down audio as late as possible but before the streaming system and console get released! Audio::Gem::AudioSystemGemRequestBus::Broadcast(&Audio::Gem::AudioSystemGemRequestBus::Events::Release); - // Shut down the streaming system and console as late as possible and after audio! - SAFE_DELETE(m_pStreamEngine); + // Shut down console as late as possible and after audio! SAFE_RELEASE(m_env.pConsole); // Log must be last thing released. @@ -904,12 +819,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) } #endif //PROFILE_WITH_VTUNE - if (m_pStreamEngine) - { - FRAME_PROFILER("StreamEngine::Update()", this, PROFILE_SYSTEM); - m_pStreamEngine->Update(); - } - #ifndef EXCLUDE_UPDATE_ON_CONSOLE if (m_bIgnoreUpdates) { @@ -985,13 +894,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) //update time subsystem m_Time.UpdateOnFrameStart(); - ////////////////////////////////////////////////////////////////////// - // update rate limiter for dedicated server - if (m_pServerThrottle.get()) - { - m_pServerThrottle->Update(); - } - ////////////////////////////////////////////////////////////////////// //update console system if (m_env.pConsole) @@ -1024,14 +926,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) } } - ////////////////////////////////////////////////////////////////////////// - // Update Resource Manager. - ////////////////////////////////////////////////////////////////////////// - { - FRAME_PROFILER("SysUpdate:ResourceManager", this, PROFILE_SYSTEM); - m_pResourceManager->Update(); - } - // Use UI timer for CryMovie, because it should not be affected by pausing game time const float fMovieFrameTime = m_Time.GetFrameTime(ITimer::ETIMER_UI); @@ -1329,21 +1223,6 @@ void CSystem::WarningV(EValidatorModule module, EValidatorSeverity severity, int m_env.pLog->LogWithType(ltype, flags | VALIDATOR_FLAG_SKIP_VALIDATOR, "%s", szBuffer); } - //if(file) - //m_env.pLog->LogWithType( ltype, " ... caused by file '%s'",file); - - if (m_pValidator && (flags & VALIDATOR_FLAG_SKIP_VALIDATOR) == 0) - { - SValidatorRecord record; - record.file = file; - record.text = szBuffer; - record.module = module; - record.severity = severity; - record.flags = flags; - record.assetScope = m_env.pLog->GetAssetScopeString(); - m_pValidator->Report(record); - } - if (bDbgBreak && g_cvars.sys_error_debugbreak) { AZ::Debug::Trace::Break(); @@ -1419,24 +1298,12 @@ void CSystem::Relaunch(bool bRelaunch) SaveConfiguration(); } -////////////////////////////////////////////////////////////////////////// -uint32 CSystem::GetUsedMemory() -{ - return CryMemoryGetAllocatedSize(); -} - ////////////////////////////////////////////////////////////////////////// ILocalizationManager* CSystem::GetLocalizationManager() { return m_pLocalizationManager; } -////////////////////////////////////////////////////////////////////////// -IResourceManager* CSystem::GetIResourceManager() -{ - return m_pResourceManager; -} - ////////////////////////////////////////////////////////////////////////// void CSystem::debug_GetCallStackRaw(void** callstack, uint32& callstackLength) { @@ -1476,12 +1343,6 @@ void CSystem::ExecuteCommandLine(bool deferred) m_executedCommandLine = true; - // auto detect system spec (overrides profile settings) - if (m_pCmdLine->FindArg(eCLAT_Pre, "autodetect")) - { - AutoDetectSpec(false); - } - // execute command line arguments e.g. +g_gametype ASSAULT +map "testy" ICmdLine* pCmdLine = GetICmdLine(); @@ -1510,50 +1371,6 @@ void CSystem::ExecuteCommandLine(bool deferred) //gEnv->pConsole->ExecuteString("sys_RestoreSpec test*"); // to get useful debugging information about current spec settings to the log file } -ITextModeConsole* CSystem::GetITextModeConsole() -{ - if (m_bDedicatedServer) - { - return m_pTextModeConsole; - } - - return 0; -} - -////////////////////////////////////////////////////////////////////////// -ESystemConfigSpec CSystem::GetConfigSpec(bool bClient) -{ - if (bClient) - { - if (m_sys_GraphicsQuality) - { - return (ESystemConfigSpec)m_sys_GraphicsQuality->GetIVal(); - } - return CONFIG_VERYHIGH_SPEC; // highest spec. - } - else - { - return m_nServerConfigSpec; - } -} - -////////////////////////////////////////////////////////////////////////// -void CSystem::SetConfigSpec(ESystemConfigSpec spec, ESystemConfigPlatform platform, bool bClient) -{ - if (bClient) - { - if (m_sys_GraphicsQuality) - { - SetConfigPlatform(platform); - m_sys_GraphicsQuality->Set(static_cast(spec)); - } - } - else - { - m_nServerConfigSpec = spec; - } -} - ////////////////////////////////////////////////////////////////////////// ESystemConfigSpec CSystem::GetMaxConfigSpec() const { @@ -1603,49 +1420,6 @@ void CProfilingSystem::VTunePause() #endif } -bool CSystem::SteamInit() -{ -#if USE_STEAM - if (m_bIsSteamInitialized) - { - return true; - } - - AZStd::string_view exePath; - AZ::ComponentApplicationBus::BroadcastResult(exePath, &AZ::ComponentApplicationRequests::GetExecutableFolder); - - //////////////////////////////////////////////////////////////////////////// - // ** DEVELOPMENT ONLY ** - creates the appropriate steam_appid.txt file needed to call SteamAPI_Init() -#if !defined(RELEASE) - AZStd::string appidPath = AZStd::string::format("%.*s/steam_appid.txt", aznumeric_cast(exePath.size()), exePath.data()); - azfopen(&pSteamAppID, appidPath.c_str(), "wt"); - fprintf(pSteamAppID, "%d", g_cvars.sys_steamAppId); - fclose(pSteamAppID); -#endif // !defined(RELEASE) - // ** END DEVELOPMENT ONLY ** - //////////////////////////////////////////////////////////////////////////// - - if (!SteamAPI_Init()) - { - CryLog("[STEAM] SteamApi_Init failed"); - return false; - } - - //////////////////////////////////////////////////////////////////////////// - // ** DEVELOPMENT ONLY ** - deletes the appropriate steam_appid.txt file as it's no longer needed -#if !defined(RELEASE) - remove(appidPath.c_str()); -#endif // !defined(RELEASE) - // ** END DEVELOPMENT ONLY ** - //////////////////////////////////////////////////////////////////////////// - - m_bIsSteamInitialized = true; - return true; -#else - return false; -#endif -} - ////////////////////////////////////////////////////////////////////// void CSystem::OnLanguageCVarChanged(ICVar* language) { diff --git a/Code/CryEngine/CrySystem/System.h b/Code/CryEngine/CrySystem/System.h index e27dfe4866..631d84d934 100644 --- a/Code/CryEngine/CrySystem/System.h +++ b/Code/CryEngine/CrySystem/System.h @@ -23,13 +23,10 @@ #include "CmdLine.h" #include "CryName.h" -#include "MTSafeAllocator.h" -#include "CPUDetect.h" #include #include "RenderBus.h" #include -#include #include @@ -39,8 +36,6 @@ namespace AzFramework } struct IConsoleCmdArgs; -class CServerThrottle; -struct IZLibCompressor; class CWatchdogThread; #if defined(AZ_RESTRICTED_PLATFORM) @@ -51,18 +46,6 @@ class CWatchdogThread; #define SYSTEM_H_SECTION_4 4 #endif -#if defined(ANDROID) -#define USE_ANDROIDCONSOLE -#elif defined(MAC) // || defined(LINUX) -#define USE_UNIXCONSOLE -#elif defined(IOS) -#define USE_IOSCONSOLE -#elif defined(WIN32) || defined(WIN64) -#define USE_WINDOWSCONSOLE -#else -#define USE_NULLCONSOLE -#endif - #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEM_H_SECTION_1 #include AZ_RESTRICTED_FILE(System_h) @@ -186,20 +169,12 @@ typedef void* WIN_HMODULE; typedef void* WIN_HMODULE; #endif -#if !defined(CRY_ASYNC_MEMCPY_DELEGATE_TO_CRYSYSTEM) -CRY_ASYNC_MEMCPY_API void cryAsyncMemcpy(void* dst, const void* src, size_t size, int nFlags, volatile int* sync); -#else -CRY_ASYNC_MEMCPY_API void cryAsyncMemcpyDelegate(void* dst, const void* src, size_t size, int nFlags, volatile int* sync); -#endif - - //forward declarations namespace Audio { struct IAudioSystem; struct IMusicSystem; } // namespace Audio -struct SDefaultValidator; struct IDataProbe; #define PHSYICS_OBJECT_ENTITY 0 @@ -233,7 +208,6 @@ struct SSystemCVars int sys_no_crash_dialog; int sys_no_error_report_window; int sys_dump_aux_threads; - int sys_WER; int sys_dump_type; int sys_ai; int sys_entitysystem; @@ -256,12 +230,6 @@ struct SSystemCVars int sys_FilesystemCaseSensitivity; int sys_deferAudioUpdateOptim; -#if USE_STEAM -#ifndef RELEASE - int sys_steamAppId; -#endif // RELEASE - int sys_useSteamCloudForPlatformSaving; -#endif // USE_STEAM AZ::IO::ArchiveVars archiveVars; @@ -276,33 +244,6 @@ extern SSystemCVars g_cvars; class CSystem; -struct SmallModuleInfo -{ - string name; - CryModuleMemoryInfo memInfo; -}; - -struct SCryEngineStatsModuleInfo -{ - string name; - CryModuleMemoryInfo memInfo; - uint32 moduleStaticSize; - uint32 usedInModule; - uint32 SizeOfCode; - uint32 SizeOfInitializedData; - uint32 SizeOfUninitializedData; -}; - -struct SCryEngineStatsGlobalMemInfo -{ - int totalUsedInModules; - int totalCodeAndStatic; - int countedMemoryModules; - uint64 totalAllocatedInModules; - int totalNumAllocsInModules; - std::vector modules; -}; - struct CProfilingSystem : public IProfilingSystem { @@ -338,17 +279,6 @@ class CSystem , public CrySystemRequestBus::Handler { public: - - inline void* operator new(std::size_t) - { - size_t allocated = 0; - return CryMalloc(sizeof(CSystem), allocated, 64); - } - inline void operator delete(void* p) - { - CryFree(p, 64); - } - CSystem(SharedEnvironmentInstance* pSharedEnvironment); ~CSystem(); @@ -382,18 +312,11 @@ public: virtual void DoWorkDuringOcclusionChecks(); virtual bool NeedDoWorkDuringOcclusionChecks() { return m_bNeedDoWorkDuringOcclusionChecks; } - //Called when the renderer finishes rendering the scene - void OnScene3DEnd() override; - //////////////////////////////////////////////////////////////////////// // CrySystemRequestBus interface implementation ISystem* GetCrySystem() override; //////////////////////////////////////////////////////////////////////// - uint32 GetUsedMemory(); - - virtual bool SteamInit(); - void Relaunch(bool bRelaunch); bool IsRelaunch() const { return m_bRelaunch; }; @@ -412,23 +335,14 @@ public: IConsole* GetIConsole() { return m_env.pConsole; }; IRemoteConsole* GetIRemoteConsole(); IMovieSystem* GetIMovieSystem() { return m_env.pMovieSystem; }; - IMemoryManager* GetIMemoryManager(){ return m_pMemoryManager; } ICryFont* GetICryFont(){ return m_env.pCryFont; } ILog* GetILog(){ return m_env.pLog; } ICmdLine* GetICmdLine(){ return m_pCmdLine; } - IStreamEngine* GetStreamEngine(); - IValidator* GetIValidator() { return m_pValidator; }; INameTable* GetINameTable() { return m_env.pNameTable; }; IViewSystem* GetIViewSystem(); ILevelSystem* GetILevelSystem(); ISystemEventDispatcher* GetISystemEventDispatcher() { return m_pSystemEventDispatcher; } - IResourceManager* GetIResourceManager(); - ITextModeConsole* GetITextModeConsole(); IProfilingSystem* GetIProfilingSystem() { return &m_ProfilingSystem; } - IZLibCompressor* GetIZLibCompressor() { return m_pIZLibCompressor; } - IZLibDecompressor* GetIZLibDecompressor() { return m_pIZLibDecompressor; } - ILZ4Decompressor* GetLZ4Decompressor() { return m_pILZ4Decompressor; } - IZStdDecompressor* GetZStdDecompressor() { return m_pIZStdDecompressor; } ////////////////////////////////////////////////////////////////////////// // retrieves the perlin noise singleton instance CPNoise3* GetNoiseGen(); @@ -450,45 +364,6 @@ public: void SetViewCamera(CCamera& Camera){ m_ViewCamera = Camera; } CCamera& GetViewCamera() { return m_ViewCamera; } - virtual int GetCPUFlags() - { - int Flags = 0; - if (!m_pCpu) - { - return Flags; - } - if (m_pCpu->hasMMX()) - { - Flags |= CPUF_MMX; - } - if (m_pCpu->hasSSE()) - { - Flags |= CPUF_SSE; - } - if (m_pCpu->hasSSE2()) - { - Flags |= CPUF_SSE2; - } - if (m_pCpu->has3DNow()) - { - Flags |= CPUF_3DNOW; - } - if (m_pCpu->hasF16C()) - { - Flags |= CPUF_F16C; - } - - return Flags; - } - virtual int GetLogicalCPUCount() - { - if (m_pCpu) - { - return m_pCpu->GetLogicalCPUCount(); - } - return 0; - } - void IgnoreUpdates(bool bIgnore) { m_bIgnoreUpdates = bIgnore; }; void SetIProcess(IProcess* process); @@ -499,8 +374,6 @@ public: void SleepIfNeeded(); - virtual void DisplayErrorMessage(const char* acMessage, float fTime, const float* pfColor = 0, bool bHardError = true); - virtual void FatalError(const char* format, ...) PRINTF_PARAMS(2, 3); virtual void ReportBug(const char* format, ...) PRINTF_PARAMS(2, 3); // Validator Warning. @@ -509,19 +382,12 @@ public: virtual int ShowMessage(const char* text, const char* caption, unsigned int uType); bool CheckLogVerbosity(int verbosity); - virtual void DebugStats(bool checkpoint, bool leaks); - void DumpWinHeaps(); - - virtual int DumpMMStats(bool log); - //! Return pointer to user defined callback. ISystemUserCallback* GetUserCallback() const { return m_pUserCallback; }; ////////////////////////////////////////////////////////////////////////// virtual void SaveConfiguration(); virtual void LoadConfiguration(const char* sFilename, ILoadConfigurationEntrySink* pSink = 0, bool warnIfMissing = true); - virtual ESystemConfigSpec GetConfigSpec(bool bClient = true); - virtual void SetConfigSpec(ESystemConfigSpec spec, ESystemConfigPlatform platform, bool bClient); virtual ESystemConfigSpec GetMaxConfigSpec() const; virtual ESystemConfigPlatform GetConfigPlatform() const; virtual void SetConfigPlatform(ESystemConfigPlatform platform); @@ -541,8 +407,6 @@ public: void SetVersionInfo(const char* const szVersion); #endif - virtual const IImageHandler* GetImageHandler() const override { return m_imageHandler.get(); } - void ShutdownModuleLibraries(); #if defined(WIN32) @@ -570,7 +434,6 @@ private: bool InitConsole(); bool InitFileSystem(); bool InitFileSystem_LoadEngineFolders(const SSystemInitParams& initParams); - bool InitStreamEngine(); bool InitAudioSystem(const SSystemInitParams& initParams); bool InitShine(const SSystemInitParams& initParams); @@ -597,7 +460,6 @@ private: #endif // #ifndef _RELEASE bool ReLaunchMediaCenter(); - void LogSystemInfo(); void UpdateAudioSystems(); void AddCVarGroupDirectory(const string& sPath); @@ -620,24 +482,7 @@ public: virtual bool GetForceNonDevMode() const; virtual bool WasInDevMode() const { return m_bWasInDevMode; }; virtual bool IsDevMode() const { return m_bInDevMode && !GetForceNonDevMode(); } - virtual bool IsMODValid(const char* szMODName) const - { - if (!szMODName || strstr(szMODName, ".") || strstr(szMODName, "\\")) - { - return (false); - } - return (true); - } - virtual void AutoDetectSpec(bool detectResolution); - virtual void AsyncMemcpy(void* dst, const void* src, size_t size, int nFlags, volatile int* sync) - { -#if !defined(CRY_ASYNC_MEMCPY_DELEGATE_TO_CRYSYSTEM) - cryAsyncMemcpy(dst, src, size, nFlags, sync); -#else - cryAsyncMemcpyDelegate(dst, src, size, nFlags, sync); -#endif - } virtual void SetConsoleDrawEnabled(bool enabled) { m_bDrawConsole = enabled; } virtual void SetUIDrawEnabled(bool enabled) { m_bDrawUI = enabled; } @@ -647,18 +492,11 @@ public: //! recreates the variable if necessary ICVar* attachVariable (const char* szVarName, int* pContainer, const char* szComment, int dwFlags = 0); - CCpuFeatures* GetCPUFeatures() { return m_pCpu; }; - const CTimeValue& GetLastTickTime(void) const { return m_lastTickTime; } const ICVar* GetDedicatedMaxRate(void) const { return m_svDedicatedMaxRate; } std::shared_ptr CreateLocalFileIO(); - // Gets the dimensions (in pixels) of the primary physical display. - // Returns true if this info is available, returns false otherwise. - bool GetPrimaryPhysicalDisplayDimensions(int& o_widthPixels, int& o_heightPixels); - bool IsTablet(); - private: // ------------------------------------------------------ // System environment. @@ -676,13 +514,10 @@ private: // ------------------------------------------------------ bool m_bPreviewMode; //!< If running in Preview mode. bool m_bDedicatedServer; //!< If running as Dedicated server. bool m_bIgnoreUpdates; //!< When set to true will ignore Update and Render calls, - IValidator* m_pValidator; //!< Pointer to validator interface. bool m_bForceNonDevMode; //!< true when running on a cheat protected server or a client that is connected to it (not used in singlplayer) bool m_bWasInDevMode; //!< Set to true if was in dev mode. bool m_bInDevMode; //!< Set to true if was in dev mode. bool m_bGameFolderWritable;//!< True when verified that current game folder have write access. - SDefaultValidator* m_pDefaultValidator; //!< - CCpuFeatures* m_pCpu; //!< CPU features int m_ttMemStatSS; //!< Time to memstat screenshot bool m_bDrawConsole; //!< Set to true if OK to draw the console. bool m_bDrawUI; //!< Set to true if OK to draw UI. @@ -690,14 +525,9 @@ private: // ------------------------------------------------------ std::map > m_moduleDLLHandles; - //! THe streaming engine - class CStreamEngine* m_pStreamEngine; - //! current active process IProcess* m_pProcess; - IMemoryManager* m_pMemoryManager; - CCamera m_PhysRendererCamera; ICVar* m_p_draw_helpers_str; int m_iJumpToPhysProfileEnt; @@ -719,18 +549,6 @@ private: // ------------------------------------------------------ //! System to manage views. IViewSystem* m_pViewSystem; - //! System to access zlib compressor - IZLibCompressor* m_pIZLibCompressor; - - //! System to access zlib decompressor - IZLibDecompressor* m_pIZLibDecompressor; - - //! System to access lz4 hc decompressor - ILZ4Decompressor* m_pILZ4Decompressor; - - //! System access to zstd decompressor - IZStdDecompressor* m_pIZStdDecompressor; - // XML Utils interface. class CXmlUtils* m_pXMLUtils; @@ -794,7 +612,6 @@ private: // ------------------------------------------------------ ICVar* m_sysWarnings; //!< might be 0, "sys_warnings" - Treat warning as errors. ICVar* m_cvSSInfo; //!< might be 0, "sys_SSInfo" 0/1 - get file sourcesafe info ICVar* m_svDedicatedMaxRate; - ICVar* m_sys_GraphicsQuality; ICVar* m_sys_firstlaunch; ICVar* m_sys_asset_processor; ICVar* m_sys_load_files_to_memory; @@ -835,8 +652,6 @@ private: // ------------------------------------------------------ ESystemConfigSpec m_nMaxConfigSpec; ESystemConfigPlatform m_ConfigPlatform; - std::unique_ptr m_pServerThrottle; - CProfilingSystem m_ProfilingSystem; // Pause mode. @@ -861,9 +676,6 @@ public: virtual const SFileVersion& GetProductVersion(); virtual const SFileVersion& GetBuildVersion(); - bool CompressDataBlock(const void* input, size_t inputSize, void* output, size_t& outputSize, int level); - bool DecompressDataBlock(const void* input, size_t inputSize, void* output, size_t& outputSize); - bool InitVTuneProfiler(); void OpenBasicPaks(); @@ -914,8 +726,6 @@ public: protected: // ------------------------------------------------------------- CCmdLine* m_pCmdLine; - class CResourceManager* m_pResourceManager; - ITextModeConsole* m_pTextModeConsole; string m_currentLanguageAudio; string m_systemConfigName; // computed from system_(hardwareplatform)_(assetsPlatform) - eg, system_android_es3.cfg or system_android_opengl.cfg or system_windows_pc.cfg @@ -937,16 +747,7 @@ protected: // ------------------------------------------------------------- ESystemEvent m_eRuntimeState; bool m_bIsAsserting; - friend struct SDefaultValidator; - friend struct SCryEngineFoldersLoader; - // friend void ScreenshotCmd( IConsoleCmdArgs *pParams ); - - bool m_bIsSteamInitialized; - - std::unique_ptr m_imageHandler; std::vector m_windowMessageHandlers; bool m_initedOSAllocator = false; bool m_initedSysAllocator = false; - - AZStd::unique_ptr m_thermalInfoHandler; }; diff --git a/Code/CryEngine/CrySystem/SystemInit.cpp b/Code/CryEngine/CrySystem/SystemInit.cpp index 7d3a13d1a2..afc5bd9144 100644 --- a/Code/CryEngine/CrySystem/SystemInit.cpp +++ b/Code/CryEngine/CrySystem/SystemInit.cpp @@ -12,7 +12,7 @@ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include "CrySystem_precompiled.h" -#include "SystemInit.h" +#include "System.h" #if defined(AZ_RESTRICTED_PLATFORM) || defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) #undef AZ_RESTRICTED_SECTION @@ -95,20 +95,8 @@ #include "XConsole.h" #include "Log.h" #include "XML/xml.h" -#include "StreamEngine/StreamEngine.h" -#include "PhysRenderer.h" #include "LocalizedStringManager.h" #include "SystemEventDispatcher.h" -#include "Validator.h" -#include "ServerThrottle.h" -#include "SystemCFG.h" -#include "AutoDetectSpec.h" -#include "ResourceManager.h" -#include "MTSafeAllocator.h" -#include "ZLibCompressor.h" -#include "ZLibDecompressor.h" -#include "ZStdDecompressor.h" -#include "LZ4Decompressor.h" #include "LevelSystem/LevelSystem.h" #include "LevelSystem/SpawnableLevelSystem.h" #include "ViewSystem/ViewSystem.h" @@ -117,29 +105,10 @@ #include #include -#if USE_STEAM -#include "Steamworks/public/steam/steam_api.h" -#include "Steamworks/public/steam/isteamremotestorage.h" -#endif - -#if defined(IOS) -#include "IOSConsole.h" -#endif - #if defined(ANDROID) #include - #include "AndroidConsole.h" -#if !defined(AZ_RELEASE_BUILD) - #include "ThermalInfoAndroid.h" -#endif // !defined(AZ_RELEASE_BUILD) #endif -#if defined(AZ_PLATFORM_ANDROID) || defined(AZ_PLATFORM_IOS) -#include "MobileDetectSpec.h" -#endif - -#include "WindowsConsole.h" - #if defined(EXTERNAL_CRASH_REPORTING) #include #endif @@ -153,10 +122,6 @@ # include #endif -#ifdef WIN32 -extern LONG WINAPI CryEngineExceptionFilterWER(struct _EXCEPTION_POINTERS* pExceptionPointers); -#endif - #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_14 #include AZ_RESTRICTED_FILE(SystemInit_cpp) @@ -199,12 +164,6 @@ void CryEngineSignalHandler(int signal) #endif // AZ_TRAIT_USE_CRY_SIGNAL_HANDLER -#if defined(USE_UNIXCONSOLE) -#if defined(LINUX) && !defined(ANDROID) -CUNIXConsole* pUnixConsole; -#endif -#endif // USE_UNIXCONSOLE - ////////////////////////////////////////////////////////////////////////// #define DEFAULT_LOG_FILENAME "@log@/Log.txt" @@ -245,8 +204,6 @@ CUNIXConsole* pUnixConsole; #define AZ_TRACE_SYSTEM_WINDOW AZ::Debug::Trace::GetDefaultSystemWindow() -extern CMTSafeHeap* g_pPakHeap; - #ifdef WIN32 extern HMODULE gDLLHandle; #endif @@ -274,7 +231,6 @@ struct SCVarsClientConfigSink ////////////////////////////////////////////////////////////////////////// static inline void InlineInitializationProcessing([[maybe_unused]] const char* sDescription) { - assert(CryMemory::IsHeapValid()); if (gEnv->pLog) { gEnv->pLog->UpdateLoadingScreen(0); @@ -339,26 +295,6 @@ static void CmdCrashTest(IConsoleCmdArgs* pArgs) } AZ_POP_DISABLE_WARNING -#if USE_STEAM -////////////////////////////////////////////////////////////////////////// -static void CmdWipeSteamCloud(IConsoleCmdArgs* pArgs) -{ - if (!gEnv->pSystem->SteamInit()) - { - return; - } - - int32 fileCount = SteamRemoteStorage()->GetFileCount(); - for (int i = 0; i < fileCount; i++) - { - int32 size = 0; - const char* name = SteamRemoteStorage()->GetFileNameAndSize(i, &size); - bool success = SteamRemoteStorage()->FileDelete(name); - CryLog("Deleting file: %s - success: %d", name, success); - } -} -#endif - ////////////////////////////////////////////////////////////////////////// struct SysSpecOverrideSink : public ILoadConfigurationEntrySink @@ -472,275 +408,6 @@ static ESystemConfigPlatform GetDevicePlatform() #endif } -static void GetSpecConfigFileToLoad(ICVar* pVar, AZStd::string& cfgFile, ESystemConfigPlatform platform) -{ - switch (platform) - { - case CONFIG_PC: - cfgFile = "pc"; - break; - case CONFIG_ANDROID: - cfgFile = "android"; - break; - case CONFIG_IOS: - cfgFile = "ios"; - break; -#if defined(AZ_PLATFORM_JASPER) || defined(TOOLS_SUPPORT_JASPER) -#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_3 -#include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, jasper) -#endif -#if defined(AZ_PLATFORM_PROVO) || defined(TOOLS_SUPPORT_PROVO) -#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_3 -#include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, provo) -#endif -#if defined(AZ_PLATFORM_SALEM) || defined(TOOLS_SUPPORT_SALEM) -#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_3 -#include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, salem) -#endif - case CONFIG_OSX_METAL: - cfgFile = "osx_metal"; - break; - case CONFIG_OSX_GL: - // Spec level is hardcoded for these platforms - cfgFile = ""; - return; - default: - AZ_Assert(false, "Platform not supported"); - return; - } - - switch (pVar->GetIVal()) - { - case CONFIG_AUTO_SPEC: - // Spec level is set for autodetection - cfgFile = ""; - break; - case CONFIG_LOW_SPEC: - cfgFile += "_low.cfg"; - break; - case CONFIG_MEDIUM_SPEC: - cfgFile += "_medium.cfg"; - break; - case CONFIG_HIGH_SPEC: - cfgFile += "_high.cfg"; - break; - case CONFIG_VERYHIGH_SPEC: -#if defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_4 -#include AZ_RESTRICTED_FILE(SystemInit_cpp) -#endif - cfgFile += "_veryhigh.cfg"; - break; - default: - AZ_Assert(false, "Invalid value for r_GraphicsQuality"); - break; - } -} - -static void LoadDetectedSpec(ICVar* pVar) -{ - CDebugAllowFileAccess ignoreInvalidFileAccess; - SysSpecOverrideSink sysSpecOverrideSink; - ILoadConfigurationEntrySink* pSysSpecOverrideSinkConsole = nullptr; - -#if !defined(CONSOLE) - SysSpecOverrideSinkConsole sysSpecOverrideSinkConsole; - pSysSpecOverrideSinkConsole = &sysSpecOverrideSinkConsole; -#endif - - // g_sysSpecChanged = true; - static int no_recursive = false; - if (no_recursive) - { - return; - } - no_recursive = true; - - int spec = pVar->GetIVal(); - ESystemConfigPlatform platform = GetDevicePlatform(); - if (gEnv->IsEditor()) - { - ESystemConfigPlatform configPlatform = GetISystem()->GetConfigPlatform(); - // Check if the config platform is set first. - if (configPlatform != CONFIG_INVALID_PLATFORM) - { - platform = configPlatform; - } - } - - AZStd::string configFile; - GetSpecConfigFileToLoad(pVar, configFile, platform); - if (configFile.length()) - { - GetISystem()->LoadConfiguration(configFile.c_str(), platform == CONFIG_PC ? &sysSpecOverrideSink : pSysSpecOverrideSinkConsole); - } - else - { - // Automatically sets graphics quality - spec level autodetected for ios/android, hardcoded for all other platforms - - switch (platform) - { - case CONFIG_PC: - { - // TODO: add support for autodetection - pVar->Set(CONFIG_VERYHIGH_SPEC); - GetISystem()->LoadConfiguration("pc_veryhigh.cfg", &sysSpecOverrideSink); - break; - } - case CONFIG_ANDROID: - { -#if defined(AZ_PLATFORM_ANDROID) - AZStd::string file; - if (MobileSysInspect::GetAutoDetectedSpecName(file)) - { - if (file == "android_low.cfg") - { - pVar->Set(CONFIG_LOW_SPEC); - } - if (file == "android_medium.cfg") - { - pVar->Set(CONFIG_MEDIUM_SPEC); - } - if (file == "android_high.cfg") - { - pVar->Set(CONFIG_HIGH_SPEC); - } - if (file == "android_veryhigh.cfg") - { - pVar->Set(CONFIG_VERYHIGH_SPEC); - } - GetISystem()->LoadConfiguration(file.c_str(), pSysSpecOverrideSinkConsole); - } - else - { - float totalRAM = MobileSysInspect::GetDeviceRamInGB(); - if (totalRAM < MobileSysInspect::LOW_SPEC_RAM) - { - pVar->Set(CONFIG_LOW_SPEC); - GetISystem()->LoadConfiguration("android_low.cfg", pSysSpecOverrideSinkConsole); - } - else if (totalRAM < MobileSysInspect::MEDIUM_SPEC_RAM) - { - pVar->Set(CONFIG_MEDIUM_SPEC); - GetISystem()->LoadConfiguration("android_medium.cfg", pSysSpecOverrideSinkConsole); - } - else if (totalRAM < MobileSysInspect::HIGH_SPEC_RAM) - { - pVar->Set(CONFIG_HIGH_SPEC); - GetISystem()->LoadConfiguration("android_high.cfg", pSysSpecOverrideSinkConsole); - } - else - { - pVar->Set(CONFIG_VERYHIGH_SPEC); - GetISystem()->LoadConfiguration("android_veryhigh.cfg", pSysSpecOverrideSinkConsole); - } - } -#endif - break; - } - case CONFIG_IOS: - { -#if defined(AZ_PLATFORM_IOS) - AZStd::string file; - if (MobileSysInspect::GetAutoDetectedSpecName(file)) - { - if (file == "ios_low.cfg") - { - pVar->Set(CONFIG_LOW_SPEC); - } - if (file == "ios_medium.cfg") - { - pVar->Set(CONFIG_MEDIUM_SPEC); - } - if (file == "ios_high.cfg") - { - pVar->Set(CONFIG_HIGH_SPEC); - } - if (file == "ios_veryhigh.cfg") - { - pVar->Set(CONFIG_VERYHIGH_SPEC); - } - GetISystem()->LoadConfiguration(file.c_str(), pSysSpecOverrideSinkConsole); - } - else - { - pVar->Set(CONFIG_MEDIUM_SPEC); - GetISystem()->LoadConfiguration("ios_medium.cfg", pSysSpecOverrideSinkConsole); - } -#endif - break; - } -#if defined(AZ_PLATFORM_JASPER) || defined(TOOLS_SUPPORT_JASPER) -#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_5 -#include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, jasper) -#endif -#if defined(AZ_PLATFORM_PROVO) || defined(TOOLS_SUPPORT_PROVO) -#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_5 -#include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, provo) -#endif -#if defined(AZ_PLATFORM_SALEM) || defined(TOOLS_SUPPORT_SALEM) -#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_5 -#include AZ_RESTRICTED_FILE_EXPLICIT(SystemInit_cpp, salem) -#endif - - case CONFIG_OSX_GL: - { - pVar->Set(CONFIG_HIGH_SPEC); - GetISystem()->LoadConfiguration("osx_gl.cfg", pSysSpecOverrideSinkConsole); - break; - } - case CONFIG_OSX_METAL: - { - pVar->Set(CONFIG_HIGH_SPEC); - GetISystem()->LoadConfiguration("osx_metal_high.cfg", pSysSpecOverrideSinkConsole); - break; - } - default: - AZ_Assert(false, "Platform not supported"); - break; - } - } - - // make sure editor specific settings are not changed - if (gEnv->IsEditor()) - { - GetISystem()->LoadConfiguration("editor.cfg"); - } - - // override cvars just loaded based on current API version/GPU - - GetISystem()->SetConfigSpec(static_cast(spec), platform, false); - - no_recursive = false; -} - -////////////////////////////////////////////////////////////////////////// -struct SCryEngineLanguageConfigLoader - : public ILoadConfigurationEntrySink -{ - CSystem* m_pSystem; - string m_language; - string m_pakFile; - - SCryEngineLanguageConfigLoader(CSystem* pSystem) { m_pSystem = pSystem; } - void Load(const char* sCfgFilename) - { - CSystemConfiguration cfg(sCfgFilename, m_pSystem, this); // Parse folders config file. - } - virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, [[maybe_unused]] const char* szGroup) - { - if (azstricmp(szKey, "Language") == 0) - { - m_language = szValue; - } - else if (azstricmp(szKey, "PAK") == 0) - { - m_pakFile = szValue; - } - } - virtual void OnLoadConfigurationEntry_End() {} -}; - ////////////////////////////////////////////////////////////////////////// #if !defined(AZ_MONOLITHIC_BUILD) @@ -1101,12 +768,7 @@ bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&) auto projectName = AZ::Utils::GetProjectName(); AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Name: %s\n", projectName.empty() ? "None specified" : projectName.c_str()); - // simply open all paks if fast load pak can't be found - if (!m_pResourceManager->LoadFastLoadPaks(true)) - { - OpenBasicPaks(); - } - + OpenBasicPaks(); // Load game-specific folder. LoadConfiguration("game.cfg"); @@ -1120,21 +782,6 @@ bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&) return (true); } -////////////////////////////////////////////////////////////////////////// -bool CSystem::InitStreamEngine() -{ - LOADING_TIME_PROFILE_SECTION(GetISystem()); - - if (m_pUserCallback) - { - m_pUserCallback->OnInitProgress("Initializing Stream Engine..."); - } - - m_pStreamEngine = new CStreamEngine(); - - return true; -} - ////////////////////////////////////////////////////////////////////////// bool CSystem::InitAudioSystem(const SSystemInitParams& initParams) { @@ -1299,8 +946,6 @@ void CSystem::OpenBasicPaks() ////////////////////////////////////////////////////////////////////////// const char* const assetsDir = "@assets@"; - const char* shaderCachePakDir = "@assets@/shadercache.pak"; - const char* shaderCacheStartupPakDir = "@assets@/shadercachestartup.pak"; // After game paks to have same search order as with files on disk m_env.pCryPak->OpenPack(assetsDir, "Engine.pak"); @@ -1310,11 +955,6 @@ void CSystem::OpenBasicPaks() #include AZ_RESTRICTED_FILE(SystemInit_cpp) #endif - m_env.pCryPak->OpenPack(assetsDir, shaderCachePakDir); - m_env.pCryPak->OpenPack(assetsDir, shaderCacheStartupPakDir); - m_env.pCryPak->OpenPack(assetsDir, "Shaders.pak"); - m_env.pCryPak->OpenPack(assetsDir, "ShadersBin.pak"); - #ifdef AZ_PLATFORM_ANDROID // Load Android Obb files if available const char* obbStorage = AZ::Android::Utils::GetObbStoragePath(); @@ -1326,22 +966,6 @@ void CSystem::OpenBasicPaks() InlineInitializationProcessing("CSystem::OpenBasicPaks OpenPacks( Engine... )"); - ////////////////////////////////////////////////////////////////////////// - // Open paks in MOD subfolders. - ////////////////////////////////////////////////////////////////////////// -#if !defined(_RELEASE) - if (const ICmdLineArg* pModArg = GetICmdLine()->FindArg(eCLAT_Pre, "MOD")) - { - if (IsMODValid(pModArg->GetValue())) - { - AZStd::string modFolder = "Mods\\"; - modFolder += pModArg->GetValue(); - modFolder += "\\*.pak"; - GetIPak()->OpenPacks(assetsDir, modFolder, AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::INestedArchive::FLAGS_OVERRIDE_PAK); - } - } -#endif // !defined(_RELEASE) - // Load paks required for game init to mem gEnv->pCryPak->LoadPakToMemory("Engine.pak", AZ::IO::IArchive::eInMemoryPakLocale_GPU); } @@ -1441,96 +1065,6 @@ string GetUniqueLogFileName(string logFileName) return logFileName; } - -#if defined(WIN32) || defined(WIN64) -static wstring GetErrorStringUnsupportedCPU() -{ - static const wchar_t s_EN[] = L"Unsupported CPU detected. CPU needs to support SSE, SSE2, SSE3 and SSE4.1."; - static const wchar_t s_FR[] = { 0 }; - static const wchar_t s_RU[] = { 0 }; - static const wchar_t s_ES[] = { 0 }; - static const wchar_t s_DE[] = { 0 }; - static const wchar_t s_IT[] = { 0 }; - - const size_t fullLangID = (size_t) GetKeyboardLayout(0); - const size_t primLangID = fullLangID & 0x3FF; - const wchar_t* pFmt = s_EN; - - /*switch (primLangID) - { - case 0x07: // German - pFmt = s_DE; - break; - case 0x0a: // Spanish - pFmt = s_ES; - break; - case 0x0c: // French - pFmt = s_FR; - break; - case 0x10: // Italian - pFmt = s_IT; - break; - case 0x19: // Russian - pFmt = s_RU; - break; - case 0x09: // English - default: - break; - }*/ - wchar_t msg[1024]; - msg[0] = L'\0'; - msg[sizeof(msg) / sizeof(msg[0]) - 1] = L'\0'; - azsnwprintf(msg, sizeof(msg) / sizeof(msg[0]) - 1, pFmt); - return msg; -} -#endif - -static bool CheckCPURequirements([[maybe_unused]] CCpuFeatures* pCpu, [[maybe_unused]] CSystem* pSystem) -{ -#if defined(WIN32) || defined(WIN64) - if (!gEnv->IsDedicated()) - { - if (!(pCpu->hasSSE() && pCpu->hasSSE2() && pCpu->hasSSE3() && pCpu->hasSSE41())) - { - AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Unsupported CPU! Need SSE, SSE2, SSE3 and SSE4.1 instructions to be available."); - -#if !defined(_RELEASE) - const bool allowPrompts = pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "noprompt") == 0; -#else - const bool allowPrompts = true; -#endif // !defined(_RELEASE) - if (allowPrompts) - { - AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Asking user if they wish to continue..."); - const int mbRes = MessageBoxW(0, GetErrorStringUnsupportedCPU().c_str(), L"Open 3D Engine", MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2 | MB_DEFAULT_DESKTOP_ONLY); - if (mbRes == IDCANCEL) - { - AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "User chose to cancel startup."); - return false; - } - } - else - { -#if !defined(_RELEASE) - const bool obeyCPUCheck = pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "anycpu") == 0; -#else - const bool obeyCPUCheck = true; -#endif // !defined(_RELEASE) - if (obeyCPUCheck) - { - AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "No prompts allowed and unsupported CPU check active. Treating unsupported CPU as error and exiting."); - return false; - } - } - - AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "User chose to continue despite unsupported CPU!"); - } - } -#endif - return true; -} - - class AzConsoleToCryConsoleBinder final { public: @@ -1687,8 +1221,6 @@ bool CSystem::Init(const SSystemInitParams& startupParams) m_systemConfigName += ".cfg"; } - AZ_Assert(CryMemory::IsHeapValid(), "Memory heap must be valid before continuing SystemInit."); - #if defined(WIN32) || defined(WIN64) // check OS version - we only want to run on XP or higher - talk to Martin Mittring if you want to change this { @@ -1709,8 +1241,6 @@ AZ_POP_DISABLE_WARNING } #endif - m_pResourceManager->Init(); - // Get file version information. QueryVersionInfo(); DetectGameFolderAccessRights(); @@ -1745,16 +1275,6 @@ AZ_POP_DISABLE_WARNING } } - if (!startupParams.pValidator) - { - m_pDefaultValidator = new SDefaultValidator(this); - m_pValidator = m_pDefaultValidator; - } - else - { - m_pValidator = startupParams.pValidator; - } - #if !defined(_RELEASE) if (!m_bDedicatedServer) { @@ -1770,79 +1290,6 @@ AZ_POP_DISABLE_WARNING gEnv->SetIsDedicated(m_bDedicatedServer); #endif -#if !defined(CONSOLE) -#if !defined(_RELEASE) - bool isDaemonMode = (m_pCmdLine->FindArg(eCLAT_Pre, "daemon") != 0); -#endif // !defined(_RELEASE) - -#if defined(USE_DEDICATED_SERVER_CONSOLE) - -#if !defined(_RELEASE) - bool isSimpleConsole = (m_pCmdLine->FindArg(eCLAT_Pre, "simple_console") != 0); - - if (!(isDaemonMode || isSimpleConsole)) -#endif // !defined(_RELEASE) - { -#if defined(USE_UNIXCONSOLE) - CUNIXConsole* pConsole = new CUNIXConsole(); -#if defined(LINUX) - pUnixConsole = pConsole; -#endif -#elif defined(USE_IOSCONSOLE) - CIOSConsole* pConsole = new CIOSConsole(); -#elif defined(USE_WINDOWSCONSOLE) - CWindowsConsole* pConsole = new CWindowsConsole(); -#elif defined(USE_ANDROIDCONSOLE) - CAndroidConsole* pConsole = new CAndroidConsole(); -#else - CNULLConsole* pConsole = new CNULLConsole(false); -#endif - m_pTextModeConsole = static_cast(pConsole); - - if (m_pUserCallback == nullptr && m_bDedicatedServer) - { - char headerString[128]; - m_pUserCallback = pConsole; - pConsole->SetRequireDedicatedServer(true); - - azstrcpy( - headerString, - AZ_ARRAY_SIZE(headerString), - "Open 3D Engine - " -#if defined(LINUX) - "Linux " -#elif defined(MAC) - "MAC " -#elif defined(IOS) - "iOS " -#endif - "Dedicated Server" - " - Version "); - - char* str = headerString + strlen(headerString); - GetProductVersion().ToString(str, sizeof(headerString) - (str - headerString)); - pConsole->SetHeader(headerString); - } - } -#if !defined(_RELEASE) - else -#endif -#endif - -#if !(defined(USE_DEDICATED_SERVER_CONSOLE) && defined(_RELEASE)) - { - CNULLConsole* pConsole = new CNULLConsole(isDaemonMode); - m_pTextModeConsole = pConsole; - - if (m_pUserCallback == nullptr && m_bDedicatedServer) - { - m_pUserCallback = pConsole; - } - } -#endif - -#endif // !defined(CONSOLE) - { EBUS_EVENT(CrySystemEventBus, OnCrySystemPreInitialize, *this, startupParams); @@ -1962,9 +1409,6 @@ AZ_POP_DISABLE_WARNING // Need to load the engine.pak that includes the config files needed during initialization m_env.pCryPak->OpenPack("@assets@", "Engine.pak"); -#if defined(AZ_PLATFORM_ANDROID) || defined(AZ_PLATFORM_IOS) - MobileSysInspect::LoadDeviceSpecMapping(); -#endif InitFileSystem_LoadEngineFolders(startupParams); @@ -1973,21 +1417,6 @@ AZ_POP_DISABLE_WARNING GetIRemoteConsole()->Update(); #endif - // CPU features detection. - m_pCpu = new CCpuFeatures; - m_pCpu->Detect(); - - // Check hard minimum CPU requirements - if (!CheckCPURequirements(m_pCpu, this)) - { - return false; - } - - if (!startupParams.bSkipConsole) - { - LogSystemInfo(); - } - InlineInitializationProcessing("CSystem::Init Load Engine Folders"); ////////////////////////////////////////////////////////////////////////// @@ -2052,41 +1481,10 @@ AZ_POP_DISABLE_WARNING gEnv->bNoAssertDialog = true; } - ////////////////////////////////////////////////////////////////////////// - // Stream Engine - ////////////////////////////////////////////////////////////////////////// - AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Stream Engine Initialization"); - InitStreamEngine(); - InlineInitializationProcessing("CSystem::Init StreamEngine"); - - - { - if (m_pCmdLine->FindArg(eCLAT_Pre, "NullRenderer")) - { - m_env.pConsole->LoadConfigVar("r_Driver", "NULL"); - } - else if (m_pCmdLine->FindArg(eCLAT_Pre, "DX11")) - { - m_env.pConsole->LoadConfigVar("r_Driver", "DX11"); - } - else if (m_pCmdLine->FindArg(eCLAT_Pre, "GL")) - { - m_env.pConsole->LoadConfigVar("r_Driver", "GL"); - } - } - LogBuildInfo(); InlineInitializationProcessing("CSystem::Init LoadConfigurations"); -#ifdef WIN32 - if ((g_cvars.sys_WER)) - { - SetUnhandledExceptionFilter(CryEngineExceptionFilterWER); - } -#endif - - ////////////////////////////////////////////////////////////////////////// // Localization ////////////////////////////////////////////////////////////////////////// @@ -2095,10 +1493,6 @@ AZ_POP_DISABLE_WARNING } InlineInitializationProcessing("CSystem::Init InitLocalizations"); -#if !defined(AZ_RELEASE_BUILD) && defined(AZ_PLATFORM_ANDROID) - m_thermalInfoHandler = AZStd::make_unique(); -#endif - ////////////////////////////////////////////////////////////////////////// // Open basic pak files after intro movie playback started ////////////////////////////////////////////////////////////////////////// @@ -2210,30 +1604,6 @@ AZ_POP_DISABLE_WARNING InlineInitializationProcessing("CSystem::Init View System"); - ////////////////////////////////////////////////////////////////////////// - // Zlib compressor - m_pIZLibCompressor = new CZLibCompressor(); - - InlineInitializationProcessing("CSystem::Init ZLibCompressor"); - - ////////////////////////////////////////////////////////////////////////// - // Zlib decompressor - m_pIZLibDecompressor = new CZLibDecompressor(); - - InlineInitializationProcessing("CSystem::Init ZLibDecompressor"); - - ////////////////////////////////////////////////////////////////////////// - // LZ4 decompressor - m_pILZ4Decompressor = new CLZ4Decompressor(); - - InlineInitializationProcessing("CSystem::Init LZ4Decompressor"); - - ////////////////////////////////////////////////////////////////////////// - // ZStd decompressor - m_pIZStdDecompressor = new CZStdDecompressor(); - - InlineInitializationProcessing("CSystem::Init ZStdDecompressor"); - if (m_env.pLyShine) { m_env.pLyShine->PostInit(); @@ -2273,9 +1643,6 @@ AZ_POP_DISABLE_WARNING LoadConfiguration("client.cfg", &CVarsClientConfigSink); } - // All CVars should be registered by this point, we must now flush the cvar groups - LoadDetectedSpec(m_sys_GraphicsQuality); - //Connect to the render bus AZ::RenderNotificationsBus::Handler::BusConnect(); @@ -2349,153 +1716,6 @@ void CmdSetAwsLogLevel(IConsoleCmdArgs* pArgs) } } -static void SysRestoreSpecCmd(IConsoleCmdArgs* pParams) -{ - assert(pParams); - - if (pParams->GetArgCount() == 2) - { - const char* szArg = pParams->GetArg(1); - - ICVar* pCVar = gEnv->pConsole->GetCVar("sys_spec_Full"); - - if (!pCVar) - { - gEnv->pLog->LogWithType(ILog::eInputResponse, "sys_RestoreSpec: no action"); // e.g. running Editor in shder compile mode - return; - } - - ICVar::EConsoleLogMode mode = ICVar::eCLM_Off; - - if (azstricmp(szArg, "test") == 0) - { - mode = ICVar::eCLM_ConsoleAndFile; - } - else if (azstricmp(szArg, "test*") == 0) - { - mode = ICVar::eCLM_FileOnly; - } - else if (azstricmp(szArg, "info") == 0) - { - mode = ICVar::eCLM_FullInfo; - } - - if (mode != ICVar::eCLM_Off) - { - bool bFileOrConsole = (mode == ICVar::eCLM_FileOnly || mode == ICVar::eCLM_FullInfo); - - if (bFileOrConsole) - { - gEnv->pLog->LogToFile(" "); - } - else - { - CryLog(" "); - } - - int iSysSpec = pCVar->GetRealIVal(); - - if (iSysSpec == -1) - { - iSysSpec = ((CSystem*)gEnv->pSystem)->GetMaxConfigSpec(); - - if (bFileOrConsole) - { - gEnv->pLog->LogToFile(" sys_spec = Custom (assuming %d)", iSysSpec); - } - else - { - gEnv->pLog->LogWithType(ILog::eInputResponse, " $3sys_spec = $6Custom (assuming %d)", iSysSpec); - } - } - else - { - if (bFileOrConsole) - { - gEnv->pLog->LogToFile(" sys_spec = %d", iSysSpec); - } - else - { - gEnv->pLog->LogWithType(ILog::eInputResponse, " $3sys_spec = $6%d", iSysSpec); - } - } - - pCVar->DebugLog(iSysSpec, mode); - - if (bFileOrConsole) - { - gEnv->pLog->LogToFile(" "); - } - else - { - gEnv->pLog->LogWithType(ILog::eInputResponse, " "); - } - - return; - } - else if (strcmp(szArg, "apply") == 0) - { - const char* szPrefix = "sys_spec_"; - - ESystemConfigSpec originalSpec = CONFIG_AUTO_SPEC; - ESystemConfigPlatform originalPlatform = GetDevicePlatform(); - - if (gEnv->IsEditor()) - { - originalSpec = gEnv->pSystem->GetConfigSpec(true); - } - - std::vector cmds; - - cmds.resize(gEnv->pConsole->GetSortedVars(0, 0, szPrefix)); - gEnv->pConsole->GetSortedVars(&cmds[0], cmds.size(), szPrefix); - - gEnv->pLog->LogWithType(IMiniLog::eInputResponse, " "); - - std::vector::const_iterator it, end = cmds.end(); - - for (it = cmds.begin(); it != end; ++it) - { - const char* szName = *it; - - if (azstricmp(szName, "sys_spec_Full") == 0) - { - continue; - } - - pCVar = gEnv->pConsole->GetCVar(szName); - assert(pCVar); - - if (!pCVar) - { - continue; - } - - bool bNeeded = pCVar->GetIVal() != pCVar->GetRealIVal(); - - gEnv->pLog->LogWithType(IMiniLog::eInputResponse, " $3%s = $6%d ... %s", - szName, pCVar->GetIVal(), - bNeeded ? "$4restored" : "valid"); - - if (bNeeded) - { - pCVar->Set(pCVar->GetIVal()); - } - } - - gEnv->pLog->LogWithType(IMiniLog::eInputResponse, " "); - - if (gEnv->IsEditor()) - { - gEnv->pSystem->SetConfigSpec(originalSpec, originalPlatform, true); - } - return; - } - } - - gEnv->pLog->LogWithType(ILog::eInputResponse, "ERROR: sys_RestoreSpec invalid arguments"); -} - void CmdDrillToFile(IConsoleCmdArgs* pArgs) { if (azstricmp(pArgs->GetArg(0), "DrillerStop") == 0) @@ -2632,14 +1852,6 @@ void CSystem::CreateSystemVars() "1 - enable optimisation\n" "Default is 1"); -#if USE_STEAM -#ifndef RELEASE - REGISTER_CVAR2("sys_steamAppId", &g_cvars.sys_steamAppId, 0, VF_NULL, "steam appId used for development testing"); - REGISTER_COMMAND("sys_wipeSteamCloud", CmdWipeSteamCloud, VF_CHEAT, "Delete all files from steam cloud for this user"); -#endif // RELEASE - REGISTER_CVAR2("sys_useSteamCloudForPlatformSaving", &g_cvars.sys_useSteamCloudForPlatformSaving, 0, VF_NULL, "Use steam cloud for save games and profile on PC (instead of the user folder)"); -#endif - m_sysNoUpdate = REGISTER_INT("sys_noupdate", 0, VF_CHEAT, "Toggles updating of system with sys_script_debugger.\n" "Usage: sys_noupdate [0/1]\n" @@ -2703,9 +1915,6 @@ void CSystem::CreateSystemVars() #else const uint32 nJobSystemDefaultCoreNumber = 4; #endif - m_sys_GraphicsQuality = REGISTER_INT_CB("r_GraphicsQuality", 0, VF_ALWAYSONCHANGE, - "Specifies the system cfg spec. 1=low, 2=med, 3=high, 4=very high)", - LoadDetectedSpec); m_sys_firstlaunch = REGISTER_INT("sys_firstlaunch", 0, 0, "Indicates that the game was run for the first time."); @@ -2812,14 +2021,6 @@ void CSystem::CreateSystemVars() REGISTER_CVAR2("sys_update_profile_time", &g_cvars.sys_update_profile_time, 1.0f, 0, "Time to keep updates timings history for."); REGISTER_CVAR2("sys_no_crash_dialog", &g_cvars.sys_no_crash_dialog, m_bNoCrashDialog, VF_NULL, "Whether to disable the crash dialog window"); REGISTER_CVAR2("sys_no_error_report_window", &g_cvars.sys_no_error_report_window, m_bNoErrorReportWindow, VF_NULL, "Whether to disable the error report list"); -#if defined(_RELEASE) - if (!gEnv->IsDedicated()) - { - REGISTER_CVAR2("sys_WER", &g_cvars.sys_WER, 1, 0, "Enables Windows Error Reporting"); - } -#else - REGISTER_CVAR2("sys_WER", &g_cvars.sys_WER, 0, 0, "Enables Windows Error Reporting"); -#endif #ifdef USE_HTTP_WEBSOCKETS REGISTER_CVAR2("sys_simple_http_base_port", &g_cvars.sys_simple_http_base_port, 1880, VF_REQUIRE_APP_RESTART, @@ -2901,11 +2102,6 @@ void CSystem::CreateSystemVars() REGISTER_STRING_CB("g_language", "", VF_NULL, "Defines which language pak is loaded", CSystem::OnLanguageCVarChanged); REGISTER_STRING_CB("g_languageAudio", "", VF_NULL, "Will automatically match g_language setting unless specified otherwise", CSystem::OnLanguageAudioCVarChanged); - REGISTER_COMMAND("sys_RestoreSpec", &SysRestoreSpecCmd, 0, - "Restore or test the cvar settings of game specific spec settings,\n" - "'test*' and 'info' log to the log file only\n" - "Usage: sys_RestoreSpec [test|test*|apply|info]"); - #if defined(WIN32) REGISTER_CVAR2("sys_display_threads", &g_cvars.sys_display_threads, 0, 0, "Displays Thread info"); #elif defined(AZ_RESTRICTED_PLATFORM) diff --git a/Code/CryEngine/CrySystem/SystemInit.h b/Code/CryEngine/CrySystem/SystemInit.h deleted file mode 100644 index 55eecb97db..0000000000 --- a/Code/CryEngine/CrySystem/SystemInit.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_SYSTEMINIT_H -#define CRYINCLUDE_CRYSYSTEM_SYSTEMINIT_H -#pragma once - - -#include "System.h" - -#if defined(AZ_PLATFORM_ANDROID) - #include "AndroidConsole.h" - -// let the java code know the native renderer is taking over now -extern "C" DLL_EXPORT void OnEngineRendererTakeover(bool engineSplashActive); -#endif - -#include "UnixConsole.h" - -#if defined(USE_UNIXCONSOLE) -#if defined(LINUX) && !defined(ANDROID) -extern __attribute__((visibility("default"))) CUNIXConsole* pUnixConsole; -#endif -#endif // USE_UNIXCONSOLE - -#endif // CRYINCLUDE_CRYSYSTEM_SYSTEMINIT_H diff --git a/Code/CryEngine/CrySystem/SystemRender.cpp b/Code/CryEngine/CrySystem/SystemRender.cpp deleted file mode 100644 index b608ef5335..0000000000 --- a/Code/CryEngine/CrySystem/SystemRender.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : CryENGINE system core - - -#include "CrySystem_precompiled.h" -#include "System.h" - -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include "windows.h" -#endif - -#if defined(AZ_PLATFORM_IOS) -#import -#endif - -#include -#include -#include -#include "Log.h" -#include "XConsole.h" -#include -#include "PhysRenderer.h" -#include - -#include "ITextModeConsole.h" -#include -#include - -#include - -#if defined(AZ_RESTRICTED_PLATFORM) -#undef AZ_RESTRICTED_SECTION -#define SYSTEMRENDERER_CPP_SECTION_1 1 -#define SYSTEMRENDERER_CPP_SECTION_2 2 -#endif - -extern CMTSafeHeap* g_pPakHeap; -#if defined(AZ_PLATFORM_ANDROID) -#include -#endif - -extern int CryMemoryGetAllocatedSize(); - -///////////////////////////////////////////////////////////////////////////////// -bool CSystem::GetPrimaryPhysicalDisplayDimensions([[maybe_unused]] int& o_widthPixels, [[maybe_unused]] int& o_heightPixels) -{ -#if defined(AZ_PLATFORM_WINDOWS) - o_widthPixels = GetSystemMetrics(SM_CXSCREEN); - o_heightPixels = GetSystemMetrics(SM_CYSCREEN); - return true; -#elif defined(AZ_PLATFORM_ANDROID) - return AZ::Android::Utils::GetWindowSize(o_widthPixels, o_heightPixels); -#else - return false; -#endif -} - - -bool CSystem::IsTablet() -{ -//TODO: Add support for Android tablets -#if defined(AZ_PLATFORM_IOS) - return [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad; -#else - return false; -#endif -} - -void CSystem::OnScene3DEnd() -{ - //Render Console - if (m_bDrawConsole && gEnv->pConsole) - { - gEnv->pConsole->Draw(); - } -} - -////////////////////////////////////////////////////////////////////////// - -void CSystem::DisplayErrorMessage(const char* acMessage, - [[maybe_unused]] float fTime, - const float* pfColor, - bool bHardError) -{ - SErrorMessage message; - message.m_Message = acMessage; - if (pfColor) - { - memcpy(message.m_Color, pfColor, 4 * sizeof(float)); - } - else - { - message.m_Color[0] = 1.0f; - message.m_Color[1] = 0.0f; - message.m_Color[2] = 0.0f; - message.m_Color[3] = 1.0f; - } - message.m_HardFailure = bHardError; -#ifdef _RELEASE - message.m_fTimeToShow = fTime; -#else - message.m_fTimeToShow = 1.0f; -#endif - m_ErrorMessages.push_back(message); -} diff --git a/Code/CryEngine/CrySystem/SystemWin32.cpp b/Code/CryEngine/CrySystem/SystemWin32.cpp index 72c43bceed..c974365bfc 100644 --- a/Code/CryEngine/CrySystem/SystemWin32.cpp +++ b/Code/CryEngine/CrySystem/SystemWin32.cpp @@ -51,10 +51,8 @@ #endif #include "XConsole.h" -#include "StreamEngine/StreamEngine.h" #include "LocalizedStringManager.h" #include "XML/XmlUtils.h" -#include "AutoDetectSpec.h" #if defined(WIN32) __pragma(comment(lib, "wininet.lib")) @@ -121,19 +119,6 @@ struct PEHeader_DLL #pragma pack(pop) #endif -const SmallModuleInfo* FindModuleInfo(std::vector& vec, const char* name) -{ - for (size_t i = 0; i < vec.size(); ++i) - { - if (!vec[i].name.compareNoCase(name)) - { - return &vec[i]; - } - } - - return 0; -} - ////////////////////////////////////////////////////////////////////////// const char* CSystem::GetUserName() { @@ -231,30 +216,6 @@ int CSystem::GetApplicationLogInstance([[maybe_unused]] const char* logFilePath) #endif } -// these 2 functions are duplicated in System.cpp in editor -////////////////////////////////////////////////////////////////////////// -#if !defined(LINUX) -extern int CryStats(char* buf); -#endif -int CSystem::DumpMMStats(bool log) -{ -#if defined(LINUX) - return 0; -#else - if (log) - { - char buf[1024]; - int n = CryStats(buf); - GetILog()->Log(buf); - return n; - } - else - { - return CryStats(NULL); - }; -#endif -}; - ////////////////////////////////////////////////////////////////////////// struct CryDbgModule { @@ -264,273 +225,7 @@ struct CryDbgModule DWORD dwSize; }; -////////////////////////////////////////////////////////////////////////// -void CSystem::DebugStats([[maybe_unused]] bool checkpoint, [[maybe_unused]] bool leaks) -{ -#ifdef WIN32 - std::vector dbgmodules; - - ////////////////////////////////////////////////////////////////////////// - // Use windows Performance Monitoring API to enumerate all modules of current process. - ////////////////////////////////////////////////////////////////////////// - HANDLE hSnapshot; - hSnapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); - if (hSnapshot != INVALID_HANDLE_VALUE) - { - MODULEENTRY32 me; - memset (&me, 0, sizeof(me)); - me.dwSize = sizeof(me); - - if (Module32First (hSnapshot, &me)) - { - // the sizes of each module group - do - { - CryDbgModule module; - module.handle = me.hModule; - module.name = me.szModule; - module.dwSize = me.modBaseSize; - dbgmodules.push_back(module); - } while (Module32Next(hSnapshot, &me)); - } - CloseHandle (hSnapshot); - } - ////////////////////////////////////////////////////////////////////////// - - int nolib = 0; - -#ifdef _DEBUG - ILog* log = GetILog(); - int totalal = 0; - int totalbl = 0; - int extrastats[10]; -#endif - - int totalUsedInModules = 0; - int countedMemoryModules = 0; - for (int i = 0; i < (int)(dbgmodules.size()); i++) - { - if (!dbgmodules[i].handle) - { - CryLogAlways("WARNING: CSystem::DebugStats: NULL handle for %s", dbgmodules[i].name.c_str()); - nolib++; - continue; - } - ; - - typedef int (* PFN_MODULEMEMORY)(); - PFN_MODULEMEMORY fpCryModuleGetAllocatedMemory = (PFN_MODULEMEMORY)::GetProcAddress((HMODULE)dbgmodules[i].handle, "CryModuleGetAllocatedMemory"); - if (fpCryModuleGetAllocatedMemory) - { - int allocatedMemory = fpCryModuleGetAllocatedMemory(); - totalUsedInModules += allocatedMemory; - countedMemoryModules++; - CryLogAlways("%8d K used in Module %s: ", allocatedMemory / 1024, dbgmodules[i].name.c_str()); - } - -#ifdef _DEBUG - typedef void (* PFNUSAGESUMMARY)(ILog* log, const char*, int*); - typedef void (* PFNCHECKPOINT)(); - PFNUSAGESUMMARY fpu = (PFNUSAGESUMMARY)::GetProcAddress((HMODULE)dbgmodules[i].handle, "UsageSummary"); - PFNCHECKPOINT fpc = (PFNCHECKPOINT)::GetProcAddress((HMODULE)dbgmodules[i].handle, "CheckPoint"); - if (fpu && fpc) - { - if (checkpoint) - { - fpc(); - } - else - { - extrastats[2] = (int)leaks; - fpu(log, dbgmodules[i].name.c_str(), extrastats); - totalal += extrastats[0]; - totalbl += extrastats[1]; - }; - } - else - { - CryLogAlways("WARNING: CSystem::DebugStats: could not retrieve function from DLL %s", dbgmodules[i].name.c_str()); - nolib++; - }; -#endif - - typedef HANDLE(* PFNGETDLLHEAP)(); - PFNGETDLLHEAP fpg = (PFNGETDLLHEAP)::GetProcAddress((HMODULE)dbgmodules[i].handle, "GetDLLHeap"); - if (fpg) - { - dbgmodules[i].heap = fpg(); - } - ; - } - ; - - CryLogAlways("-------------------------------------------------------"); - CryLogAlways("%8d K Total Memory Allocated in %d Modules", totalUsedInModules / 1024, countedMemoryModules); -#ifdef _DEBUG - CryLogAlways("$8GRAND TOTAL: %d k, %d blocks (%d dlls not included)", totalal / 1024, totalbl, nolib); - CryLogAlways("estimated debugalloc overhead: between %d k and %d k", totalbl * 36 / 1024, totalbl * 72 / 1024); -#endif - - ////////////////////////////////////////////////////////////////////////// - // Get HeapQueryInformation pointer if on windows XP. - ////////////////////////////////////////////////////////////////////////// - typedef BOOL (WINAPI * FUNC_HeapQueryInformation)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); - FUNC_HeapQueryInformation pFnHeapQueryInformation = NULL; - HMODULE hKernelInstance = CryLoadLibrary("Kernel32.dll"); - if (hKernelInstance) - { - pFnHeapQueryInformation = (FUNC_HeapQueryInformation)(::GetProcAddress(hKernelInstance, "HeapQueryInformation")); - } - ////////////////////////////////////////////////////////////////////////// - - const int MAXHANDLES = 100; - HANDLE handles[MAXHANDLES]; - int realnumh = GetProcessHeaps(MAXHANDLES, handles); - char hinfo[1024]; - PROCESS_HEAP_ENTRY phe; - CryLogAlways("$6--------------------- dump of windows heaps ---------------------"); - int nTotalC = 0, nTotalCP = 0, nTotalUC = 0, nTotalUCP = 0, totalo = 0; - for (int i = 0; i < realnumh; i++) - { - HANDLE hHeap = handles[i]; - HeapCompact(hHeap, 0); - hinfo[0] = 0; - if (pFnHeapQueryInformation) - { - pFnHeapQueryInformation(hHeap, HeapCompatibilityInformation, hinfo, 1024, NULL); - } - else - { - for (int m = 0; m < (int)(dbgmodules.size()); m++) - { - if (dbgmodules[m].heap == handles[i]) - { - azstrcpy(hinfo, AZ_ARRAY_SIZE(hinfo), dbgmodules[m].name.c_str()); - } - } - } - phe.lpData = NULL; - int nCommitted = 0, nUncommitted = 0, nOverhead = 0; - int nCommittedPieces = 0, nUncommittedPieces = 0; -#if !defined(NDEBUG) - int nPrevRegionIndex = -1; -#endif - while (HeapWalk(hHeap, &phe)) - { - if (phe.wFlags & PROCESS_HEAP_REGION) - { - assert (++nPrevRegionIndex == phe.iRegionIndex); - nCommitted += phe.Region.dwCommittedSize; - nUncommitted += phe.Region.dwUnCommittedSize; - assert (phe.cbData == 0 || (phe.wFlags & PROCESS_HEAP_ENTRY_BUSY)); - } - else - if (phe.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) - { - nUncommittedPieces += phe.cbData; - } - else - { - //if (phe.wFlags & PROCESS_HEAP_ENTRY_BUSY) - nCommittedPieces += phe.cbData; - } - - - { - /* - MEMORY_BASIC_INFORMATION mbi; - if (VirtualQuery(phe.lpData, &mbi,sizeof(mbi)) == sizeof(mbi)) - { - if (mbi.State == MEM_COMMIT) - nCommittedPieces += phe.cbData;//mbi.RegionSize; - //else - // nUncommitted += mbi.RegionSize; - } - else - nCommittedPieces += phe.cbData; - */ - } - - nOverhead += phe.cbOverhead; - } - - CryLogAlways("* heap %8x: %6d (or ~%6d) K in use, %6d..%6d K uncommitted, %6d K overhead (%s)\n", - handles[i], nCommittedPieces / 1024, nCommitted / 1024, nUncommittedPieces / 1024, nUncommitted / 1024, nOverhead / 1024, hinfo); - - nTotalC += nCommitted; - nTotalCP += nCommittedPieces; - nTotalUC += nUncommitted; - nTotalUCP += nUncommittedPieces; - totalo += nOverhead; - } - ; - CryLogAlways("$6----------------- total in heaps: %d megs committed (win stats shows ~%d) (%d..%d uncommitted, %d k overhead) ---------------------", nTotalCP / 1024 / 1024, nTotalC / 1024 / 1024, nTotalUCP / 1024 / 1024, nTotalUC / 1024 / 1024, totalo / 1024); - -#endif //WIN32 -}; - #ifdef WIN32 -struct DumpHeap32Stats -{ - DumpHeap32Stats() - : dwFree(0) - , dwMoveable(0) - , dwFixed(0) - , dwUnknown(0) - { - } - void operator += (const DumpHeap32Stats& right) - { - dwFree += right.dwFree; - dwMoveable += right.dwMoveable; - dwFixed += right.dwFixed; - dwUnknown += right.dwUnknown; - } - DWORD dwFree; - DWORD dwMoveable; - DWORD dwFixed; - DWORD dwUnknown; -}; -static void DumpHeap32 (const HEAPLIST32& hl, DumpHeap32Stats& stats) -{ - HEAPENTRY32 he; - memset (&he, 0, sizeof(he)); - he.dwSize = sizeof(he); - - if (Heap32First (&he, hl.th32ProcessID, hl.th32HeapID)) - { - DumpHeap32Stats heap; - do - { - if (he.dwFlags & LF32_FREE) - { - heap.dwFree += he.dwBlockSize; - } - else - if (he.dwFlags & LF32_MOVEABLE) - { - heap.dwMoveable += he.dwBlockSize; - } - else - if (he.dwFlags & LF32_FIXED) - { - heap.dwFixed += he.dwBlockSize; - } - else - { - heap.dwUnknown += he.dwBlockSize; - } - } while (Heap32Next (&he)); - - CryLogAlways ("%08X %6d %6d %6d (%d)", hl.th32HeapID, heap.dwFixed / 0x400, heap.dwFree / 0x400, heap.dwMoveable / 0x400, heap.dwUnknown / 0x400); - stats += heap; - } - else - { - CryLogAlways ("%08X empty or invalid"); - } -} - ////////////////////////////////////////////////////////////////////////// class CStringOrder { @@ -566,94 +261,6 @@ const char* GetModuleGroup (const char* szString) #endif -////////////////////////////////////////////////////////////////////////// -void CSystem::DumpWinHeaps() -{ -#ifdef WIN32 - // - // Retrieve modules and log them; remember the process id - - HANDLE hSnapshot; - hSnapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0); - if (hSnapshot == INVALID_HANDLE_VALUE) - { - CryLogAlways ("Cannot get the module snapshot, error code %d", GetLastError()); - return; - } - - DWORD dwProcessID = GetCurrentProcessId(); - - MODULEENTRY32 me; - memset (&me, 0, sizeof(me)); - me.dwSize = sizeof(me); - - if (Module32First (hSnapshot, &me)) - { - // the sizes of each module group - StringToSizeMap mapGroupSize; - DWORD dwTotalModuleSize = 0; - CryLogAlways ("base size module"); - do - { - dwProcessID = me.th32ProcessID; - const char* szGroup = GetModuleGroup (me.szModule); - CryLogAlways ("%08X %8X %25s - %s", me.modBaseAddr, me.modBaseSize, me.szModule, azstricmp(szGroup, "Other") ? szGroup : ""); - dwTotalModuleSize += me.modBaseSize; - AddSize (mapGroupSize, szGroup, me.modBaseSize); - } while (Module32Next(hSnapshot, &me)); - - CryLogAlways ("------------------------------------"); - for (StringToSizeMap::iterator it = mapGroupSize.begin(); it != mapGroupSize.end(); ++it) - { - CryLogAlways (" %6.3f Mbytes - %s", double(it->second) / 0x100000, it->first); - } - CryLogAlways ("------------------------------------"); - CryLogAlways (" %6.3f Mbytes - TOTAL", double(dwTotalModuleSize) / 0x100000); - CryLogAlways ("------------------------------------"); - } - else - { - CryLogAlways ("No modules to dump"); - } - - CloseHandle (hSnapshot); - - // - // Retrieve the heaps and dump each of them with a special function - - hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, 0); - if (hSnapshot == INVALID_HANDLE_VALUE) - { - CryLogAlways ("Cannot get the heap LIST snapshot, error code %d", GetLastError()); - return; - } - - HEAPLIST32 hl; - memset (&hl, 0, sizeof(hl)); - hl.dwSize = sizeof(hl); - - CryLogAlways ("__Heap__ fixed free move (unknown)"); - if (Heap32ListFirst (hSnapshot, &hl)) - { - DumpHeap32Stats stats; - do - { - DumpHeap32 (hl, stats); - } while (Heap32ListNext (hSnapshot, &hl)); - - CryLogAlways ("-------------------------------------------------"); - CryLogAlways ("$6 %6.3f %6.3f %6.3f (%.3f) Mbytes", double(stats.dwFixed) / 0x100000, double(stats.dwFree) / 0x100000, double(stats.dwMoveable) / 0x100000, double(stats.dwUnknown) / 0x100000); - CryLogAlways ("-------------------------------------------------"); - } - else - { - CryLogAlways ("No heaps to dump"); - } - - CloseHandle(hSnapshot); -#endif -} - // Make system error message string ////////////////////////////////////////////////////////////////////////// //! \return pointer to the null terminated error string or 0 @@ -739,8 +346,6 @@ void CSystem::FatalError(const char* format, ...) assert(szBuffer[0] >= ' '); // strcpy(szBuffer,szBuffer+1); // remove verbosity tag since it is not supported by ::MessageBox - LogSystemInfo(); - OutputDebugString(szBuffer); #ifdef WIN32 OnFatalError(szBuffer); @@ -879,146 +484,6 @@ bool CSystem::ReLaunchMediaCenter() } #endif //defined(WIN32) -////////////////////////////////////////////////////////////////////////// -#if defined(WIN32) -void CSystem::LogSystemInfo() -{ - ////////////////////////////////////////////////////////////////////// - // Write the system informations to the log - ////////////////////////////////////////////////////////////////////// - - char szBuffer[1024]; - char szProfileBuffer[128]; - char szLanguageBuffer[64]; - //char szCPUModel[64]; - - MEMORYSTATUSEX MemoryStatus; - MemoryStatus.dwLength = sizeof(MemoryStatus); - - DEVMODE DisplayConfig; - OSVERSIONINFO OSVerInfo; - OSVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - - // log system language - GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, szLanguageBuffer, sizeof(szLanguageBuffer)); - azsprintf(szBuffer, "System language: %s", szLanguageBuffer); - CryLogAlways(szBuffer); - - // log Windows directory - GetWindowsDirectory(szBuffer, sizeof(szBuffer)); - string str = "Windows Directory: \""; - str += szBuffer; - str += "\""; - CryLogAlways(str); - - ////////////////////////////////////////////////////////////////////// - // Send system time & date - ////////////////////////////////////////////////////////////////////// - - str = "Local time is "; - azstrtime(szBuffer); - str += szBuffer; - str += " "; - _strdate_s(szBuffer); - str += szBuffer; - azsprintf(szBuffer, ", system running for %lu minutes", GetTickCount() / 60000); - str += szBuffer; - CryLogAlways(str); - - ////////////////////////////////////////////////////////////////////// - // Send system memory status - ////////////////////////////////////////////////////////////////////// - - GlobalMemoryStatusEx(&MemoryStatus); - azsprintf(szBuffer, "%I64dMB physical memory installed, %I64dMB available, %I64dMB virtual memory installed, %ld percent of memory in use", - MemoryStatus.ullTotalPhys / 1048576 + 1, - MemoryStatus.ullAvailPhys / 1048576, - MemoryStatus.ullTotalVirtual / 1048576, - MemoryStatus.dwMemoryLoad); - CryLogAlways(szBuffer); - - if (GetISystem()->GetIMemoryManager()) - { - IMemoryManager::SProcessMemInfo memCounters; - GetISystem()->GetIMemoryManager()->GetProcessMemInfo(memCounters); - - uint64 PagefileUsage = memCounters.PagefileUsage; - uint64 PeakPagefileUsage = memCounters.PeakPagefileUsage; - uint64 WorkingSetSize = memCounters.WorkingSetSize; - azsprintf(szBuffer, "PageFile usage: %I64dMB, Working Set: %I64dMB, Peak PageFile usage: %I64dMB,", - (uint64)PagefileUsage / (1024 * 1024), - (uint64)WorkingSetSize / (1024 * 1024), - (uint64)PeakPagefileUsage / (1024 * 1024)); - CryLogAlways(szBuffer); - } - - ////////////////////////////////////////////////////////////////////// - // Send display settings - ////////////////////////////////////////////////////////////////////// - - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DisplayConfig); - GetPrivateProfileString("boot.description", "display.drv", - "(Unknown graphics card)", szProfileBuffer, sizeof(szProfileBuffer), - "system.ini"); - azsprintf(szBuffer, "Current display mode is %lux%lux%lu, %s", - DisplayConfig.dmPelsWidth, DisplayConfig.dmPelsHeight, - DisplayConfig.dmBitsPerPel, szProfileBuffer); - CryLogAlways(szBuffer); - - ////////////////////////////////////////////////////////////////////// - // Send input device configuration - ////////////////////////////////////////////////////////////////////// - - str = ""; - // Detect the keyboard type - switch (GetKeyboardType(0)) - { - case 1: - str = "IBM PC/XT (83-key)"; - break; - case 2: - str = "ICO (102-key)"; - break; - case 3: - str = "IBM PC/AT (84-key)"; - break; - case 4: - str = "IBM enhanced (101/102-key)"; - break; - case 5: - str = "Nokia 1050"; - break; - case 6: - str = "Nokia 9140"; - break; - case 7: - str = "Japanese"; - break; - default: - str = "Unknown"; - break; - } - - // Any mouse attached ? - if (!GetSystemMetrics(SM_MOUSEPRESENT)) - { - CryLogAlways(str + " keyboard and no mouse installed"); - } - else - { - azsprintf(szBuffer, " keyboard and %i+ button mouse installed", - GetSystemMetrics(SM_CMOUSEBUTTONS)); - CryLogAlways(str + szBuffer); - } - - CryLogAlways("--------------------------------------------------------------------------------"); -} -#else -void CSystem::LogSystemInfo() -{ -} -#endif - #if (defined(WIN32) || defined(WIN64)) ////////////////////////////////////////////////////////////////////////// bool CSystem::GetWinGameFolder(char* szMyDocumentsPath, int maxPathSize) diff --git a/Code/CryEngine/CrySystem/Tests/Test_CLog.cpp b/Code/CryEngine/CrySystem/Tests/Test_CLog.cpp deleted file mode 100644 index e792ba095f..0000000000 --- a/Code/CryEngine/CrySystem/Tests/Test_CLog.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "CrySystem_precompiled.h" - -#include -#include - -#include -#include - -#include // for max path decl -#include -#include -#include -#include - -namespace CLogUnitTests -{ - using ::testing::NiceMock; - using ::testing::_; - using ::testing::Return; - - // for fuzzing test, how much work to do? Not much, as this must be fast. - const int NumTrialsToPerform = 16000; - - class CLogUnitTests - : public ::testing::Test - { - public: - - using CryPrimitivesAllocatorScope = AZ::AllocatorScope; - - void SetUp() override - { - m_primitiveAllocators.ActivateAllocators(); - - m_priorEnv = gEnv; - m_priorFileIO = AZ::IO::FileIOBase::GetInstance(); - m_priorDirectFileIO = AZ::IO::FileIOBase::GetDirectInstance(); - - m_data = AZStd::make_unique(); - m_data->m_stubEnv.pSystem = &m_data->m_system; - - gEnv = &m_data->m_stubEnv; - - // for FileIO, you must set the instance to null before changing it. - // this is a way to tell the singleton system that you mean to replace a singleton and its - // not a mistake. - AZ::IO::FileIOBase::SetInstance(nullptr); - AZ::IO::FileIOBase::SetInstance(&m_data->m_fileIOMock); - AZ::IO::FileIOBase::SetDirectInstance(nullptr); - AZ::IO::FileIOBase::SetDirectInstance(&m_data->m_fileIOMock); - - ON_CALL(m_data->m_system, GetIRemoteConsole()) - .WillByDefault( - Return(&m_data->m_remoteConsoleMock)); - - AZ::IO::MockFileIOBase::InstallDefaultReturns(m_data->m_fileIOMock); - } - - void TearDown() override - { - AZ::IO::FileIOBase::SetInstance(nullptr); - AZ::IO::FileIOBase::SetInstance(m_priorFileIO); - AZ::IO::FileIOBase::SetDirectInstance(nullptr); - AZ::IO::FileIOBase::SetDirectInstance(m_priorDirectFileIO); - - m_data.reset(); - - // restore state. - gEnv = m_priorEnv; - m_primitiveAllocators.DeactivateAllocators(); - } - - struct DataMembers - { - SSystemGlobalEnvironment m_stubEnv; - NiceMock m_system; - NiceMock m_fileIOMock; - NiceMock m_remoteConsoleMock; - }; - - AZStd::unique_ptr m_data; - SSystemGlobalEnvironment* m_priorEnv = nullptr; - ISystem* m_priorSystem = nullptr; - AZ::IO::FileIOBase* m_priorFileIO = nullptr; - AZ::IO::FileIOBase* m_priorDirectFileIO = nullptr; - CryPrimitivesAllocatorScope m_primitiveAllocators; - }; - - TEST_F(CLogUnitTests, LogAlways_InvalidString_Asserts) - { - AZ_TEST_START_TRACE_SUPPRESSION; - CLog testLog(&m_data->m_system); - testLog.LogAlways(nullptr); - AZ_TEST_STOP_TRACE_SUPPRESSION(1); - } - - TEST_F(CLogUnitTests, LogAlways_EmptyString_IgnoresWithoutCrashing) - { - CLog testLog(&m_data->m_system); - testLog.LogAlways(""); - } - - TEST_F(CLogUnitTests, LogAlways_NormalString_NoFileName_DoesNotCrash) - { - CLog testLog(&m_data->m_system); - testLog.LogAlways("test"); - } - - TEST_F(CLogUnitTests, LogAlways_SetFileName_Empty_DoesNotCrash) - { - CLog testLog(&m_data->m_system); - testLog.SetFileName("", false); - testLog.LogAlways("test"); - } - -#if AZ_TRAIT_DISABLE_LOG_ALWAYS_FUZZ_TEST - TEST_F(CLogUnitTests, DISABLED_LogAlways_FuzzTest) -#else - TEST_F(CLogUnitTests, LogAlways_FuzzTest) -#endif // AZ_TRAIT_DISABLE_LOG_ALWAYS_FUZZ_TEST - { - CLog testLog(&m_data->m_system); - AZStd::string randomJunkName; - - randomJunkName.resize(128, '\0'); - - // expect the mock to repeatedly get called. If we fail this expectation - // it means the code is early-outing somewhere and we are not getting coverage. - EXPECT_CALL(m_data->m_fileIOMock, Write(_, _, _, _)) - .WillRepeatedly( - Return(AZ::IO::Result(AZ::IO::ResultCode::Success))); - - // don't rely on randomness in unit tests, they need to be repeatable. - // the following random generator is not seeded by the time, but by a constant (default 1234). - AZ::SimpleLcgRandom randGen; - - for (int trialNumber = 0; trialNumber < NumTrialsToPerform; ++trialNumber) - { - for (int randomChar = 0; randomChar < randomJunkName.size(); ++randomChar) - { - // note that this is intentionally allowing null characters to generate. - // note that this also puts characters AFTER the null, if a null appears in the mddle. - // so that if there are off by one errors they could include cruft afterwards. - - if (randomChar > trialNumber % randomJunkName.size()) - { - // choose this point for the nulls to begin. It makes sure we test every size of string. - randomJunkName[randomChar] = 0; - } - else - { - randomJunkName[randomChar] = (char)(randGen.GetRandom() % 256); // this will trigger invalid UTF8 decoding too - } - } - testLog.LogAlways("%s", randomJunkName.c_str()); - } - } - - TEST_F(CLogUnitTests, LogAlways_SetFileName_Correct_DoesNotCrash_WritesToFile) - { - CLog testLog(&m_data->m_system); - testLog.SetFileName("logfile.log", false); - - // EXPECT a call to the file system - if we dont get a call here, it means something went wrong. - // it also expects exactly one call to write. One call to log should be one call to write, - // or else performance will suffer. - - EXPECT_CALL(m_data->m_fileIOMock, Write(_, _, _, _)) - .WillOnce( - Return(AZ::IO::Result(AZ::IO::ResultCode::Success))); - - testLog.LogAlways("test"); - } -} // end namespace CLogUnitTests - - diff --git a/Code/CryEngine/CrySystem/Tests/Test_CommandRegistration.cpp b/Code/CryEngine/CrySystem/Tests/Test_CommandRegistration.cpp deleted file mode 100644 index d54ba87446..0000000000 --- a/Code/CryEngine/CrySystem/Tests/Test_CommandRegistration.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "CrySystem_precompiled.h" - -#include - -#include - -#include -#include -#include -#include - -#include - -namespace UnitTests -{ - class RemoteConsoleMock - : public IRemoteConsole - { - public: - MOCK_METHOD0(RegisterConsoleVariables, void()); - MOCK_METHOD0(UnregisterConsoleVariables, void()); - MOCK_METHOD0(Start, void()); - MOCK_METHOD0(Stop, void()); - MOCK_CONST_METHOD0(IsStarted, bool()); - MOCK_METHOD1(AddLogMessage, void(const char*)); - MOCK_METHOD1(AddLogWarning, void(const char*)); - MOCK_METHOD1(AddLogError, void(const char*)); - MOCK_METHOD0(Update, void()); - MOCK_METHOD2(RegisterListener, void(IRemoteConsoleListener*, const char*)); - MOCK_METHOD1(UnregisterListener, void(IRemoteConsoleListener*)); - }; - - struct TestTraceMessageCapture - : public AZ::Debug::TraceMessageBus::Handler - { - using Callback = AZStd::function; - Callback m_callback; - - TestTraceMessageCapture() - { - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - } - - ~TestTraceMessageCapture() - { - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - } - - bool OnError(const char* window, const char* message) override - { - if (m_callback) - { - m_callback(window, message); - } - return false; - } - - bool OnWarning(const char* window, const char* message) override - { - if (m_callback) - { - m_callback(window, message); - } - return false; - } - }; - - using SystemAllocatorScope = AZ::AllocatorScope; - - struct CommandRegistrationUnitTests - : public ::testing::Test - , public SystemAllocatorScope - { - CommandRegistrationUnitTests() - { - EXPECT_CALL(m_system, GetIRemoteConsole()) - .WillRepeatedly(::testing::Return(&m_remoteConsole)); - } - - void SetUp() override - { - SystemAllocatorScope::ActivateAllocators(); - - memset(&m_stubEnv, 0, sizeof(SSystemGlobalEnvironment)); - m_stubEnv.pSystem = &m_system; - m_priorEnv = gEnv; - gEnv = &m_stubEnv; - - // now it safe to set up the console - m_console = AZStd::make_unique(); - m_stubEnv.pConsole = m_console.get(); - - EXPECT_CALL(m_system, GetIConsole()) - .WillRepeatedly(::testing::Return(m_stubEnv.pConsole)); - } - - void TearDown() override - { - m_console.reset(); - gEnv = m_priorEnv; - SystemAllocatorScope::DeactivateAllocators(); - } - - ::testing::NiceMock m_system; - ::testing::NiceMock m_remoteConsole; - AZStd::unique_ptr m_console; - SSystemGlobalEnvironment m_stubEnv; - SSystemGlobalEnvironment* m_priorEnv = nullptr; - }; - - TEST_F(CommandRegistrationUnitTests, RegisterUnregisterTest) - { - using namespace AzFramework; - - { - bool result = false; - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::RegisterCommand, "foo", "", 0, [](const AZStd::vector&) -> CommandResult - { - return CommandResult::Success; - }); - EXPECT_TRUE(result); - } - - { - bool result = false; - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::UnregisterCommand, "foo"); - EXPECT_TRUE(result); - } - } - - TEST_F(CommandRegistrationUnitTests, RegisterUnregisterNegativeTest) - { - using namespace AzFramework; - - // register too many times - { - auto fnFoo = [](const AZStd::vector&) -> CommandResult - { - return CommandResult::Success; - }; - - bool result = false; - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::RegisterCommand, "foo", "", 0, fnFoo); - EXPECT_TRUE(result); - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::RegisterCommand, "foo", "", 0, fnFoo); - EXPECT_FALSE(result); - } - - // unregister too many times - { - bool result = false; - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::UnregisterCommand, "foo"); - EXPECT_TRUE(result); - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::UnregisterCommand, "foo"); - EXPECT_FALSE(result); - } - - // a null callback should fail - { - AZ_TEST_START_TRACE_SUPPRESSION; - bool result = false; - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::RegisterCommand, "shouldfail", "", 0, nullptr); - EXPECT_FALSE(result); - AZ_TEST_STOP_TRACE_SUPPRESSION(1); - } - - // a null identifier should fail - { - AZ_TEST_START_TRACE_SUPPRESSION; - bool result = false; - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::RegisterCommand, "", "", 0, nullptr); - EXPECT_FALSE(result); - AZ_TEST_STOP_TRACE_SUPPRESSION(1); - } - } - - TEST_F(CommandRegistrationUnitTests, DoCallback) - { - using namespace AzFramework; - - int count = 0; - - { - auto fnCommand = [&count](const AZStd::vector&) -> CommandResult - { - ++count; - return CommandResult::Success; - }; - - bool result = false; - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::RegisterCommand, "bar", "bar docs", CommandFlags::Development, fnCommand); - EXPECT_TRUE(result); - } - - const bool bSilentMode = true; - const bool bDeferExecution = false; - m_console->ExecuteString("bar", bSilentMode, bDeferExecution); - EXPECT_EQ(1, count); - - { - bool result = false; - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::UnregisterCommand, "bar"); - EXPECT_TRUE(result); - } - } - - TEST_F(CommandRegistrationUnitTests, DoCallbackNegativeTests) - { - using namespace AzFramework; - - bool result = false; - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::RegisterCommand, "bar", "", 0, [](const AZStd::vector& args) - { - if (args.size() > 1) - { - return CommandResult::ErrorWrongNumberOfArguments; - } - return CommandResult::Error; - }); - EXPECT_TRUE(result); - - const bool bSilentMode = true; - const bool bDeferExecution = false; - - // general error - { - int found = 0; - TestTraceMessageCapture capture; - capture.m_callback = [&found](const char* window, const char* message) - { - if (azstrnicmp(window, "console", AZ_ARRAY_SIZE("console") - 1) == 0) - { - if (azstrnicmp(message, "Command returned a generic error\n", AZ_ARRAY_SIZE("Command returned a generic error\n") - 1) == 0) - { - ++found; - } - } - }; - m_console->ExecuteString("bar", bSilentMode, bDeferExecution); - EXPECT_EQ(1, found); - } - - // too many args - { - int found = 0; - TestTraceMessageCapture capture; - capture.m_callback = [&found](const char* window, const char* message) - { - if (azstrnicmp(window, "console", AZ_ARRAY_SIZE("console") - 1) == 0) - { - if (azstrnicmp(message, "Command does not have the right number of arguments (send = 4)\n", AZ_ARRAY_SIZE("Command does not have the right number of arguments (send = 4)\n") - 1) == 0) - { - ++found; - } - } - }; - m_console->ExecuteString("bar 1 2 3", bSilentMode, bDeferExecution); - EXPECT_EQ(1, found); - } - - // clean up - { - result = false; - CommandRegistrationBus::BroadcastResult(result, &CommandRegistrationBus::Events::UnregisterCommand, "bar"); - EXPECT_TRUE(result); - } - } - -} // namespace UnitTests - - diff --git a/Code/CryEngine/CrySystem/Tests/Test_CryPrimitives.cpp b/Code/CryEngine/CrySystem/Tests/Test_CryPrimitives.cpp deleted file mode 100644 index 26d12ffd8c..0000000000 --- a/Code/CryEngine/CrySystem/Tests/Test_CryPrimitives.cpp +++ /dev/null @@ -1,463 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "CrySystem_precompiled.h" -#include -#include - -TEST(StringTests, CUT_Strings) -{ - bool bOk; - char bf[4]; - - // cry_strcpy() - - bOk = cry_strcpy(0, 0, 0); - EXPECT_TRUE(!bOk); - - bOk = cry_strcpy(0, 0, 0, 0); - EXPECT_TRUE(!bOk); - - bOk = cry_strcpy(0, 1, 0); - EXPECT_TRUE(!bOk); - - bOk = cry_strcpy(0, 1, 0, 1); - EXPECT_TRUE(!bOk); - - bOk = cry_strcpy(0, 1, ""); - EXPECT_TRUE(!bOk); - - bOk = cry_strcpy(0, 1, "", 1); - EXPECT_TRUE(!bOk); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 0, ""); - EXPECT_TRUE(!bOk && !memcmp(bf, "abcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 0, "", 1); - EXPECT_TRUE(!bOk && !memcmp(bf, "abcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 1, 0); - EXPECT_TRUE(!bOk && !memcmp(bf, "\000bcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 1, 0, 0); - EXPECT_TRUE(!bOk && !memcmp(bf, "\000bcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 0); - EXPECT_TRUE(!bOk && !memcmp(bf, "\000bcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 3, "qwerty"); - EXPECT_TRUE(!bOk && !memcmp(bf, "qw\000d", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 3, "qwerty", 4); - EXPECT_TRUE(!bOk && !memcmp(bf, "qw\000d", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 3, "qwerty", 3); - EXPECT_TRUE(!bOk && !memcmp(bf, "qw\000d", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 3, "qwerty", 2); - EXPECT_TRUE(bOk && !memcmp(bf, "qw\000d", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 3, "qwerty", 1); - EXPECT_TRUE(bOk && !memcmp(bf, "q\000cd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, 3, "qwerty", 0); - EXPECT_TRUE(bOk && !memcmp(bf, "\000bcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, "qwerty"); - EXPECT_TRUE(!bOk && !memcmp(bf, "qwe\000", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, "qwerty", 4); - EXPECT_TRUE(!bOk && !memcmp(bf, "qwe\000", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, "qwerty", 3); - EXPECT_TRUE(bOk && !memcmp(bf, "qwe\000", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, "qwerty", 2); - EXPECT_TRUE(bOk && !memcmp(bf, "qw\000d", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, "qwe"); - EXPECT_TRUE(bOk && !memcmp(bf, "qwe\000", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, "qwe", 4); - EXPECT_TRUE(bOk && !memcmp(bf, "qwe\000", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, "qw", 3); - EXPECT_TRUE(bOk && !memcmp(bf, "qw\000d", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, sizeof(bf), "q"); - EXPECT_TRUE(bOk && !memcmp(bf, "q\000cd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcpy(bf, sizeof(bf), "q", 2); - EXPECT_TRUE(bOk && !memcmp(bf, "q\000cd", 4)); - - // cry_strcat() - - bOk = cry_strcat(0, 0, 0); - EXPECT_TRUE(!bOk); - - bOk = cry_strcat(0, 0, 0, 0); - EXPECT_TRUE(!bOk); - - bOk = cry_strcat(0, 1, 0); - EXPECT_TRUE(!bOk); - - bOk = cry_strcat(0, 1, 0, 0); - EXPECT_TRUE(!bOk); - - bOk = cry_strcat(0, 1, ""); - EXPECT_TRUE(!bOk); - - bOk = cry_strcat(0, 1, "", 1); - EXPECT_TRUE(!bOk); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, 0, "xy"); - EXPECT_TRUE(!bOk && !memcmp(bf, "abcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, 0, "xy", 3); - EXPECT_TRUE(!bOk && !memcmp(bf, "abcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, 0, "xy", 0); - EXPECT_TRUE(!bOk && !memcmp(bf, "abcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, 1, "xyz"); - EXPECT_TRUE(!bOk && !memcmp(bf, "\000bcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, 1, "xyz", 4); - EXPECT_TRUE(!bOk && !memcmp(bf, "\000bcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, 1, "xyz", 1); - EXPECT_TRUE(!bOk && !memcmp(bf, "\000bcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, 1, "xyz", 0); - EXPECT_TRUE(bOk && !memcmp(bf, "\000bcd", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, 1, 0, 0); - EXPECT_TRUE(!bOk && !memcmp(bf, "\000bcd", 4)); - - memcpy(bf, "a\000cd", 4); - bOk = cry_strcat(bf, 3, "xyz"); - EXPECT_TRUE(!bOk && !memcmp(bf, "ax\000d", 4)); - - memcpy(bf, "a\000cd", 4); - bOk = cry_strcat(bf, 3, "xyz", 4); - EXPECT_TRUE(!bOk && !memcmp(bf, "ax\000d", 4)); - - memcpy(bf, "a\000cd", 4); - bOk = cry_strcat(bf, 3, "xyz", 2); - EXPECT_TRUE(!bOk && !memcmp(bf, "ax\000d", 4)); - - memcpy(bf, "a\000cd", 4); - bOk = cry_strcat(bf, 3, "xyz", 1); - EXPECT_TRUE(bOk && !memcmp(bf, "ax\000d", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, "xyz"); - EXPECT_TRUE(!bOk && !memcmp(bf, "abc\000", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, "xyz", 4); - EXPECT_TRUE(!bOk && !memcmp(bf, "abc\000", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, "xyz", 1); - EXPECT_TRUE(!bOk && !memcmp(bf, "abc\000", 4)); - - memcpy(bf, "abcd", 4); - bOk = cry_strcat(bf, "xyz", 0); - EXPECT_TRUE(bOk && !memcmp(bf, "abc\000", 4)); - - memcpy(bf, "ab\000d", 4); - bOk = cry_strcat(bf, "xyz"); - EXPECT_TRUE(!bOk && !memcmp(bf, "abx\000", 4)); - - memcpy(bf, "ab\000d", 4); - bOk = cry_strcat(bf, "xyz", 4); - EXPECT_TRUE(!bOk && !memcmp(bf, "abx\000", 4)); - - memcpy(bf, "ab\000d", 4); - bOk = cry_strcat(bf, "xyz", 1); - EXPECT_TRUE(bOk && !memcmp(bf, "abx\000", 4)); - - memcpy(bf, "ab\000d", 4); - bOk = cry_strcat(bf, "xyz", 0); - EXPECT_TRUE(bOk && !memcmp(bf, "ab\000d", 4)); - - memcpy(bf, "ab\000d", 4); - bOk = cry_strcat(bf, 0, 0); - EXPECT_TRUE(!bOk && !memcmp(bf, "ab\000d", 4)); - - memcpy(bf, "ab\000d", 4); - bOk = cry_strcat(bf, 0, 1); - EXPECT_TRUE(!bOk && !memcmp(bf, "ab\000d", 4)); - - memcpy(bf, "a\000cd", 4); - bOk = cry_strcat(bf, sizeof(bf), "xy"); - EXPECT_TRUE(bOk && !memcmp(bf, "axy\000", 4)); - - memcpy(bf, "a\000cd", 4); - bOk = cry_strcat(bf, sizeof(bf), "xy", 3); - EXPECT_TRUE(bOk && !memcmp(bf, "axy\000", 4)); - - memcpy(bf, "a\000cd", 4); - bOk = cry_strcat(bf, sizeof(bf), "xy", 1); - EXPECT_TRUE(bOk && !memcmp(bf, "ax\000d", 4)); -} - -using CryPrimitivesAllocatorScope = AZ::AllocatorScope; - -class CryPrimitives - : public ::testing::Test -{ -public: - void SetUp() override - { - m_memory.ActivateAllocators(); - } - - void TearDown() override - { - m_memory.DeactivateAllocators(); - } - - CryPrimitivesAllocatorScope m_memory; -}; - -TEST_F(CryPrimitives, CUT_CryString) -{ - ////////////////////////////////////////////////////////////////////////// - // Based on MS documentation of find_last_of - string strTestFindLastOfOverload1("abcd-1234-abcd-1234"); - string strTestFindLastOfOverload2("ABCD-1234-ABCD-1234"); - string strTestFindLastOfOverload3("456-EFG-456-EFG"); - string strTestFindLastOfOverload4("12-ab-12-ab"); - - const char* cstr2 = "B1"; - const char* cstr2b = "D2"; - const char* cstr3a = "5E"; - string str4a("ba3"); - string str4b("a2"); - - size_t nPosition(string::npos); - - nPosition = strTestFindLastOfOverload1.find_last_of('d', 14); - EXPECT_TRUE(nPosition == 13); - - - nPosition = strTestFindLastOfOverload2.find_last_of(cstr2, 12); - EXPECT_TRUE(nPosition == 11); - - - nPosition = strTestFindLastOfOverload2.find_last_of(cstr2b); - EXPECT_TRUE(nPosition == 16); - - - nPosition = strTestFindLastOfOverload3.find_last_of(cstr3a, 8, 2); - EXPECT_TRUE(nPosition == 4); - - - nPosition = strTestFindLastOfOverload4.find_last_of(str4a, 8); - EXPECT_TRUE(nPosition == 4); - - - nPosition = strTestFindLastOfOverload4.find_last_of(str4b); - EXPECT_TRUE(nPosition == 9); - - ////////////////////////////////////////////////////////////////////////// - // Based on MS documentation of find_last_not_of - string strTestFindLastNotOfOverload1("dddd-1dd4-abdd"); - string strTestFindLastNotOfOverload2("BBB-1111"); - string strTestFindLastNotOfOverload3("444-555-GGG"); - string strTestFindLastNotOfOverload4("12-ab-12-ab"); - - const char* cstr2NF = "B1"; - const char* cstr3aNF = "45G"; - const char* cstr3bNF = "45G"; - - string str4aNF("b-a"); - string str4bNF("12"); - - nPosition = strTestFindLastNotOfOverload1.find_last_not_of('d', 7); - EXPECT_TRUE(nPosition == 5); - - nPosition = strTestFindLastNotOfOverload1.find_last_not_of("d"); - EXPECT_TRUE(nPosition == 11); - - nPosition = strTestFindLastNotOfOverload2.find_last_not_of(cstr2NF, 6); - EXPECT_TRUE(nPosition == 3); - - nPosition = strTestFindLastNotOfOverload3.find_last_not_of(cstr3aNF); - EXPECT_TRUE(nPosition == 7); - - nPosition = strTestFindLastNotOfOverload3.find_last_not_of(cstr3bNF, 6, 3);//nPosition - 1 ); - EXPECT_TRUE(nPosition == 3); - - nPosition = strTestFindLastNotOfOverload4.find_last_not_of(str4aNF, 5); - EXPECT_TRUE(nPosition == 1); - - nPosition = strTestFindLastNotOfOverload4.find_last_not_of(str4bNF); - EXPECT_TRUE(nPosition == 10); -} - - -TEST_F(CryPrimitives, CUT_FixedString) -{ - CryStackStringT str1; - CryStackStringT str2; - CryStackStringT str3; - CryStackStringT str4; - CryStackStringT str5; - CryStackStringT wstr1; - CryStackStringT wstr2; - CryFixedStringT<100> fixedString100; - CryFixedStringT<200> fixedString200; - - typedef CryStackStringT T; - T* pStr = new T; - *pStr = "adads"; - delete pStr; - - str1 = "abcd"; - EXPECT_EQ(str1, "abcd"); - - str2 = "efg"; - EXPECT_EQ(str2, "efg"); - - str2 = str1; - EXPECT_EQ(str2, "abcd"); - - str1 += "XY"; - EXPECT_EQ(str1, "abcdXY"); - - str2 += "efghijk"; - EXPECT_EQ(str2, "abcdefghijk"); - - str1.replace("bc", ""); - EXPECT_EQ(str1, "adXY"); - - str1.replace("XY", "1234"); - EXPECT_EQ(str1, "ad1234"); - - str1.replace("1234", "1234567890"); - EXPECT_EQ(str1, "ad1234567890"); - - str1.reserve(200); - EXPECT_EQ(str1, "ad1234567890"); - EXPECT_TRUE(str1.capacity() == 200); - - str1.reserve(0); - EXPECT_EQ(str1, "ad1234567890"); - EXPECT_TRUE(str1.capacity() == str1.length()); - - str1.erase(7); // doesn't change capacity - EXPECT_EQ(str1, "ad12345"); - - str4.assign("abc"); - EXPECT_EQ(str4, "abc"); - str4.reserve(9); - EXPECT_TRUE(str4.capacity() >= 9); // capacity is always >= MAX_SIZE-1 - str4.reserve(0); - EXPECT_TRUE(str4.capacity() >= 9); // capacity is always >= MAX_SIZE-1 - - size_t idx = str1.find("123"); - EXPECT_TRUE(idx == 2); - - idx = str1.find("123", 3); - EXPECT_TRUE(idx == str1.npos); - - wstr1 = L"abc"; - EXPECT_EQ(wstr1, L"abc"); - EXPECT_TRUE(wstr1.compare(L"aBc") > 0); - EXPECT_TRUE(wstr1.compare(L"babc") < 0); - EXPECT_TRUE(wstr1.compareNoCase(L"aBc") == 0); - - str1.Format("This is a %s %ls with %d params", "mixed", L"string", 3); - str2.Format("This is a %ls %s with %d params", L"mixed", "string", 3); - EXPECT_EQ(str1, "This is a mixed string with 3 params"); - EXPECT_EQ(str1, str2); - - wstr1.Format(L"This is a %ls %hs with %d params", L"mixed", "string", 3); - wstr2.Format(L"This is a %hs %ls with %d params", "mixed", L"string", 3); - EXPECT_EQ(wstr1, L"This is a mixed string with 3 params"); - - str5.FormatFast("%s", "12345"); - EXPECT_EQ("1234", str5); - - // we expect here that the string gets cut since it doesn't fit into the string buffer - str5.FormatFast("%s", "012345"); - EXPECT_EQ("0123", str5); -} - -TEST_F(CryPrimitives, CUT_DynArray) -{ - LegacyDynArray a; - a.push_back(3); - a.insert(&a[0], 1, 1); - a.insert(&a[1], 1, 2); - a.insert(&a[0], 1, 0); - - for (int i = 0; i < 4; i++) - { - EXPECT_TRUE(a[i] == i); - } - - const int nStrs = 11; - string Strs[nStrs] = { "nought", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" }; - LegacyDynArray s; - for (int i = 0; i < nStrs; i += 2) - { - s.push_back(Strs[i]); - } - for (int i = 1; i < nStrs; i += 2) - { - s.insert(i, Strs[i]); - } - for (int i = 0; i < nStrs; i++) - { - EXPECT_TRUE(s[i] == Strs[i]); - } - - LegacyDynArray s2 = s; - s.erase(5, 2); - EXPECT_TRUE(s.size() == nStrs - 2); - - s.insert(&s[3], &Strs[5], &Strs[8]); - - s2 = s2(3, 4); - EXPECT_TRUE(s2.size() == 4); -} diff --git a/Code/CryEngine/CrySystem/Tests/Test_Localization.cpp b/Code/CryEngine/CrySystem/Tests/Test_Localization.cpp deleted file mode 100644 index ad3972fffe..0000000000 --- a/Code/CryEngine/CrySystem/Tests/Test_Localization.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "CrySystem_precompiled.h" -#include -#include -#include "LocalizedStringManager.h" -#include -#include -#include -#include - -#include - -class SystemEventDispatcherMock - : public ISystemEventDispatcher -{ -public: - virtual ~SystemEventDispatcherMock() {} - MOCK_METHOD1(RegisterListener, bool(ISystemEventListener* pListener)); - MOCK_METHOD1(RemoveListener, bool(ISystemEventListener* pListener)); - MOCK_METHOD3(OnSystemEvent, void(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam)); - MOCK_METHOD0(Update, void()); -}; - -using namespace testing; -using ::testing::NiceMock; - -using SystemAllocatorScope = AZ::AllocatorScope; - -class SystemFixture - : public ::testing::Test - , public SystemAllocatorScope -{ -public: - SystemFixture() - { - EXPECT_CALL(m_system, GetISystemEventDispatcher()) - .WillRepeatedly(Return(&m_dispatcher)); - - EXPECT_CALL(m_console, GetCVar(_)) - .WillRepeatedly(Return(&m_cvarMock)); - - EXPECT_CALL(m_cryPak, FindFirst(_, _, _)) - .WillRepeatedly(Return(AZ::IO::ArchiveFileIterator{})); - - EXPECT_CALL(m_cryPak, GetLocalizationFolder()) - .WillRepeatedly(Return("french")); - - EXPECT_CALL(m_cvarMock, GetFlags()) - .WillRepeatedly(Return(VF_WASINCONFIG)); - } - - void SetUp() override - { - SystemAllocatorScope::ActivateAllocators(); - - memset(&m_stubEnv, 0, sizeof(SSystemGlobalEnvironment)); - m_stubEnv.pConsole = &m_console; - m_stubEnv.pSystem = &m_system; - m_stubEnv.pCryPak = &m_cryPak; - m_stubEnv.pLog = nullptr; - m_priorEnv = gEnv; - gEnv = &m_stubEnv; - } - - void TearDown() override - { - gEnv = m_priorEnv; - - SystemAllocatorScope::DeactivateAllocators(); - } - - NiceMock m_system; - NiceMock m_dispatcher; - NiceMock m_console; - NiceMock m_cryPak; - NiceMock m_cvarMock; - SSystemGlobalEnvironment m_stubEnv; - SSystemGlobalEnvironment* m_priorEnv = nullptr; -}; - -class UnitTestCLocalizedStringsManager : public CLocalizedStringsManager -{ -public: - UnitTestCLocalizedStringsManager(ISystem* pSystem) : CLocalizedStringsManager(pSystem) - { - } - - bool LocalizeLabel(const char* sLabel, string& outLocalizedString, bool bEnglish = false) override - { - m_capturedLabels.push_back(sLabel); - return CLocalizedStringsManager::LocalizeLabel(sLabel, outLocalizedString, bEnglish); - } - - std::vector m_capturedLabels; - - friend class GTEST_TEST_CLASS_NAME_(SystemFixture, LocalizeStringInternal_WhitespaceCharacters_CorrectlyTokenizes); -}; - -// this test makes sure that whitespace characters such as tab work (not just space) and are considered to be separators. -TEST_F(SystemFixture, LocalizeStringInternal_SpecificWhitespaceCharacters_CorrectlyTokenizes) -{ - UnitTestCLocalizedStringsManager manager(&m_system); - manager.SetLanguage("french"); - - string outString; - manager.LocalizeString_s("@hello\t@world", outString, false); - ASSERT_EQ(manager.m_capturedLabels.size(), 2); - EXPECT_STREQ(manager.m_capturedLabels[0].c_str(), "@hello"); - EXPECT_STREQ(manager.m_capturedLabels[1].c_str(), "@world"); - manager.m_capturedLabels.clear(); - - manager.LocalizeString_s("@hello\n@world", outString, false); - ASSERT_EQ(manager.m_capturedLabels.size(), 2); - EXPECT_STREQ(manager.m_capturedLabels[0].c_str(), "@hello"); - EXPECT_STREQ(manager.m_capturedLabels[1].c_str(), "@world"); - manager.m_capturedLabels.clear(); - - manager.LocalizeString_s("@hello\r@world", outString, false); - ASSERT_EQ(manager.m_capturedLabels.size(), 2); - EXPECT_STREQ(manager.m_capturedLabels[0].c_str(), "@hello"); - EXPECT_STREQ(manager.m_capturedLabels[1].c_str(), "@world"); - manager.m_capturedLabels.clear(); - - manager.LocalizeString_s("@hello @world", outString, false); - ASSERT_EQ(manager.m_capturedLabels.size(), 2); - EXPECT_STREQ(manager.m_capturedLabels[0].c_str(), "@hello"); - EXPECT_STREQ(manager.m_capturedLabels[1].c_str(), "@world"); - manager.m_capturedLabels.clear(); -} - - -// this test makes sure that multiple whitespace characters in a row don't themselves count as tokens or change the output in undesirable ways. -TEST_F(SystemFixture, LocalizeStringInternal_ManyWhitespaceCharacters_CorrectlyTokenizes) -{ - UnitTestCLocalizedStringsManager manager(&m_system); - manager.SetLanguage("french"); - - string outString; - const char* testString = "@hello\n\r\t \t\r\n@world\n\r\t "; - manager.LocalizeString_ch(testString, outString, false); - ASSERT_EQ(manager.m_capturedLabels.size(), 2); - EXPECT_STREQ(manager.m_capturedLabels[0].c_str(), "@hello"); - EXPECT_STREQ(manager.m_capturedLabels[1].c_str(), "@world"); - - // since there are no localizations available it should not have gobbled up whitespace or altered it. - EXPECT_STREQ(outString, testString); -} diff --git a/Code/CryEngine/CrySystem/Tests/test_CrySystem.cpp b/Code/CryEngine/CrySystem/Tests/test_CrySystem.cpp deleted file mode 100644 index 637682065f..0000000000 --- a/Code/CryEngine/CrySystem/Tests/test_CrySystem.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "CrySystem_precompiled.h" -#include -#include -#include -#include -#include -#include - -namespace UnitTests -{ - class CSystemUnitTests - : public ::testing::Test - { - public: - void SetUp() override - { - IMemoryManager* cryMemoryManager = nullptr; - CryGetIMemoryManagerInterface((void**)&cryMemoryManager); - AZ_Assert(cryMemoryManager, "Unable to resolve CryMemoryManager"); - m_cryMemoryManager = AZ::Environment::CreateVariable("CryIMemoryManagerInterface", cryMemoryManager); - SSystemInitParams startupParams; - AZ::AllocatorInstance::Create(); - AZ::AllocatorInstance::Create(); - m_system = new CSystem(startupParams.pSharedEnvironment); - } - - void TearDown() override - { - delete m_system; - AZ::AllocatorInstance::Destroy(); - AZ::AllocatorInstance::Destroy(); - } - - - CSystem* m_system = nullptr; - AZ::EnvironmentVariable m_cryMemoryManager; - - }; - - TEST_F(CSystemUnitTests, ApplicationLogInstanceUnitTests) - { - const char dummyString[] = "dummy"; - const char testString[] = "test"; - EXPECT_EQ(m_system->GetApplicationLogInstance(dummyString), 0); - EXPECT_EQ(m_system->GetApplicationLogInstance(testString), 0); -#if AZ_TRAIT_OS_USE_WINDOWS_MUTEX - EXPECT_EQ(m_system->GetApplicationLogInstance(dummyString), 1); -#endif - } -} diff --git a/Code/CryEngine/CrySystem/Tests/test_Main.cpp b/Code/CryEngine/CrySystem/Tests/test_Main.cpp deleted file mode 100644 index 5ae78cabbf..0000000000 --- a/Code/CryEngine/CrySystem/Tests/test_Main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "CrySystem_precompiled.h" -#include -#include -#include -#include - -class CrySystemTestEnvironment - : public AZ::Test::ITestEnvironment - , public ::UnitTest::TraceBusRedirector -{ -public: - virtual ~CrySystemTestEnvironment() - {} - -protected: - void SetupEnvironment() override - { - AZ::AllocatorInstance::Create(); - AZ::AllocatorInstance::Create(); - - ::UnitTest::TraceBusRedirector::BusConnect(); - } - - void TeardownEnvironment() override - { - ::UnitTest::TraceBusRedirector::BusDisconnect(); - AZ::AllocatorInstance::Destroy(); - AZ::AllocatorInstance::Destroy(); - } -}; - -AZ_UNIT_TEST_HOOK(new CrySystemTestEnvironment) diff --git a/Code/CryEngine/CrySystem/Tests/test_MaterialUtils.cpp b/Code/CryEngine/CrySystem/Tests/test_MaterialUtils.cpp deleted file mode 100644 index 99077e41e8..0000000000 --- a/Code/CryEngine/CrySystem/Tests/test_MaterialUtils.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -#include "CrySystem_precompiled.h" -#include - -#include -#include -#include "MaterialUtils.h" - -#include - - -TEST(CrySystemMaterialUtilsTests, MaterialUtilsTestBasics) -{ - char tempBuffer[AZ_MAX_PATH_LEN] = { 0 }; - // call to ensure that it handles nullptr without crashing - MaterialUtils::UnifyMaterialName(nullptr); - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(tempBuffer[0] == 0); -} - -TEST(CrySystemMaterialUtilsTests, MaterialUtilsTestExtensions) -{ - char tempBuffer[AZ_MAX_PATH_LEN]; - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, "blahblah.mtl"); - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(strcmp(tempBuffer, "blahblah") == 0); - - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, "blahblah.mat.mat.abc.test.mtl"); - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(strcmp(tempBuffer, "blahblah.mat.mat.abc.test") == 0); - - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, "test/.mat.mat/blahblah.mat.mat.abc.test.mtl"); - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(strcmp(tempBuffer, "test/.mat.mat/blahblah.mat.mat.abc.test") == 0); - - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, ".mat.mat.blahblah.mat.mat.abc.test.mtl"); - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(strcmp(tempBuffer, ".mat.mat.blahblah.mat.mat.abc.test") == 0); -} - -TEST(CrySystemMaterialUtilsTests, MaterialUtilsTestPrefixes) -{ - char tempBuffer[AZ_MAX_PATH_LEN]; - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, ".\\blahblah.mat"); - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(strcmp(tempBuffer, "blahblah") == 0); - - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, "./materials/blahblah.mat.mat.abc.test"); - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(strcmp(tempBuffer, "materials/blahblah.mat.mat.abc") == 0); - - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, ".\\engine\\materials\\blahblah.mat.mat.abc.test"); - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(strcmp(tempBuffer, "materials/blahblah.mat.mat.abc") == 0); - - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, "engine/materials/blahblah.mat.mat.abc.test"); - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(strcmp(tempBuffer, "materials/blahblah.mat.mat.abc") == 0); - - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, "materials/blahblah.mat"); - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(strcmp(tempBuffer, "materials/blahblah") == 0); -} - -TEST(CrySystemMaterialUtilsTests, MaterialUtilsTestGameName) -{ - char tempBuffer[AZ_MAX_PATH_LEN]; - - auto projectName = AZ::Utils::GetProjectName(); - azsnprintf(tempBuffer, AZ_MAX_PATH_LEN, ".\\%s\\materials\\blahblah.mat.mat.abc.test", projectName.c_str()); - - MaterialUtils::UnifyMaterialName(tempBuffer); - EXPECT_TRUE(strcmp(tempBuffer, "materials/blahblah.mat.mat.abc") == 0); -} diff --git a/Code/CryEngine/CrySystem/Timer.h b/Code/CryEngine/CrySystem/Timer.h index 8778405067..33cfbd6087 100644 --- a/Code/CryEngine/CrySystem/Timer.h +++ b/Code/CryEngine/CrySystem/Timer.h @@ -31,7 +31,7 @@ public: // interface ITimer ---------------------------------------------------------- - // TODO: Review m_time usage in System.cpp / SystemRender.cpp + // TODO: Review m_time usage in System.cpp // if it wants Game Time / UI Time or a new Render Time? virtual void ResetTimer(); diff --git a/Code/CryEngine/CrySystem/UnixConsole.cpp b/Code/CryEngine/CrySystem/UnixConsole.cpp deleted file mode 100644 index 5ec186b8b8..0000000000 --- a/Code/CryEngine/CrySystem/UnixConsole.cpp +++ /dev/null @@ -1,2518 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Console implementation for UNIX systems based on curses ncurses - - -#include "CrySystem_precompiled.h" -#include "System.h" -#include "UnixConsole.h" - -#if defined(USE_DEDICATED_SERVER_CONSOLE) - -#if defined(USE_UNIXCONSOLE) - -#if !defined(WIN32) -#include -#include -#include -#include -#if defined(MAC) -#include -#include -#else -#include -#endif // defined(MAC) -#if defined(LINUX) || defined(MAC) - #include -#endif -#endif -#include - -#define UNIXConsole_MORE_LEFT "<<" -#define UNIXConsole_MORE_RIGHT ">>" -#define UNIXConsole_MORE_COLOR (3) // Colorpair index -#define UNIXConsole_PROMPT "] " -#define UNIXConsole_PROMPT_COLOR (2) // Colorpair index -#define UNIXConsole_WRAP_CHAR '\\' -#define UNIXConsole_WRAP_COLOR (4) -#define UNIXConsole_MIN_WIDTH (10) -#define UNIXConsole_MAX_LINES (1000) -#define UNIXConsole_MAX_HISTORY (100) - -#if defined(LINUX) || defined(MAC) -// Should find a better test for ncurses... -#define NCURSES 1 -#endif - -#if defined(WIN32) -#define snprintf _snprintf -#endif - -// macro which check if we should process console function -// used for disable console on Linux -#define IS_SHOW_CONSOLE if (!m_bShowConsole) {return; } -#define IS_SHOW_CONSOLE_RET(ret) if (!m_bShowConsole) {return ret; } - - -CryCriticalSectionNonRecursive CUNIXConsole::m_cleanupLock; - -class CUNIXConsoleInputThread - : public CrySimpleThread<> -{ - CUNIXConsole& m_UNIXConsole; -#if !defined(WIN32) - int m_IntrPipe[2]; -#else - HANDLE m_IntrEvent; -#endif - bool m_Cancelled; - -public: - CUNIXConsoleInputThread(CUNIXConsole& UNIXConsole) - : m_UNIXConsole(UNIXConsole) - , m_Cancelled(false) - { -#if !defined(WIN32) - pipe(m_IntrPipe); -#else - m_IntrEvent = CreateEvent(NULL, true, false, NULL); -#endif - } - - ~CUNIXConsoleInputThread() - { -#if !defined(WIN32) - close(m_IntrPipe[0]); - close(m_IntrPipe[1]); -#else - CloseHandle(m_IntrEvent); -#endif - } - - virtual void Run(); - virtual void Cancel() { m_Cancelled = true; Interrupt(); } - void Interrupt() - { -#if !defined(WIN32) - write(m_IntrPipe[1], "", 1); -#else - SetEvent(m_IntrEvent); -#endif - } -}; - -class CUNIXConsoleSignalHandler -{ - friend class CUNIXConsole; - - static CUNIXConsole* m_pUNIXConsole; - static void Handler(int signum); -}; - -CUNIXConsole::CUNIXConsole() - : m_HistoryIndex(-1) - , m_PromptResponse(0) - , m_pSystem(NULL) - , m_pConsole(NULL) - , m_pTimer(NULL) - , m_OnUpdateCalled(false) - , m_LastUpdateTime(0.0f) - , m_svMap(NULL) - , m_svGameRules(NULL) - , m_Width(~0) - , m_Height(~0) - , m_HeaderHeight(1) - , m_StatusHeight(1) - , m_CmdHeight(2) - , m_Color(DEFAULT_COLOR) - , m_DefaultColorPair(-1) - , m_EnableColor(true) - , m_WindowResized(false) - , m_OnShutdownCalled(false) - , m_Initialized(false) - , m_RequireDedicatedServer(false) - , m_ScrollUp(0) - , m_InputThread(NULL) - , m_CursorPosition(0) - , m_ScrollPosition(0) - , m_fsMode(false) - , m_bShowConsole(true) -{ -} - -CUNIXConsole::~CUNIXConsole() -{ - Cleanup(); - m_Lock.Lock(); -} - -void CUNIXConsole::SetRequireDedicatedServer(bool value) -{ - assert(!m_Initialized); - m_RequireDedicatedServer = value; -} - -#if defined(WIN32) || defined(WIN64) -void ResizeConBufAndWindow(HANDLE hConsole, SHORT xSize, SHORT ySize) -{ - CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */ - BOOL bSuccess; - SMALL_RECT srWindowRect; /* hold the new console size */ - COORD coordScreen; - - bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi); - /* get the largest size we can size the console window to */ - coordScreen = GetLargestConsoleWindowSize(hConsole); - /* define the new console window size and scroll position */ - srWindowRect.Right = (SHORT) (min(xSize, coordScreen.X) - 1); - srWindowRect.Bottom = (SHORT) (min(ySize, coordScreen.Y) - 1); - srWindowRect.Left = srWindowRect.Top = (SHORT) 0; - /* define the new console buffer size */ - coordScreen.X = xSize; - coordScreen.Y = ySize; - /* if the current buffer is larger than what we want, resize the */ - /* console window first, then the buffer */ - if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y > (DWORD) xSize * ySize) - { - bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect); - bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen); - bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect); - bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen); - } - /* if the current buffer is smaller than what we want, resize the */ - /* buffer first, then the console window */ - if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y < (DWORD) xSize * ySize) - { - bSuccess = SetConsoleScreenBufferSize(hConsole, coordScreen); - bSuccess = SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect); - } - /* if the current buffer *is* the size we want, don't do anything! */ - return; -} - -BOOL WINAPI CtrlHandler(DWORD evt) -{ - switch (evt) - { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - return TRUE; - case CTRL_CLOSE_EVENT: - gEnv->pSystem->Quit(); - return TRUE; - } - return FALSE; -} -#endif - -void CUNIXConsole::Init(const char* headerString) -{ - assert(!m_Initialized); - - if (headerString != NULL) - { - m_HeaderString = headerString; - } - -#if defined(WIN32) || defined(WIN64) - // Allocate a console for the process. We don't care if this is successful - // or not, because failure indicates that the process already has a - // console, which is fine. - AllocConsole(); - HANDLE hConsOut = GetStdHandle(STD_OUTPUT_HANDLE); - ResizeConBufAndWindow(hConsOut, 120, 60); - SetConsoleCtrlHandler(CtrlHandler, TRUE); -#endif - - // Initialize curses. - initscr(); - cbreak(); - noecho(); - nonl(); - intrflush(stdscr, FALSE); - keypad(stdscr, TRUE); - scrollok(stdscr, TRUE); - idcok(stdscr, TRUE); - idlok(stdscr, TRUE); - nodelay(stdscr, TRUE); - - // Enable color output. - if (m_EnableColor) - { - if (start_color() != OK) - { - m_EnableColor = false; - } - } - - if (m_EnableColor) - { -#if defined(NCURSES) - // Setup the color table. - short colorPair = 0; - attr_t attr; - attr_get(&attr, &colorPair, NULL); - m_DefaultColorPair = colorPair; - m_ColorPair[0] = m_DefaultColorPair; - m_ColorPair[1] = m_DefaultColorPair; - short color_fg = 0, color_bg = 0; - pair_content(m_DefaultColorPair, &color_fg, &color_bg); - short pair = 0; - init_pair(++pair, COLOR_BLUE, color_bg); - m_ColorPair[2] = pair; - init_pair(++pair, COLOR_GREEN, color_bg); - m_ColorPair[3] = pair; - init_pair(++pair, COLOR_RED, color_bg); - m_ColorPair[4] = pair; - init_pair(++pair, COLOR_CYAN, color_bg); - m_ColorPair[5] = pair; - init_pair(++pair, COLOR_YELLOW, COLOR_BLACK); - m_ColorPair[6] = pair; - init_pair(++pair, COLOR_MAGENTA, color_bg); - m_ColorPair[7] = pair; - init_pair(++pair, COLOR_RED, color_bg); - m_ColorPair[8] = pair; - init_pair(++pair, COLOR_BLACK, COLOR_WHITE); - m_ColorPair[9] = pair; -#else - // Color output supported only for ncurses. - m_EnableColor = false; - m_DefaultColorPair = 0; -#endif - } - else - { - m_DefaultColorPair = 0; - } - - // Set the screen size and draw the initial screen. - SetSize(COLS, LINES); - - m_syslogStats.Init(); - - m_Initialized = true; -} - -void CUNIXConsole::Cleanup() -{ - m_cleanupLock.Lock(); - if (m_Initialized) - { - // Kill the input thread. - if (m_InputThread != NULL) - { - m_InputThread->Cancel(); - m_InputThread->WaitForThread(); - delete m_InputThread; - m_InputThread = NULL; - } - - // Curses cleanup. - clear(); - endwin(); - - m_Initialized = false; - } - m_cleanupLock.Unlock(); -} - -void CUNIXConsole::SetSize(unsigned width, unsigned height) -{ - bool repaint = false; - - assert(IsLocked()); - if (width != m_Width) - { - m_Width = width; - FixCursorPosition(); - repaint = true; - } - if (height != m_Height) - { - m_Height = height; - repaint = true; - } - if (repaint) - { - Repaint(); - } -} - -bool CUNIXConsole::IsTooSmall() -{ - assert(IsLocked()); - if (m_Height < m_HeaderHeight + m_StatusHeight + m_CmdHeight + 1) - { - return true; - } - if (m_Width < UNIXConsole_MIN_WIDTH) - { - return true; - } - return false; -} - -void CUNIXConsole::CheckResize() -{ - assert(IsLocked()); -#if defined(NCURSES) - int lines, cols; - - IS_SHOW_CONSOLE - - if (m_WindowResized) - { - m_WindowResized = false; - // Get the new window size from the terminal driver. - winsize ws; - memset(&ws, 0, sizeof ws); - ioctl(1, TIOCGWINSZ, &ws); - lines = ws.ws_row; - cols = ws.ws_col; - if (m_Width != lines || m_Height != cols) - { - resizeterm(lines, cols); - SetSize(cols, lines); - Repaint(); - } - } -#endif -} - -void CUNIXConsole::NewLine() -{ - char lineBuf[3] = "\1X"; - bool doScroll = !m_LineBuffer.empty(); - - assert(IsLocked()); - lineBuf[1] = m_Color + '0'; - - if (m_LineBuffer.size() == UNIXConsole_MAX_LINES) - { - m_LineBuffer.pop_front(); - } - m_LineBuffer.push_back(lineBuf); - - if (doScroll) - { - ScrollLog(); - } - else - { - unsigned row = m_Height - m_CmdHeight - m_StatusHeight - 1; - move(row, 0); - } - if (m_ScrollUp > 0) - { - const string& lastDisplayLine - = m_LineBuffer[m_LineBuffer.size() - m_ScrollUp - 1]; - DrawLogLine(lastDisplayLine); - } -} - -void CUNIXConsole::ContinueLine() -{ - IS_SHOW_CONSOLE - - if (m_LineBuffer.empty()) - { - NewLine(); - return; - } - const string& lastLine = *m_LineBuffer.rbegin(); - unsigned column = DrawLogLine(lastLine, true /* noOutput */); - SetColorRaw(m_Color); - const unsigned row = m_Height - m_CmdHeight - m_StatusHeight - 1; - move(row, column); -} - -void CUNIXConsole::SetColor(int color) -{ - assert(IsLocked()); - m_Color = color; - SetColorRaw(color); - if (m_LineBuffer.empty()) - { - m_LineBuffer.push_back(""); - } - const TLineBuffer::const_reverse_iterator it = m_LineBuffer.rbegin(); - string& lastLine = const_cast(*it); - lastLine.push_back(1); - lastLine.push_back('0' + color); -} - -void CUNIXConsole::SetColorRaw(int color) -{ - attr_t colorAttr = 0; - - assert(IsLocked()); - if (color == DEFAULT_COLOR) - { - color = 0; - } - if (m_EnableColor) - { - colorAttr = COLOR_PAIR(m_ColorPair[color]); - } - switch (color) - { - case 0: - attrset(A_NORMAL | colorAttr); - break; - case 1: - attrset(A_REVERSE | colorAttr); - break; - case 2: - case 3: - attrset(A_NORMAL | colorAttr); - break; - case 4: - attrset(A_BOLD | colorAttr); - break; - case 5: - attrset(A_NORMAL | colorAttr); - break; - case 6: - attrset(A_BOLD | colorAttr); - break; - case 7: - case 8: - case 9: - attrset(A_NORMAL | colorAttr); - break; - default: - abort(); - } -} - -void CUNIXConsole::Put(int c) -{ - assert(IsLocked()); - - // Get the last buffer line. - if (m_LineBuffer.empty()) - { - NewLine(); - } - const TLineBuffer::const_reverse_iterator it = m_LineBuffer.rbegin(); - string& lastLine = const_cast(*it); - assert(c >= 0x20); - - // Wrap the line if required. - unsigned row = m_Height - m_CmdHeight - m_StatusHeight - 1; - unsigned column = 0; - GetLineHeight(lastLine, &column); - assert(column <= m_Width); - lastLine.push_back(char(c)); - - if (m_ScrollUp == 0) - { - // Output the line wrap character. - if (column == m_Width - 1) - { - move(row, m_Width - 1); - attr_t colorAttr = 0; - if (m_EnableColor) - { - colorAttr = COLOR_PAIR(UNIXConsole_WRAP_COLOR); - } - attrset(A_NORMAL | colorAttr); - addch(UNIXConsole_WRAP_CHAR); - ScrollLog(); - move(row, 0); - } - - // Output the character. - SetColorRaw(m_Color); - addch(c); - } -} - -void CUNIXConsole::Put(const char* s) -{ - assert(IsLocked()); - while (*s) - { - if (*s == '\n') - { - NewLine(); - } - else - { - Put(*s); - } - ++s; - } -} - -unsigned CUNIXConsole::GetLineLength(const string& line) -{ - unsigned length = 0; - - for (string::const_iterator it = line.begin(), itEnd = line.end(); - it != itEnd; - ++it) - { - char c = *it; - if (c == 1) - { - ++it; - assert(it != itEnd); - continue; - } - ++length; - } - return length; -} - -char CUNIXConsole::GetLastCharacter(const string& line, int* color) -{ - char c0 = 0, c1 = 0; - char lastChar = 0; - - if (!line.empty()) - { - for (int i = line.size() - 1; i >= 0; i--) - { - c1 = c0; - c0 = line[i]; - if (c0 == 1) - { - assert(lastChar); - if (color) - { - *color = c1 - '0'; - } - return lastChar; - } - else if (c0 && c1 != 1 && !lastChar) - { - lastChar = c0; - } - } - } - - *color = DEFAULT_COLOR; - if (lastChar) - { - return lastChar; - } - assert(c0 && c0 != 1); - return c0; -} - -unsigned CUNIXConsole::GetLineHeight(const string& line, unsigned* column) -{ - unsigned lineLength = GetLineLength(line); - unsigned height = 1; - - assert(IsLocked()); - while (lineLength > m_Width) - { - lineLength -= m_Width - 1; - ++height; - } - if (column != NULL) - { - *column = lineLength; - } - return height; -} - -void CUNIXConsole::ScrollLog() -{ - if (m_fsMode) - { - return; - } - - // Scroll the log window. We'll do that by defining a software scrolling - // region. The constructor has set scrollok() and idlok(), so the output - // routing will use the hardware scrolling region (if available). - unsigned top = m_HeaderHeight; - unsigned bottom = m_Height - m_CmdHeight - m_StatusHeight; - - assert(IsLocked()); - // Some curses implementations (pdcurses) require the current position to - // be within the defined scrolling region. - move(top, 0); - if (setscrreg(top, bottom) == OK) - { - move(bottom, 0); - addch('\n'); - setscrreg(0, m_Height - 1); - DrawStatus(1); - } - else - { - // Scrolling regions not supported. We'll scroll the entire window and - // the repaint everything except for the log window. - scroll(stdscr); - move(bottom - 1, 0); - attrset(A_NORMAL); - clrtobot(); - DrawHeader(); - DrawStatus(); - DrawCmd(); - } - move(bottom - 1, 0); -} - -bool CUNIXConsole::FixCursorPosition() -{ - IS_SHOW_CONSOLE_RET(false) - - bool repaint = false; - - assert(IsLocked()); - - // Clip the cursor position. - if (m_CursorPosition > (int)m_InputLine.size()) - { - m_CursorPosition = m_InputLine.size(); - } - - // Trivial scroll position fixes. - if (m_CursorPosition < (int)m_Width / 2 && m_ScrollPosition > 0) - { - m_ScrollPosition = 0; - repaint = true; - } - else if (m_CursorPosition < m_ScrollPosition) - { - m_ScrollPosition = m_CursorPosition - m_Width / 4; - repaint = true; - } - - assert(m_ScrollPosition <= m_CursorPosition); - // The method may be called after the cursor has been moved to the - // right, so we may have to scroll the input line. - int displayLenth = m_Width * m_CmdHeight; - displayLenth -= strlen(UNIXConsole_PROMPT); - // If the cursor is at the end of the input line, then we only must leave - // one space for the cursor itself, otherwise we must leave space for the - // right scroll indicator. - if (m_CursorPosition == m_InputLine.size()) - { - displayLenth -= 1; - } - else - { - displayLenth -= strlen(UNIXConsole_MORE_RIGHT); - } - if (m_ScrollPosition < m_CursorPosition - displayLenth) - { - m_ScrollPosition = m_CursorPosition - displayLenth; - repaint = true; - } - - return repaint; -} - -void CUNIXConsole::OnEdit() -{ - assert(IsLocked()); - m_SavedInputLine.clear(); - m_HistoryIndex = -1; - if (m_pConsole != NULL) - { - m_pConsole->ResetAutoCompletion(); - } -} - -void CUNIXConsole::KeyEnter() -{ - bool redrawAll = false; - bool pushCommand = false; - - assert(IsLocked()); - - // Scroll the log window to the bottom. - if (m_ScrollUp > 0) - { - m_ScrollUp = 0; - redrawAll = true; - } - - // Process the input line. - while (!m_InputLine.empty() && m_InputLine[0] == '\\') - { - m_InputLine.erase(0, 1); - } - if (!m_InputLine.empty()) - { - pushCommand = true; - -#if defined(UC_ENABLE_MAGIC_COMMANDS) - // Enable some magic commands intercepted by the console. All magic - // commands start with an '@' character. - { - const char* const command = m_InputLine.c_str(); - if (!azstricmp(command, "@quit")) - { - // We're called from the input thread, hence we can't join it. We - // have to prevent Cleanup() (called via atexit()) from trying to - // join. - CUNIXConsoleInputThread* inputThread = m_InputThread; - m_InputThread = NULL; - Unlock(); - if (m_pSystem != NULL) - { - m_pSystem->Quit(); - inputThread->Exit(); - } - exit(0); - // Not reached. - abort(); - } - // Add other magic commands here. - } -#endif - } - - if (pushCommand) - { - { - m_CommandQueue.push_back(m_InputLine); - } - } - - if (!m_InputLine.empty()) - { - m_CommandHistory.push_back(m_InputLine); - while (m_CommandHistory.size() > UNIXConsole_MAX_HISTORY) - { - m_CommandHistory.pop_front(); - } - m_HistoryIndex = -1; - m_InputLine.clear(); - m_SavedInputLine.clear(); - m_CursorPosition = 0; - m_ScrollPosition = 0; - if (!redrawAll) - { - DrawCmd(); - refresh(); - } - } - - if (redrawAll) - { - Repaint(); - } -} -void CUNIXConsole::KeyUp() -{ - const int historySize = m_CommandHistory.size(); - - assert(IsLocked()); - if (m_HistoryIndex < historySize - 1) - { - if (m_HistoryIndex == -1) - { - m_SavedInputLine = m_InputLine; - } - m_HistoryIndex += 1; - m_InputLine = m_CommandHistory[historySize - m_HistoryIndex - 1]; - m_CursorPosition = m_InputLine.size(); - FixCursorPosition(); - DrawCmd(); - refresh(); - } -} - -void CUNIXConsole::KeyDown() -{ - const int historySize = m_CommandHistory.size(); - - assert(IsLocked()); - if (m_HistoryIndex > -1) - { - m_HistoryIndex -= 1; - if (m_HistoryIndex == -1) - { - m_InputLine = m_SavedInputLine; - m_SavedInputLine.clear(); - } - else - { - m_InputLine = m_CommandHistory[historySize - m_HistoryIndex - 1]; - } - m_CursorPosition = m_InputLine.size(); - FixCursorPosition(); - DrawCmd(); - refresh(); - } -} - -void CUNIXConsole::KeyLeft() -{ - assert(IsLocked()); - if (m_CursorPosition > 0) - { - m_CursorPosition -= 1; - DrawCmd(!FixCursorPosition()); - } -} - -void CUNIXConsole::KeyRight() -{ - assert(IsLocked()); - if (m_CursorPosition < (int)m_InputLine.size()) - { - m_CursorPosition += 1; - DrawCmd(!FixCursorPosition()); - } -} - -void CUNIXConsole::KeyHome(bool ctrl) -{ - assert(IsLocked()); - if (ctrl) - { - const int logHeight = GetLogHeight(); - int maxUp = m_LineBuffer.size() - logHeight; - if (m_ScrollUp != maxUp) - { - m_ScrollUp = maxUp; - Repaint(); - } - } - else if (m_CursorPosition != 0) - { - m_CursorPosition = 0; - DrawCmd(!FixCursorPosition()); - } -} - -void CUNIXConsole::KeyEnd(bool ctrl) -{ - assert(IsLocked()); - if (ctrl) - { - const int logHeight = GetLogHeight(); - int maxUp = m_LineBuffer.size() - logHeight; - if (m_ScrollUp != 0) - { - m_ScrollUp = 0; - Repaint(); - } - } - else if (m_CursorPosition < (int)m_InputLine.size()) - { - m_CursorPosition = m_InputLine.size(); - DrawCmd(!FixCursorPosition()); - } -} - -void CUNIXConsole::KeyBackspace() -{ - assert(IsLocked()); - if (m_CursorPosition > 0) - { - m_InputLine.erase(m_CursorPosition - 1, 1); - m_CursorPosition -= 1; - FixCursorPosition(); - OnEdit(); - DrawCmd(); - } -} - -void CUNIXConsole::KeyDelete() -{ - assert(IsLocked()); - if (m_CursorPosition < (int)m_InputLine.size()) - { - m_InputLine.erase(m_CursorPosition, 1); - FixCursorPosition(); - OnEdit(); - DrawCmd(); - } -} - -void CUNIXConsole::KeyDeleteWord() -{ - assert(IsLocked()); - if (m_CursorPosition > 0) - { - const char* const inputLine = m_InputLine.c_str(); - const char* p = inputLine + m_CursorPosition - 1; - - while (p > inputLine && *p == ' ') - { - --p; - } - while (p > inputLine && *p != ' ') - { - --p; - } - m_InputLine.erase(p - inputLine, m_CursorPosition); - m_CursorPosition = (uint32)(p - inputLine); - FixCursorPosition(); - OnEdit(); - DrawCmd(); - - /* Old std::string based code, kept for reference. - size_t wordIndex; - wordIndex = m_InputLine.find_last_of(" ", m_CursorPosition - 1); - if (wordIndex != string::npos) - { - wordIndex = m_InputLine.find_last_not_of(" ", wordIndex); - if (wordIndex != string::npos) - wordIndex += 1; - } - if (wordIndex == string::npos) - { - m_InputLine.erase(0, m_CursorPosition); - m_CursorPosition = 0; - } - else - { - m_InputLine.erase(wordIndex, m_CursorPosition - wordIndex); - m_CursorPosition = wordIndex; - } - FixCursorPosition(); - OnEdit(); - DrawCmd(); - */ - } -} - -void CUNIXConsole::KeyKill() -{ - assert(IsLocked()); - if (m_CursorPosition < (int)m_InputLine.size()) - { - m_InputLine.resize(m_CursorPosition); - FixCursorPosition(); - OnEdit(); - DrawCmd(); - } -} - -void CUNIXConsole::KeyRepaint() -{ - assert(IsLocked()); - Repaint(); -} - -void CUNIXConsole::KeyTab() -{ - const char* result; - - assert(IsLocked()); - if (m_OnShutdownCalled) - { - return; - } - string Tmp(m_InputLine); - Unlock(); - result = m_pConsole->ProcessCompletion(Tmp.c_str()); - Lock(); - if (result != NULL) - { - if (result[0] == '\\') - { - ++result; - } - m_InputLine = result; - m_CursorPosition = m_InputLine.size(); - FixCursorPosition(); - m_SavedInputLine.clear(); - m_HistoryIndex = -1; - DrawCmd(); - refresh(); - } -} - -void CUNIXConsole::KeyPgUp(bool ctrl) -{ - const int logHeight = GetLogHeight(); - // int logStep = logHeight - 2; - int logStep = ctrl ? 10 : 1; - int maxUp = m_LineBuffer.size() - logHeight; - int prevScrollUp = m_ScrollUp; - - assert(IsLocked()); - if (logStep < 1) - { - logStep = 1; - } - if (maxUp < 0) - { - maxUp = 0; - } - m_ScrollUp += logStep; - if (m_ScrollUp > maxUp) - { - m_ScrollUp = maxUp; - } - if (m_ScrollUp != prevScrollUp) - { - Repaint(); - } -} - -void CUNIXConsole::KeyPgDown(bool ctrl) -{ - const int logHeight = GetLogHeight(); - // int logStep = logHeight - 2; - int logStep = ctrl ? 10 : 1; - int prevScrollUp = m_ScrollUp; - - assert(IsLocked()); - if (logStep < 1) - { - logStep = 1; - } - if (m_ScrollUp > 0) - { - m_ScrollUp -= logStep; - } - if (m_ScrollUp < 0) - { - m_ScrollUp = 0; - } - if (m_ScrollUp != prevScrollUp) - { - Repaint(); - } -} - -void CUNIXConsole::Key(int c) -{ - assert(IsLocked()); - assert(c >= 0x20 && c <= 0xff); - assert(m_CursorPosition <= (int)m_InputLine.size()); - m_InputLine.insert(m_CursorPosition, 1, (char)c); - m_CursorPosition += 1; - FixCursorPosition(); - OnEdit(); - DrawCmd(); - refresh(); -} - -void CUNIXConsole::Repaint() -{ - IS_SHOW_CONSOLE - - assert(IsLocked()); - clear(); - DrawHeader(); - if (m_fsMode) - { - DrawFullscreen(); - } - else - { - DrawLog(); - } - DrawStatus(); - DrawCmd(); - refresh(); -} - -void CUNIXConsole::Flush() -{ - IS_SHOW_CONSOLE - - assert(IsLocked()); - refresh(); -} - -void CUNIXConsole::InputIdle() -{ - IS_SHOW_CONSOLE - - if (m_pTimer == NULL) - { - return; - } - - Lock(); - - CTimeValue now = m_pTimer->GetAsyncTime(); - float timePassed = (now - m_LastUpdateTime).GetSeconds(); - - // If more than 0.2 sec have passed since the last OnUpdate() call, then - // we'll start painting dots to the status line. - if (timePassed > 0.2f) - { - int nDots = (int)(timePassed + 0.5) / 3; - if (nDots > (int) m_Width - 2) - { - nDots = (int)m_Width - 2; - } - if (m_ProgressStatus.length() != nDots) - { - m_ProgressStatus.clear(); - m_ProgressStatus.append(nDots, '.'); - DrawStatus(); - DrawCmd(true); - refresh(); - } - } - - Unlock(); -} - -// get at least n spaces -static char* GetSpaces(int n) -{ - static char* spaceBuffer = 0; - static int spaceBufferSz = 0; - - if (n > spaceBufferSz) - { - spaceBufferSz = MAX(spaceBufferSz * 2, n); - delete[] spaceBuffer; - spaceBuffer = new char[spaceBufferSz]; - memset(spaceBuffer, ' ', spaceBufferSz); - } - - return spaceBuffer; -} - -void CUNIXConsole::DrawHeader() -{ - IS_SHOW_CONSOLE - - const char* const headerString = m_HeaderString.c_str(); - int headerLength = m_HeaderString.size(); - int padLeft = 0, padRight = 0; - const char* term = termname(); - - assert(IsLocked()); - - if (m_HeaderHeight == 0) - { - return; - } - - if (headerLength >= (int)m_Width) - { - padLeft = 0; - padRight = 0; - headerLength = m_Width; - } - else - { - padLeft = (m_Width - headerLength) / 2; - padRight = m_Width - headerLength - padLeft; - } - move(m_HeaderHeight - 1, 0); -#if defined(LINUX) - // For the Linux console ncurses reports the A_UNDERLINE is supported, even - // thought it is not. We'll do an explicit test for the terminal type - // "linux" (i.e. Linux console). - if ((termattrs() & A_UNDERLINE) && strcasecmp(term, "linux")) - { - attrset(A_UNDERLINE); - } - else -#endif - { - if (m_EnableColor) - { - attrset(A_BOLD | COLOR_PAIR(m_ColorPair[2] /* blue */)); - } - else - { - attrset(A_REVERSE); - } - } - scrollok(stdscr, FALSE); - addnstr(GetSpaces(padLeft), padLeft); - addnstr(headerString, headerLength); - addnstr(GetSpaces(padRight), padRight); - scrollok(stdscr, TRUE); - attrset(A_NORMAL); -} - -// Output a single log line. -// If the noOutput flag is set to 'true', then no output is written to the -// screen and no cursor movements are performed. -// The method returns the current output column (i.e. the output column for -// the next charater to be written to the log window). -// Note: Even it the noOutput flag is set, the method will update the m_Color -// field of the UNIX console. -unsigned CUNIXConsole::DrawLogLine(const string& line, bool noOutput) -{ - IS_SHOW_CONSOLE_RET(0) - - const unsigned row = m_Height - m_CmdHeight - m_StatusHeight - 1; - unsigned column = 0; - - if (!noOutput) - { - assert(IsLocked()); - move(row, column); - attrset(A_NORMAL); - } - for (string::const_iterator it = line.begin(), itEnd = line.end(); it != itEnd; ) - { - char c = *it++; - if (column == m_Width - 1) - { - if (!noOutput) - { - attr_t colorAttr = 0; - if (m_EnableColor) - { - colorAttr = COLOR_PAIR(UNIXConsole_WRAP_COLOR); - } - attrset(A_NORMAL | colorAttr); - addch(UNIXConsole_WRAP_CHAR); - ScrollLog(); - move(row, 0); - SetColorRaw(m_Color); - } - column = 0; - } - if (c == 1) - { - assert(it != itEnd); - int color = *it - '0'; - m_Color = color; - ++it; - if (!noOutput) - { - SetColorRaw(color); - } - continue; - } - if (!noOutput) - { - addch(c); - } - ++column; - } - return column; -} - -// The scrollUp parameter indicates how many log lines to scroll up from the -// bottom. -void CUNIXConsole::DrawLog() -{ - IS_SHOW_CONSOLE - - unsigned scrollUp = m_ScrollUp; - - assert(IsLocked()); - - if (IsTooSmall()) - { - return; - } - if (m_LineBuffer.empty()) - { - return; - } - - // DrawLog is called only on refresh and on window resize, so performance is - // not an issue. We'll simply repaint by re-sending the log lines from the - // scroll buffer. - int nLines = m_LineBuffer.size(); - int lastLine = nLines - 1 - (int)scrollUp; - int firstLine = lastLine - GetLogHeight(); - - if (firstLine < 0) - { - firstLine = 0; - } - for (int i = firstLine; i <= lastLine; ++i) - { - const string& line = m_LineBuffer[i]; - if (i > firstLine) - { - ScrollLog(); - } - DrawLogLine(line); - } -} - -void CUNIXConsole::DrawStatus(int maxLines) -{ - IS_SHOW_CONSOLE - - unsigned row = m_Height - m_CmdHeight - m_StatusHeight; - const char* statusLeft = NULL; - const char* statusRight = NULL; - char bufferLeft[256]; - char bufferRight[256]; - - assert(IsLocked()); - - if (IsTooSmall() || maxLines == 0 || m_StatusHeight == 0) - { - return; - } - else if (maxLines == -1) - { - maxLines = m_StatusHeight; - } - - // If we're scrolled, then the right size shows a scroll indicator. - if (m_ScrollUp > 0) - { - const int logHeight = GetLogHeight(); - int logBottomLine = (int)m_LineBuffer.size() - m_ScrollUp; - assert(logBottomLine >= 0); - float percent = 100.f * (float)logBottomLine / m_LineBuffer.size(); - if (m_ScrollUp == m_LineBuffer.size() - logHeight) - { - cry_strcpy(bufferRight, "| SCROLL:TOP "); - } - else - { - snprintf( - bufferRight, - sizeof bufferRight, - "| SCROLL:%.1f%% ", - percent); - bufferRight[sizeof(bufferRight) - 1] = 0; - } - statusRight = bufferRight; - } - - if (!m_Prompt.empty()) - { - // No status display when a user prompt is active. - } - else if (!m_ProgressStatus.empty()) - { - snprintf(bufferLeft, sizeof bufferLeft, " %s", m_ProgressStatus.c_str()); - bufferLeft[sizeof bufferLeft - 1] = 0; - statusLeft = bufferLeft; - } - else if (m_OnUpdateCalled) - { - // Standard status display. - // Map name and game rules on the left. - // Current update rate and player count on the right. - const char* mapName = m_svMap->GetString(); - const char* gameRules = m_svGameRules->GetString(); - snprintf(bufferLeft, sizeof bufferLeft, - " map:%s rules:%s", - mapName, - gameRules); - bufferLeft[sizeof bufferLeft - 1] = 0; - statusLeft = bufferLeft; - float updateRate = 0.f; - static float displayUpdateRate = 0.f; - if (m_pTimer != NULL) - { - updateRate = m_pTimer->GetFrameRate(); -#if 0 - // Avoid jumping numbers in the update rate display. Per update the - // displayed update rate changes by at most maxDeltaRate. - const static float maxDeltaRate = 10.0f; - if (updateRate - displayUpdateRate > maxDeltaRate) - { - displayUpdateRate += maxDeltaRate; - } - else if (updateRate - displayUpdateRate < -maxDeltaRate) - { - displayUpdateRate -= maxDeltaRate; - } - else - { - displayUpdateRate = updateRate; - } -#else - // Display the update rate as reported by the timer. - displayUpdateRate = updateRate; -#endif - } - else - { - displayUpdateRate = 0.f; - } - if (statusRight == NULL) - { - char* pBufferRight = bufferRight; - char* const pBufferRightEnd = bufferRight + sizeof bufferRight; - azstrcpy(pBufferRight, AZ_ARRAY_SIZE(bufferRight), "| "); - pBufferRight += strlen(pBufferRight); - int numPlayers = 0; - - if (pBufferRight < pBufferRightEnd) - { - if (m_pConsole != NULL) - { - pBufferRight += snprintf( - pBufferRight, - pBufferRightEnd - pBufferRight, - "upd:%.1fms(%.2f..%.2f) " \ - "rate:%.1f/s", - m_updStats.avgUpdateTime, m_updStats.minUpdateTime, m_updStats.maxUpdateTime, - displayUpdateRate); - } - else - { - cry_strcpy(pBufferRight, pBufferRightEnd - pBufferRight, "BUSY "); - } - } - bufferRight[sizeof bufferRight - 1] = 0; - statusRight = bufferRight; - } - } - else - { - // No status display (blank). This branch is taken on the very first draw - // operation of the UNIX console. - } - if (statusLeft == NULL) - { - statusLeft = ""; - } - if (statusRight == NULL) - { - statusRight = ""; - } - - int leftWidth = strlen(statusLeft); - int rightWidth = strlen(statusRight); - int pad = 0; - - if (leftWidth + rightWidth > (int)m_Width) - { - pad = 0; - if (rightWidth > (int)m_Width) - { - leftWidth = 0; - rightWidth = m_Width; - } - else - { - leftWidth = m_Width - rightWidth; - } - } - else - { - pad = m_Width - leftWidth - rightWidth; - } - - move(row, 0); - attrset(A_REVERSE | A_BOLD); - scrollok(stdscr, FALSE); - for (int i = 0; i < leftWidth; ++i) - { - addch(statusLeft[i]); - } - for (int i = 0; i < pad; ++i) - { - addch(' '); - } - for (int i = 0; i < rightWidth; ++i) - { - addch(statusRight[i]); - } - scrollok(stdscr, TRUE); - attrset(A_NORMAL); -} - -void CUNIXConsole::DrawFullscreen() -{ - IS_SHOW_CONSOLE - - scrollok(stdscr, FALSE); - - int maxy = 1; - for (DynArray::iterator iter = m_drawCmds.begin(); iter != m_drawCmds.end(); ++iter) - { - maxy = max(maxy, iter->y); - } - - int scrolly = min(maxy - 1, m_ScrollUp); - - for (DynArray::iterator iter = m_drawCmds.begin(); iter != m_drawCmds.end(); ++iter) - { - switch (iter->op) - { - case eCDO_PutText: - { - int y = iter->y - scrolly; - if (y < 0 || y > (int)m_Height - 4) - { - break; - } - if (iter->x < 0 || iter->x > (int)m_Width) - { - break; - } - int len = strlen(iter->text); - if (iter->x + len > (int)m_Width) - { - len = m_Width - iter->x; - } - move(y + 1, iter->x); - for (int i = 0; i < len; i++) - { - addch(iter->text[i]); - } - } - } - } - scrollok(stdscr, TRUE); -} - -void CUNIXConsole::DrawCmd(bool cursorOnly) -{ - IS_SHOW_CONSOLE - - unsigned row = m_Height - m_CmdHeight; - unsigned column = 0; - attr_t colorAttr = 0; - const unsigned promptWidth = strlen(UNIXConsole_PROMPT); - const unsigned moreLeftWidth = strlen(UNIXConsole_MORE_LEFT); - const unsigned moreRightWidth = strlen(UNIXConsole_MORE_RIGHT); - - assert(IsLocked()); - - // If the window is too small, then don't draw anything. - if (IsTooSmall() - || m_CmdHeight == 0 - || m_Width < promptWidth + moreLeftWidth + moreRightWidth) - { - return; - } - - if (!m_Prompt.empty()) - { - DrawCmdPrompt(); - return; - } - - if (!cursorOnly) - { - scrollok(stdscr, FALSE); - - // Draw the command prompt. - if (m_EnableColor) - { - colorAttr = COLOR_PAIR(UNIXConsole_PROMPT_COLOR); - } - attrset(A_BOLD | colorAttr); - move(row, 0); - for (const char* p = UNIXConsole_PROMPT; *p; ++p) - { - addch(*p); - ++column; - } - - // Draw the left scroll indicator (if scrolled). - if (m_ScrollPosition > 0) - { - if (m_EnableColor) - { - colorAttr = COLOR_PAIR(UNIXConsole_MORE_COLOR); - } - attrset(A_NORMAL | colorAttr); - for (const char* p = UNIXConsole_MORE_LEFT; *p; ++p) - { - addch(*p); - ++column; - } - } - - // Draw the input line. We'll draw to the end of the command window - // (leaving the last cell blank) and the overdraw the more indicator (if - // required). - string::const_iterator it = m_InputLine.begin(); - string::const_iterator itEnd = m_InputLine.end(); - if (m_ScrollPosition > 0) - { - for (int i = m_ScrollPosition + strlen(UNIXConsole_MORE_LEFT); - i > 0; - --i, ++it) - { - ; - } - } - attrset(A_NORMAL); - bool lineTruncated = false; - for (; it != itEnd; ++it) - { - char c = *it; - if (row == m_Height - 1 && column == m_Width - 1) - { - lineTruncated = true; - break; - } - if (column == m_Width) - { - row += 1; - column = 0; - assert(row < m_Height); - move(row, column); - } - addch(c); - ++column; - } - - // Draw the right scroll indicator (if required). - if (lineTruncated) - { - move(m_Height - 1, m_Width - moreRightWidth); - if (m_EnableColor) - { - colorAttr = COLOR_PAIR(UNIXConsole_MORE_COLOR); - } - attrset(A_NORMAL | colorAttr); - for (const char* p = UNIXConsole_MORE_RIGHT; *p; ++p) - { - addch(*p); - ++column; - } - } - else - { - attrset(A_NORMAL); - clrtobot(); - move(m_Height - 1, m_Width - 1); - addch(' '); - } - - scrollok(stdscr, TRUE); - } - - // Update the cursor position. - column = m_CursorPosition - m_ScrollPosition + promptWidth; - row = m_Height - m_CmdHeight; - if (column >= m_Width) - { - row += column / m_Width; - column %= m_Width; - } - move(row, column); - refresh(); -} - -void CUNIXConsole::DrawCmdPrompt() -{ - IS_SHOW_CONSOLE - - unsigned row = m_Height - m_CmdHeight; - unsigned column = 0; - - string::const_iterator it = m_Prompt.begin(); - string::const_iterator itEnd = m_Prompt.end(); - attrset(A_BOLD); - clrtobot(); - scrollok(stdscr, FALSE); - move(row, column); - for (; it != itEnd; ++it) - { - char c = *it; - if (row == m_Height - 1 && column == m_Width - 1) - { - break; - } - if (column == m_Width) - { - row += 1; - column = 0; - move(row, column); - } - addch(c); - ++column; - } - scrollok(stdscr, TRUE); - move(row, column); - refresh(); -} - -char CUNIXConsole::Prompt(const char* promptString, const char* responseChars) -{ - char response = 0; - - Lock(); - - while (m_PromptResponse != 0) - { - m_PromptCond.Wait(m_Lock); - } -#ifndef _NDEBUG - // This method is called from __assert_fail, so we better don't put any - // asserts in here... - if (!m_Prompt.empty() || !*promptString || !*responseChars) - { - abort(); - } - if (strlen(responseChars) + 1 > sizeof m_PromptResponseChars) - { - abort(); - } -#endif - m_Prompt = promptString; - cry_strcpy(m_PromptResponseChars, responseChars); - DrawCmd(); - while (m_PromptResponse == 0) - { - m_PromptCond.Wait(m_Lock); - } - response = m_PromptResponse; - m_PromptResponse = 0; - m_Prompt.clear(); - m_PromptResponseChars[0] = 0; - m_PromptCond.Notify(); - DrawCmd(); - - Unlock(); - - return response; -} - -bool CUNIXConsole::IsInputThread() -{ - CrySimpleThread<>* callerThread = CrySimpleThread<>::Self(); - - return callerThread == m_InputThread; -} - -void CUNIXConsole::PrintF(const char* format, ...) -{ - char lineBuffer[1024]; - va_list ap; - - va_start(ap, format); - vsnprintf(lineBuffer, sizeof lineBuffer, format, ap); - lineBuffer[sizeof lineBuffer - 1] = 0; - Print(lineBuffer); - va_end(ap); -} - -void CUNIXConsole::Print(const char* line) -{ - IS_SHOW_CONSOLE - - static string lastLine; - static bool firstCall = true; - const size_t lineLength = strlen(line); - size_t lineOffset = 0; - - Lock(); - - // Check if the last line is a true prefix of the specified text argument. - // It it is a prefix, then the output is added to the last line sent to the - // sink. - if (!firstCall - && lineLength > lastLine.size() - && !strncmp(line, lastLine.c_str(), lastLine.size())) - { - // Line continued. - lineOffset = lastLine.size(); - ContinueLine(); // Will set the correct color. - } - else - { - NewLine(); - SetColor(); - } - lastLine = line; - firstCall = false; - - for (size_t i = lineOffset; i < lineLength; ++i) - { - char c = line[i]; - switch (c) - { - case '\\': - if (i < lineLength - 1 && line[i + 1] == 'n') - { - // Sequence "\\n", treat as "\n". - NewLine(); - ++i; - continue; - } - break; - case '\n': - NewLine(); - continue; - case '\r': - ClearLine(); - continue; - case '\t': - // We'll do it like the graphical console, just add 4 spaces and don't - // care about TAB stops. - for (unsigned j = 0; j < 4; ++j) - { - Put(' '); - } - continue; - case '$': - if (i < lineLength - 1) - { - ++i; - char colorChar = line[i]; - if (isdigit(colorChar)) - { - SetColor(colorChar - '0'); - continue; - } - if (colorChar == 'o' || colorChar == 'O') - { - // Ignore. - continue; - } - } - break; - default: - break; - } - if (c < 0x20) - { - // Unrecognized control character. Ignore. - continue; - } - Put((unsigned char)c); - } - DrawCmd(true); - // Flush(); - - Unlock(); -} - -bool CUNIXConsole::OnError(const char* errorString) -{ - if (!m_Initialized) - { - return true; - } - - return true; -} - -void CUNIXConsole::OnInitProgress(const char* sProgressMsg) -{ - if (!m_Initialized) - { - return; - } - - Lock(); - m_ProgressStatus = sProgressMsg; - DrawStatus(); - DrawCmd(true); - Flush(); - Unlock(); -} - -void CUNIXConsole::OnInit(ISystem* pSystem) -{ - if (m_RequireDedicatedServer && !gEnv->IsDedicated()) - { - return; - } - - Lock(); - - if (!m_Initialized) - { - Init(); - } - - assert(m_pSystem == NULL); - m_pSystem = pSystem; - assert(m_pConsole == NULL); - m_pConsole = pSystem->GetIConsole(); - - // Add the output print sink to the system console. - if (m_pConsole != 0) - { - m_pConsole->AddOutputPrintSink(this); - } - - // Start the input thread. - m_InputThread = new CUNIXConsoleInputThread(*this); - m_InputThread->Start(); - - Unlock(); - -#if defined(NCURSES) - // Setup the signal handler. - struct sigaction action; - memset(&action, 0, sizeof action); - action.sa_handler = CUNIXConsoleSignalHandler::Handler; - sigfillset(&action.sa_mask); - CUNIXConsoleSignalHandler::m_pUNIXConsole = this; - sigaction(SIGWINCH, &action, NULL); - sigset_t mask; - memset(&mask, 0, sizeof mask); - sigemptyset(&mask); - sigaddset(&mask, SIGWINCH); - sigprocmask(SIG_UNBLOCK, &mask, NULL); -#endif -} - -void CUNIXConsole::OnShutdown() -{ - if (!m_Initialized) - { - return; - } - - Lock(); - assert(!m_OnShutdownCalled); - m_pConsole->RemoveOutputPrintSink(this); - m_OnShutdownCalled = true; - Unlock(); - - Cleanup(); -} - -void CUNIXConsole::OnUpdate() -{ - FUNCTION_PROFILER(gEnv->pSystem, PROFILE_SYSTEM); - - IS_SHOW_CONSOLE - - if (!m_Initialized) - { - return; - } - - bool updateStatus = false; - static CTimeValue lastStatusUpdate = 0.f; - - if (m_OnShutdownCalled) - { - return; - } - - Lock(); - - if (!m_OnUpdateCalled) - { - m_OnUpdateCalled = true; - assert(m_svMap == NULL); - assert(m_svGameRules == NULL); - m_svMap = m_pConsole->GetCVar("sv_map"); - m_svGameRules = m_pConsole->GetCVar("sv_gamerules"); - assert(m_pTimer == NULL); - m_pTimer = m_pSystem->GetITimer(); - } - - if (!m_ProgressStatus.empty()) - { - m_ProgressStatus.clear(); - updateStatus = true; - } - CTimeValue now = m_pTimer->GetAsyncTime(); - if ((now - lastStatusUpdate).GetSeconds() > 0.1f) - { - updateStatus = true; - } - m_LastUpdateTime = now; - - if (updateStatus) - { - DrawStatus(); - DrawCmd(true); - Flush(); - lastStatusUpdate = now; - } - - while (!m_CommandQueue.empty()) - { - const string& command = m_CommandQueue[0]; - Unlock(); - if (m_pConsole) - { - m_pConsole->ExecuteString(command.c_str()); - - // doing the check again in case m_pConsole was nulled while executing the command - if (m_pConsole) - { - m_pConsole->AddCommandToHistory(command.c_str()); - } - } - Lock(); - m_CommandQueue.pop_front(); - } - - m_pSystem->GetUpdateStats(m_updStats); - - bool fsMode = !m_drawCmds.empty(); - if (fsMode || fsMode != m_fsMode) - { - m_fsMode = fsMode; - Repaint(); - } - - Unlock(); -} - -void CUNIXConsole::GetMemoryUsage(ICrySizer* pSizer) -{ - size_t size = sizeof *this; - - Lock(); - - // We're using string (for various reasons), so our best guess of the - // size is the .size(). - size += m_HeaderString.size(); - size += m_LineBuffer.size() * sizeof(string); - for (TLineBuffer::const_iterator it = m_LineBuffer.begin(), - itEnd = m_LineBuffer.end(); - it != itEnd; - ++it) - { - size += it->size(); - } - size += m_CommandQueue.size() * sizeof(string); - for (TCommandQueue::const_iterator it = m_CommandQueue.begin(), - itEnd = m_CommandQueue.end(); - it != itEnd; - ++it) - { - size += it->size(); - } - size += m_CommandHistory.size() * sizeof(string); - for (TCommandHistory::const_iterator it = m_CommandHistory.begin(), - itEnd = m_CommandHistory.end(); - it != itEnd; - ++it) - { - size += it->size(); - } - if (m_InputThread != NULL) - { - size += sizeof *m_InputThread; - } - size += m_InputLine.size(); - size += m_SavedInputLine.size(); - size += m_ProgressStatus.size(); - - Unlock(); - - pSizer->AddObject(this, size); -} - -Vec2_tpl CUNIXConsole::BeginDraw() -{ - m_newCmds.resize(0); - return Vec2_tpl(80, 25 - 3); -} - -void CUNIXConsole::PutText(int x, int y, const char* msg) -{ - IS_SHOW_CONSOLE - - SConDrawCmd cmd; - cmd.op = eCDO_PutText; - cmd.x = x; - cmd.y = y; - cry_strcpy(cmd.text, msg); - m_newCmds.push_back(cmd); -} - -void CUNIXConsole::EndDraw() -{ - IS_SHOW_CONSOLE - - Lock(); - m_drawCmds.swap(m_newCmds); - Unlock(); -} - -void CUNIXConsoleInputThread::Run() -{ -#if !defined(WIN32) - fd_set rdfds; -#endif - bool interrupted = false; - - // The input thread selects stdin (0) and the interrupt pipe. The select() - // call has a timeout (typically 0.5 sec) and will call the InputIdle() - // method whenever the timer expires. - while (true) - { - interrupted = false; -#if !defined(WIN32) - FD_ZERO(&rdfds); - FD_SET(m_IntrPipe[0], &rdfds); - FD_SET(0, &rdfds); - timeval tv; - memset(&tv, 0, sizeof tv); - tv.tv_sec = 0; - tv.tv_usec = 100000; // 0.1 sec. - if (select(m_IntrPipe[0] + 1, &rdfds, NULL, NULL, &tv) != -1) - { - if (FD_ISSET(m_IntrPipe[0], &rdfds)) - { - char buf; - read(m_IntrPipe[0], &buf, 1); - interrupted = true; - } - else if (!FD_ISSET(0, &rdfds)) - { - // Both m_IntrPipe[0] and 0 are not ready, so this must be a timeout. - m_UNIXConsole.InputIdle(); - continue; - } - } - else - { - // Got interrupted by a signal. - assert(errno == EINTR); - interrupted = true; - } -#else - HANDLE handles[2]; - handles[0] = m_IntrEvent; - handles[1] = GetStdHandle(STD_INPUT_HANDLE); - DWORD result = WaitForMultipleObjects(2, handles, false, 10 /* 0.1 sec */); - switch (result) - { - case WAIT_OBJECT_0: - interrupted = true; - ResetEvent(m_IntrEvent); - break; - case WAIT_OBJECT_0 + 1: - break; - case WAIT_TIMEOUT: - m_UNIXConsole.InputIdle(); - continue; - case WAIT_FAILED: - assert(!"WaitForMultipleObjects() failed"); - } -#endif - if (interrupted) - { - if (m_Cancelled) - { - break; - } - m_UNIXConsole.Lock(); - m_UNIXConsole.CheckResize(); - m_UNIXConsole.Unlock(); - continue; - } - int c = getch(); - m_UNIXConsole.Lock(); - - // Handle prompt responses. - if (!m_UNIXConsole.m_Prompt.empty()) - { - bool acceptAll = false; - char response = 0; - if (strchr(m_UNIXConsole.m_PromptResponseChars, '@')) - { - acceptAll = true; - } - if (c == KEY_ENTER || c == '\r') - { - c = '\n'; - } - if (c == KEY_BACKSPACE || c == 0x7f) - { - c = '\010'; - } - if (c <= 0xff && strchr(m_UNIXConsole.m_PromptResponseChars, (char)c)) - { - response = (char)c; - } - else if (acceptAll && (isprint(c) || c == '\n')) - { - response = (char)c; - } - else - { - beep(); - m_UNIXConsole.Unlock(); - continue; - } - m_UNIXConsole.m_PromptResponse = response; - m_UNIXConsole.m_PromptCond.Notify(); - m_UNIXConsole.Unlock(); - continue; - } - - // if console is hided then pass only F10 key - if (!m_UNIXConsole.m_bShowConsole) - { - if (KEY_F(10) == c) - { - m_UNIXConsole.KeyF(10); - } - m_UNIXConsole.Unlock(); - continue; - } - - switch (c) - { - case ERR: - break; - case KEY_RESIZE: - // Window size changed. This key is received only if the ncurses - // library is configured to handle SIGWINCH and if no other SIGWINCH - // handler has been installed. - m_UNIXConsole.SetSize(COLS, LINES); - m_UNIXConsole.Repaint(); - break; - case KEY_ENTER: - case PADENTER: - case '\r': - case '\n': - m_UNIXConsole.KeyEnter(); - break; - case KEY_UP: - case '\020': // CTRL-P - m_UNIXConsole.KeyUp(); - break; - case KEY_DOWN: - case '\016': // CTRL-N - m_UNIXConsole.KeyDown(); - break; - case KEY_LEFT: - m_UNIXConsole.KeyLeft(); - break; - case KEY_RIGHT: - m_UNIXConsole.KeyRight(); - break; - case KEY_HOME: - case '\001': // CTRL-A - m_UNIXConsole.KeyHome(false); - break; - case CTL_HOME: - m_UNIXConsole.KeyHome(true); - break; - case KEY_END: - case '\005': // CTRL-E - m_UNIXConsole.KeyEnd(false); - break; - case CTL_END: - m_UNIXConsole.KeyEnd(true); - break; - case KEY_BACKSPACE: -#if defined(MAC) - // Mac OS X returns delete key instead of backspace - case 0x7f: -#else - case '\010': // CTRL-H -#endif - m_UNIXConsole.KeyBackspace(); - break; - case KEY_DC: - case KEY_SDC: - case '\004': // CTRL-D - m_UNIXConsole.KeyDelete(); - break; - case '\027': // CTRL-W - m_UNIXConsole.KeyDeleteWord(); - break; - case '\013': // CTRL-K - m_UNIXConsole.KeyKill(); - break; - case '\014': // CTRL-L - m_UNIXConsole.KeyRepaint(); - break; - case '\t': // TAB - m_UNIXConsole.KeyTab(); - break; - case KEY_NPAGE: - case '\006': // CTRL-F - m_UNIXConsole.KeyPgDown(false); - break; - case CTL_PGDN: - m_UNIXConsole.KeyPgDown(true); - break; - case KEY_PPAGE: - case '\002': // CTRL-B - m_UNIXConsole.KeyPgUp(false); - break; - case CTL_PGUP: - m_UNIXConsole.KeyPgUp(true); - break; - case KEY_F(10): - m_UNIXConsole.KeyF(10); - break; - case KEY_F(11): - m_UNIXConsole.KeyF(11); - break; - default: - if (c >= 0x20 && c <= 0xff) - { - m_UNIXConsole.Key(c); - } - break; - } - m_UNIXConsole.Unlock(); - } -} - -void CUNIXConsole::KeyF(int id) -{ -#ifdef LINUX - if (11 == id) - { - def_prog_mode(); - endwin(); - m_bShowConsole = false; - system("/bin/bash"); - reset_prog_mode(); - refresh(); - m_bShowConsole = true; - } - else if (10 == id) - { - if (m_bShowConsole) - { - def_prog_mode(); - endwin(); - m_bShowConsole = false; - } - else - { - reset_prog_mode(); - refresh(); - m_bShowConsole = true; - } - } -#endif -} - -CUNIXConsole* CUNIXConsoleSignalHandler::m_pUNIXConsole = NULL; - -void CUNIXConsoleSignalHandler::Handler(int signum) -{ -#if defined(NCURSES) - switch (signum) - { - case SIGWINCH: - m_pUNIXConsole->m_WindowResized = true; - m_pUNIXConsole->m_InputThread->Interrupt(); - break; - default: - break; - } -#endif -} - -#endif // USE_UNIXCONSOLE - -/////////////////////////////////////////////////////////////////////////////////////// -// -// simple light-weight console implementation -// -/////////////////////////////////////////////////////////////////////////////////////// -#if defined(AZ_RESTRICTED_PLATFORM) -#include AZ_RESTRICTED_FILE(UnixConsole_cpp) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else -CNULLConsole::CNULLConsole(bool isDaemonMode) - : m_isDaemon(isDaemonMode) -{ -} - -void CNULLConsole::Print(const char* inszText) -{ - if (m_isDaemon) - { - return; - } - -#if defined(WIN32) || defined(WIN64) - DWORD written; - char buf[1024]; - sprintf_s(buf, "%s\n", inszText); - WriteConsole(m_hOut, buf, strlen(buf), &written, NULL); -#elif defined(LINUX) || defined(MAC) - printf("%s\n", inszText); -#endif -} - -void CNULLConsole::OnInit(ISystem* pSystem) -{ - m_syslogStats.Init(); - - if (m_isDaemon) - { - return; - } - - IConsole* pConsole = pSystem->GetIConsole(); - pConsole->AddOutputPrintSink(this); - -#if defined(WIN32) || defined(WIN64) - AllocConsole(); - m_hOut = GetStdHandle(STD_OUTPUT_HANDLE); -#endif -} - -void CNULLConsole::OnUpdate() -{ -} - -void CNULLConsole::PutText([[maybe_unused]] int x, [[maybe_unused]] int y, [[maybe_unused]] const char* msg) -{ -} -#endif - -/////////////////////////////////////////////////////////////////////////////////////// -// -// Logging server internal statistics into syslog service -// -/////////////////////////////////////////////////////////////////////////////////////// -CSyslogStats::CSyslogStats() - : m_syslog_stats(0) - , m_syslog_period(SYSLOG_DEFAULT_PERIOD) -{ -} - -CSyslogStats::~CSyslogStats() -{ -#if (defined(LINUX) && !defined(ANDROID)) || defined(MAC) -#if defined(NCURSES) - closelog(); -#endif - if (gEnv->pConsole) - { - gEnv->pConsole->UnregisterVariable("syslog_stats"); - gEnv->pConsole->UnregisterVariable("syslog_period"); - } -#endif -} - -void CSyslogStats::Init() -{ -#if (defined(LINUX) && !defined(ANDROID)) || defined(MAC) -#if defined(NCURSES) -# if defined(LINUX) - openlog("LinuxLauncher", LOG_PID, LOG_USER); -# elif defined(MAC) - openlog("MacLauncher", LOG_PID, LOG_USER); -# endif -#endif // NCURSES - - if (gEnv->pConsole) - { - REGISTER_CVAR2("syslog_stats", &m_syslog_stats, 0, 0, "Start/Stop logging server info into syslog"); - REGISTER_CVAR2("syslog_period", &m_syslog_period, SYSLOG_DEFAULT_PERIOD, 0, "Syslog logging timeout period"); - } -#endif -} - -void CSyslogStats::Update([[maybe_unused]] float srvRate, [[maybe_unused]] int numPlayers) -{ -} - -#endif // defined(USE_DEDICATED_SERVER_CONSOLE) - -// vim:ts=2 - diff --git a/Code/CryEngine/CrySystem/UnixConsole.h b/Code/CryEngine/CrySystem/UnixConsole.h deleted file mode 100644 index 12b2852e69..0000000000 --- a/Code/CryEngine/CrySystem/UnixConsole.h +++ /dev/null @@ -1,573 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Console implementation for UNIX systems, based on curses ncurses. - - -#pragma once - - -#include -#include - -#if defined(USE_DEDICATED_SERVER_CONSOLE) - -class CSyslogStats -{ -public: - CSyslogStats(); - ~CSyslogStats(); - - void Init(); - void Update(float srvRate, int numPlayers); - -private: - int m_syslog_stats; - int m_syslog_period; - CTimeValue m_syslogStartTime; - CTimeValue m_syslogCurrTime; - static const int SYSLOG_DEFAULT_PERIOD = 3000; // default timeout (sec) -}; - -#if defined(USE_UNIXCONSOLE) - -#if defined(WIN32) -// Avoid naming conflict with wincon.h. -#undef MOUSE_MOVED -#endif - -#include -#include - -// Avoid naming conflicts with pdcurses. -// Use werase(stdscr) instead of erase(). -#undef erase -// Use wclear(stdscr) instead of clear(). -#undef clear -// (MATT) Could not compile CONTAINER_VALUE etc templates for Vector{Map,Set} in ISerialise apparently because of the -// clear and erase macros. Changed order to undefine them straight after pdcurses. {2009/04/09} - -#include - - -// Define if you wish to enable the player count feature. -// Note: The player count feature can not be used when building -// Windows-style DLLs! -#if defined(LINUX) || defined(MAC) -#define UC_ENABLE_PLAYER_COUNT 1 -#else -#undef UC_ENABLE_PLAYER_COUNT -#endif - -// Define if you wish to enable magic console commands. -// These are commands starting with an '@' character, which are intercepted by -// the CUNIXConsole class and not passed to the system. -//#undef UC_ENABLE_MAGIC_COMMANDS -#define UC_ENABLE_MAGIC_COMMANDS 1 - -class CUNIXConsoleInputThread; -class CUNIXConsoleSignalHandler; - - -class CUNIXConsole - : public ISystemUserCallback - , public IOutputPrintSink - , public ITextModeConsole -{ - friend class CUNIXConsoleInputThread; - friend class CUNIXConsoleSignalHandler; - - static const int DEFAULT_COLOR = -1; - - typedef CryMutex ConsoleLock; - ConsoleLock m_Lock; - static CryCriticalSectionNonRecursive m_cleanupLock; - - enum EConDrawOp - { - eCDO_PutText, - }; - struct SConDrawCmd - { - EConDrawOp op; - int x, y; - char text[256]; - }; - DynArray m_drawCmds; - DynArray m_newCmds; - bool m_fsMode; - - CSyslogStats m_syslogStats; - bool m_bShowConsole; // hide or show console - - SSystemUpdateStats m_updStats; - - bool IsLocked() { return m_Lock.IsLocked(); } - - // The header string. - // - // Should be set by the launcher through SetHeader(). - string m_HeaderString; - - // The line buffer. - // - // We'll use the escape sequence "\1" followed by a digit to encode color - // changes. - typedef std::deque TLineBuffer; - TLineBuffer m_LineBuffer; - - // The command queue. - // - // Commands typed on the console are added to this command queue. It is - // processed by the OnUpdate() callback. - typedef std::deque TCommandQueue; - TCommandQueue m_CommandQueue; - - // The command history. - // - // The UNIX console is decoupled from the system console object through a - // command queue, so we can't use the history buffer from the system - // console. This is our own command history. - // - // The history index indicates the reverse index (counting from the end) - // into our command history. The special value -1 indicates that we're not - // currently showing a command from the history. - typedef std::deque TCommandHistory; - TCommandHistory m_CommandHistory; - int m_HistoryIndex; - - // Interactive prompt. - // - // If this is not empty, then this prompt is shown in the command area. The - // input thread will wait for one if the response characters. The response is - // stored to m_PromptResponse and m_PromptCond is notified. - string m_Prompt; - char m_PromptResponseChars[16]; // Null-terminated. - char m_PromptResponse; - CryConditionVariable m_PromptCond; - - ISystem* m_pSystem; - IConsole* m_pConsole; - ITimer* m_pTimer; // Initialized on the first call to OnUpdate(). - - // Flag indicating if OnUpdate() has been called. - // - // The initialization of the console variable pointers for 'sv_map' and - // 'sv_gamerules' is deferred until the first iteration of the update loop, - // because OnInit() is called too early for that. - bool m_OnUpdateCalled; - CTimeValue m_LastUpdateTime; - - ICVar* m_svMap; - ICVar* m_svGameRules; - - // Terminal window layout. - // - // The terminal window is split into 4 logical windows. Top to bottom, - // these windows are: - // - Header window. May be empty (height 0). - // - Log window. This is the area in the middle of the terminal showing the - // log messages. - // - Status window. This is a window below the log window showing things - // like current FPS or other status information. - // - Command window. This is a few lines (typically 1 or 2) at the - // bottom of the terminal window. The command prompt and command line - // editor is shown in the command window. - // - // The layout is implementated as a single curses window - the standard - // screen (stdscr). - - // The width and height of the terminal window. - unsigned m_Width, m_Height; - - // The height of the header window. - // The header window is displayed at the top of the terminal window. - // Typically 0 (no header) or 1 (single header line). - unsigned m_HeaderHeight; - - // The height of the status window. - // This is typically a single line between the log window and the command - // window, displayed in inverse video. - unsigned m_StatusHeight; - - // The height of the command window. - // This is typically a single line at the bottom of the screen. - unsigned m_CmdHeight; - - // The current text color. - int m_Color; - - // The default text color pair (read from curses when the app starts). - int m_DefaultColorPair; - - // Flag indicating if color output is enabled. - bool m_EnableColor; - - // Flag indicating that the window has been resized. - // Set by the SIGWINCH signal handler. - bool m_WindowResized; - - // Flag indicating that OnShutdown() has been called. - bool m_OnShutdownCalled; - - // Flag indicating if the console has been initialized (i.e. Init() has been - // called). - bool m_Initialized; - - // Flag indicating if the implied console initialization (performed by the - // OnInit() callback) requires a dedicated server. - // This flag is set through the public SetRequireDedicatedServer() method. - bool m_RequireDedicatedServer; - - // The number of (logical) lines scrolled up. - // 0 indicates that we're at the bottom of the log. - int m_ScrollUp; - - // Array of color pair handles. - // 0: default terminal color - // 1: default terminal color, reverse video - // 2: blue - // 3: green - // 4: red, bold font - // 5: cyan - // 6: yellow on black, bold font - // 7: magenta - // 8: red, normal text - // 9: black on white - short m_ColorPair[10]; - - // The keyboard input thread. - CUNIXConsoleInputThread* m_InputThread; - - // The current input line, cursor position, and horizontal scroll position. - string m_InputLine; - string m_SavedInputLine; - int m_CursorPosition; - int m_ScrollPosition; - - // The current progress status string. - // - // Set by the OnInitProgress() method and cleared by OnUpdate(). If this is - // not empty, then this is shown in the status line. - string m_ProgressStatus; - - // Set the size of the terminal window. - // - // This method is called when the UNIX console is created and whenever the - // size of the terminal window changes (i.e. SIGWINCH received). - // - // We're relying on the ncurses handler for SIGWINCH, so we'll call this - // method when getch() returns KEY_RESIZE. - void SetSize(unsigned width, unsigned height); - - // Check if the terminal window is too small for drawing. - bool IsTooSmall(); - - // Check if the window size has changed. - void CheckResize(); - - // Get the height of the log window. - unsigned GetLogHeight() - { - return m_Height - m_HeaderHeight - m_StatusHeight - m_CmdHeight; - } - - // Scroll the log window and start a new log line. - // - // Move the cursor position to the beginning of the new log line. - void NewLine(); - - // Continue the last log line. - // - // Move the cursor position to the first character following the last - // character logged and update the current color. - void ContinueLine(); - - // Clear the current output line. - // - // Move the cursor to the beginning of the current output line. - // - // Note: This is a bit fuzzy to implement because long wrapped lines are not - // easy to deal with. Instead I'll simply call NewLine() and maybe - // implement this later. - void ClearLine() { NewLine(); } - - // Set the output color. - // - // The color is one of the 10 color codes (0-9) used by the graphical - // console. If color output is enabled, then the corresponding terminal - // color is set. If color output is not enabled, then only the text - // attributes are changed. - // - // In addition to setting the color (if enabled), the method will set the - // following terminal attributes: - // 0, 1: Normal text (black, white) - // 4, 6: Bold text (red, yellow, typically indicates an error or warning) - // other: Underlined text - void SetColor(int color = DEFAULT_COLOR); - void SetColorRaw(int color); - - // Write a single character or a sequence of characters to the console, - // using the currently specified color. The specified character must be a - // printable character. - // - // Note: - // - The Put(const char *) method will interpret '\n' as a line separator an - // call NewLine() when encountered. All other characters must be - // printable characters. - // - Both Put() methods will _not_ update the cursor position before writing - // the character to the screen. It is up to the caller to update the - // cursor position (either by calling NewLine() or ContinueLine()). - void Put(int c); - void Put(const char* s); - - // Get the length of the line (number of displayed characters), not counting - // color change escapes. - static unsigned GetLineLength(const string& line); - - // Get the last printable character from the specified line. It is an error - // if the specified line contains no printable characters. If color is not - // NULL, then the selected color for the last character is stored to *color. - static char GetLastCharacter(const string& line, int* color); - - // Get the height of a line of text. - // - // The method returns the number of terminal lines to display the specified - // line (wrapped). If column is not NULL, then *column is set to the column - // indicating the end of the last wrapped terminal line. - unsigned GetLineHeight(const string& line, unsigned* column = NULL); - - // Scroll the log window one line. - void ScrollLog(); - - // Flush/repaint the screen. - void Flush(); - - // Called by the input thread when idle. - void InputIdle(); - - // Lock/unlock the UNIX console. - void Lock() { m_Lock.Lock(); } - void Unlock() { m_Lock.Unlock(); } - - // Fix the cursor position and scroll position after updating the command - // input line. Returns true if the command window must be repainted. - bool FixCursorPosition(); - - // Called when the command line has been edited. - void OnEdit(); - - // Keyboard input. - void KeyEnter(); - void KeyUp(); - void KeyDown(); - void KeyLeft(); - void KeyRight(); - void KeyHome(bool ctrl); - void KeyEnd(bool ctrl); - void KeyBackspace(); - void KeyDelete(); - void KeyDeleteWord(); - void KeyKill(); - void KeyRepaint(); - void KeyTab(); - void KeyPgUp(bool ctrl); - void KeyPgDown(bool ctrl); - void KeyF(int id); - void Key(int c); - - // Drawing. - void Repaint(); - void DrawHeader(); - unsigned DrawLogLine(const string&, bool noOutput = false); - void DrawLog(); - void DrawFullscreen(); - void DrawStatus(int maxLines = -1); - void DrawCmd(bool cursorOnly = false); - void DrawCmdPrompt(); - - CUNIXConsole(const CUNIXConsole&); - void operator = (const CUNIXConsole&); - -public: - CUNIXConsole(); - ~CUNIXConsole(); - - // Set or clear the RequireDedicatedServer flag. - // The implied initialization call performed by the - // ISystemUserCallback::OnInit() depends on this flag. - // Note: This method _must_ be called before Init() or OnInit() is called. - void SetRequireDedicatedServer(bool); - - // Initialize the console for use. - // - // This method must be called before any other method of the console is - // called. - // It is perfectly valid to instanciate a console and not use it (i.e. skip - // the Init() call). - // - // Note: If the ISystemUserCallback interface is used, then the call to - // Init() is optional. OnInit() will call Init() if it has not been called - // already. - void Init(const char* headerString = NULL); - - // Check if the console is initialized. - bool IsInitialized() { return m_Initialized; } - - // Cleanup function. - // This method is called by the destructor. - // If the instance has not been initialized (via Init() and/or OnInit()), - // then this method has no effect. - void Cleanup(); - - // Set the header string. - // Note: - // - Setting the header string does _not_ trigger a redraw. - // - This method may be called before Init() has been called. - void SetHeader(const char* headerString) - { - Lock(); - m_HeaderString = headerString; - Unlock(); - } - - // Issue a query-response prompt. - // - // promptString is the string to be shown as the query prompt. - // responseChars is a null-terminated string of valid response characters. - // Add '@' to the response characters if the user may type any character. - // - // The method blocks the caller until the user has typed a response. The - // return value is the response character typed by the user. - DLL_EXPORT char Prompt(const char* promptString, const char* responseChars); - - // Check if the calling thread is the input thread. - // - // This may be used to make sure that you're not calling Prompt() from the - // input thread - which will deadlock. - DLL_EXPORT bool IsInputThread(); - - // Print formatted. Calls Print(). - DLL_EXPORT void PrintF(const char* format, ...) PRINTF_PARAMS(2, 3); - - // Interface IOutputPrintSink ///////////////////////////////////////////// - DLL_EXPORT virtual void Print(const char* line); - - // Interface ISystemUserCallback ////////////////////////////////////////// - virtual bool OnError(const char* errorString); - virtual bool OnSaveDocument() { return false; } - virtual bool OnBackupDocument() { return false; } - virtual void OnProcessSwitch() { } - virtual void OnInitProgress(const char* sProgressMsg); - virtual void OnInit(ISystem*); - virtual void OnShutdown(); - virtual void OnUpdate(); - virtual void GetMemoryUsage(ICrySizer* pSizer); - - // Interface ITextModeConsole ///////////////////////////////////////////// - virtual Vec2_tpl BeginDraw(); - virtual void PutText(int x, int y, const char* msg); - virtual void EndDraw(); -}; - -#endif // USE_UNIXCONSOLE - -#if defined(AZ_RESTRICTED_PLATFORM) -#include AZ_RESTRICTED_FILE(UnixConsole_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else -// simple light-weight console -class CNULLConsole - : public IOutputPrintSink - , public ISystemUserCallback - , public ITextModeConsole -{ -public: - CNULLConsole(bool isDaemonMode); - - /////////////////////////////////////////////////////////////////////////////////////// - // IOutputPrintSink - /////////////////////////////////////////////////////////////////////////////////////// - virtual void Print(const char* inszText); - - /////////////////////////////////////////////////////////////////////////////////////// - // ISystemUserCallback - /////////////////////////////////////////////////////////////////////////////////////// - /** this method is called at the earliest point the ISystem pointer can be used - the log might not be yet there - */ - virtual void OnSystemConnect([[maybe_unused]] ISystem* pSystem) {}; - /** Signals to User that engine error occured. - @return true to Halt execution or false to ignore this error. - */ - virtual bool OnError([[maybe_unused]] const char* szErrorString) { return false; }; - /** If working in Editor environment notify user that engine want to Save current document. - This happens if critical error have occured and engine gives a user way to save data and not lose it - due to crash. - */ - virtual bool OnSaveDocument() { return false; } - - /** If working in Editor environment and a critical error occurs notify the user to backup - the current document to prevent data loss due to crash. - */ - virtual bool OnBackupDocument() { return false; } - - /** Notify user that system wants to switch out of current process. - (For ex. Called when pressing ESC in game mode to go to Menu). - */ - virtual void OnProcessSwitch() {}; - - // Notify user, usually editor about initialization progress in system. - virtual void OnInitProgress([[maybe_unused]] const char* sProgressMsg) {}; - - // Initialization callback. This is called early in CSystem::Init(), before - // any of the other callback methods is called. - virtual void OnInit(ISystem*); - - // Shutdown callback. - virtual void OnShutdown() {}; - - // Notify user of an update iteration. Called in the update loop. - virtual void OnUpdate(); - - // to collect the memory information in the user program/application - virtual void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) {}; - - /////////////////////////////////////////////////////////////////////////////////////// - // ITextModeConsole - /////////////////////////////////////////////////////////////////////////////////////// - virtual Vec2_tpl BeginDraw() { return Vec2_tpl(0, 0); }; - virtual void PutText(int x, int y, const char* msg); - virtual void EndDraw() {}; - - void SetRequireDedicatedServer(bool) - { - // Does nothing - } - void SetHeader(const char*) - { - //Does nothing - } -private: -#if defined(WIN32) || defined(WIN64) - HANDLE m_hOut; -#endif - bool m_isDaemon; - CSyslogStats m_syslogStats; -}; - -#endif - -#endif // defined(USE_DEDICATED_SERVER_CONSOLE) diff --git a/Code/CryEngine/CrySystem/Validator.h b/Code/CryEngine/CrySystem/Validator.h deleted file mode 100644 index 83dc0533f6..0000000000 --- a/Code/CryEngine/CrySystem/Validator.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_VALIDATOR_H -#define CRYINCLUDE_CRYSYSTEM_VALIDATOR_H - -#pragma once - -////////////////////////////////////////////////////////////////////////// -// Default validator implementation. -////////////////////////////////////////////////////////////////////////// -struct SDefaultValidator - : public IValidator -{ - CSystem* m_pSystem; - SDefaultValidator(CSystem* system) - : m_pSystem(system) {}; - virtual void Report(SValidatorRecord& record) - { - if (record.text) - { - static bool bNoMsgBoxOnWarnings = false; - if ((record.text[0] == '!') || (m_pSystem->m_sysWarnings && m_pSystem->m_sysWarnings->GetIVal() != 0)) - { - if (g_cvars.sys_no_crash_dialog) - { - return; - } - - if (bNoMsgBoxOnWarnings) - { - return; - } - -#ifdef WIN32 - string strMessage = record.text; - strMessage += "\n---------------------------------------------\nAbort - terminate application\nRetry - continue running the application\nIgnore - don't show this message box any more"; - switch (::MessageBox(NULL, strMessage.c_str(), "CryEngine Warning", MB_ABORTRETRYIGNORE | MB_DEFBUTTON2 | MB_ICONWARNING | MB_SYSTEMMODAL)) - { - case IDABORT: - m_pSystem->GetIConsole()->Exit ("User abort requested during showing the warning box with the following message: %s", record.text); - break; - case IDRETRY: - break; - case IDIGNORE: - bNoMsgBoxOnWarnings = true; - m_pSystem->m_sysWarnings->Set(0); - break; - } -#endif - } - } - } -}; - -#endif // CRYINCLUDE_CRYSYSTEM_VALIDATOR_H diff --git a/Code/CryEngine/CrySystem/WindowsConsole.cpp b/Code/CryEngine/CrySystem/WindowsConsole.cpp deleted file mode 100644 index c83606890e..0000000000 --- a/Code/CryEngine/CrySystem/WindowsConsole.cpp +++ /dev/null @@ -1,1153 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : CWindowsConsole member definitions - - -#include "CrySystem_precompiled.h" -#include "System.h" -#include "WindowsConsole.h" - -#ifdef USE_WINDOWSCONSOLE - -#define WINDOWS_CONSOLE_WIDTH 128 -#define WINDOWS_CONSOLE_HEIGHT 50 -#define WINDOWS_CONSOLE_LOG_BUFFER_LINES 1024 -#define WINDOWS_CONSOLE_LOG_SCROLL_LINES 10 -#define WINDOWS_CONSOLE_TAB_SIZE 4 -#define WINDOWS_CONSOLE_CRYENGINE_BLACK 0x0 -#define WINDOWS_CONSOLE_CRYENGINE_WHITE 0x1 -#define WINDOWS_CONSOLE_CRYENGINE_BLUE 0x2 -#define WINDOWS_CONSOLE_CRYENGINE_GREEN 0x3 -#define WINDOWS_CONSOLE_CRYENGINE_RED 0x4 -#define WINDOWS_CONSOLE_CRYENGINE_CYAN 0x5 -#define WINDOWS_CONSOLE_CRYENGINE_YELLOW 0x6 -#define WINDOWS_CONSOLE_CRYENGINE_MAGENTA 0x7 -#define WINDOWS_CONSOLE_CRYENGINE_ORANGE 0x8 -#define WINDOWS_CONSOLE_CRYENGINE_GREY 0x9 -#define WINDOWS_CONSOLE_NATIVE_BLACK 0x0 -#define WINDOWS_CONSOLE_NATIVE_BROWN 0x6 -#define WINDOWS_CONSOLE_NATIVE_LIGHTGREY 0x7 -#define WINDOWS_CONSOLE_NATIVE_LIGHTBLUE 0x9 -#define WINDOWS_CONSOLE_NATIVE_LIGHTGREEN 0xA -#define WINDOWS_CONSOLE_NATIVE_LIGHTCYAN 0xB -#define WINDOWS_CONSOLE_NATIVE_LIGHTRED 0xC -#define WINDOWS_CONSOLE_NATIVE_LIGHTMAGENTA 0xD -#define WINDOWS_CONSOLE_NATIVE_YELLOW 0xE -#define WINDOWS_CONSOLE_NATIVE_WHITE 0xF -#define WINDOWS_CONSOLE_COLOR_MASK 0xF -#define WINDOWS_CONSOLE_BGCOLOR_SHIFT 4 - -const uint8 CWindowsConsole::s_colorTable[ WINDOWS_CONSOLE_NUM_CRYENGINE_COLORS ] = -{ - WINDOWS_CONSOLE_NATIVE_BLACK, - WINDOWS_CONSOLE_NATIVE_WHITE, - WINDOWS_CONSOLE_NATIVE_LIGHTBLUE, - WINDOWS_CONSOLE_NATIVE_LIGHTGREEN, - WINDOWS_CONSOLE_NATIVE_LIGHTRED, - WINDOWS_CONSOLE_NATIVE_LIGHTCYAN, - WINDOWS_CONSOLE_NATIVE_YELLOW, - WINDOWS_CONSOLE_NATIVE_LIGHTMAGENTA, - WINDOWS_CONSOLE_NATIVE_BROWN, - WINDOWS_CONSOLE_NATIVE_LIGHTGREY -}; - -CWindowsConsole::CWindowsConsole() - : m_lock() - , m_consoleScreenBufferSize() - , m_consoleWindow() - , m_inputBufferHandle(INVALID_HANDLE_VALUE) - , m_screenBufferHandle(INVALID_HANDLE_VALUE) - , m_logBuffer(0, 0, WINDOWS_CONSOLE_WIDTH, WINDOWS_CONSOLE_HEIGHT - 2, WINDOWS_CONSOLE_LOG_BUFFER_LINES, L' ', WINDOWS_CONSOLE_CRYENGINE_GREY, WINDOWS_CONSOLE_CRYENGINE_BLACK) - , m_fullScreenBuffer(0, 0, WINDOWS_CONSOLE_WIDTH, WINDOWS_CONSOLE_HEIGHT - 2, WINDOWS_CONSOLE_HEIGHT - 2, L' ', WINDOWS_CONSOLE_CRYENGINE_GREY, WINDOWS_CONSOLE_CRYENGINE_BLACK) - , m_statusBuffer(0, WINDOWS_CONSOLE_HEIGHT - 2, WINDOWS_CONSOLE_WIDTH, 1, 1, L' ', WINDOWS_CONSOLE_CRYENGINE_BLACK, WINDOWS_CONSOLE_CRYENGINE_GREY) - , m_commandBuffer(0, WINDOWS_CONSOLE_HEIGHT - 1, WINDOWS_CONSOLE_WIDTH, 1, 1, L' ', WINDOWS_CONSOLE_CRYENGINE_WHITE, WINDOWS_CONSOLE_CRYENGINE_BLACK) - , m_dirtyCellBuffers(0) - , m_commandQueue() - , m_commandPrompt("] ") - , m_commandPromptLength(m_commandPrompt.length()) - , m_command() - , m_commandCursor(0) - , m_logLine() - , m_progressString() - , m_header() - , m_updStats() - , m_pInputThread(NULL) - , m_pSystem(NULL) - , m_pConsole(NULL) - , m_pTimer(NULL) - , m_pCVarSvMap(NULL) - , m_pCVarSvMission(NULL) - , m_pCVarSvGameRules(NULL) - , m_lastStatusUpdate() - , m_lastUpdateTime() - , m_initialized(false) - , m_OnUpdateCalled(false) - , m_requireDedicatedServer(false) -{ -} - -CWindowsConsole::~CWindowsConsole() -{ - CleanUp(); -} - -Vec2_tpl< int > CWindowsConsole::BeginDraw() -{ - m_newCmds.resize(0); - return Vec2_tpl< int >(WINDOWS_CONSOLE_WIDTH, WINDOWS_CONSOLE_HEIGHT - 2); -} - -void CWindowsConsole::PutText(int x, int y, const char* pMsg) -{ - SConDrawCmd cmd; - - cmd.x = x; - cmd.y = y; - cry_strcpy(cmd.text, pMsg); - m_newCmds.push_back(cmd); -} - -void CWindowsConsole::EndDraw() -{ - Lock(); - m_drawCmds.swap(m_newCmds); - Unlock(); -} - -void CWindowsConsole::SetTitle(const char* title) -{ - m_title = title; - - if (m_title.empty()) - { - SetConsoleTitle(m_header.c_str()); - } - else - { - stack_string fullHeader = m_title + " - " + m_header; - SetConsoleTitle(fullHeader); - } -} - -void CWindowsConsole::Print(const char* pInszText) -{ - Lock(); - - bool isContinue = true; - const char* pInszTextPtr = pInszText; - const char* pLogLinePtr = m_logLine.c_str(); - - while (*pLogLinePtr && isContinue) - { - if (*pInszTextPtr != *pLogLinePtr) - { - isContinue = false; - } - - ++pInszTextPtr; - ++pLogLinePtr; - } - - // Do not treat lines as equal if the new line starts the same as the previous line - isContinue = isContinue && (*pInszTextPtr == 0 || m_logLine.empty()); - - if (!isContinue) - { - pInszTextPtr = pInszText; - m_logBuffer.NewLine(); - m_logLine.clear(); - } - - m_logLine.append(pInszTextPtr); - m_logBuffer.Print(pInszTextPtr); - m_dirtyCellBuffers |= eCBB_Log; - - Unlock(); -} - -bool CWindowsConsole::OnError([[maybe_unused]] const char* szErrorString) -{ - return true; -} - -bool CWindowsConsole::OnSaveDocument() -{ - return false; -} - -bool CWindowsConsole::OnBackupDocument() -{ - return false; -} - -void CWindowsConsole::OnProcessSwitch() -{ -} - -void CWindowsConsole::OnInitProgress(const char* sProgressMsg) -{ - if (m_initialized) - { - Lock(); - m_progressString = sProgressMsg; - DrawStatus(); - Unlock(); - } -} - -// the CtrlHandler will be called from a separate thread that only handles -// Ctrl messages. When the CLOSE event is sent, this function can just wait -// forever, as FreeConsole() will kill the thread. If this function returns -// immediately, windows will call TerminateProcess() and nothing will be cleaned up. -static BOOL WINAPI CtrlHandler(DWORD ctrlEvent) -{ - switch (ctrlEvent) - { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - return TRUE; - case CTRL_CLOSE_EVENT: - if ( (gEnv != nullptr) && (gEnv->pSystem != nullptr) && (gEnv->pSystem->GetIConsole() != nullptr) ) - { - gEnv->pSystem->GetIConsole()->ExecuteString("quit", true, true); - Sleep(INFINITE); - return TRUE; - } - default: - break; - } - return FALSE; -} - -void CWindowsConsole::OnInit(ISystem* pSystem) -{ - if (m_requireDedicatedServer && !gEnv->IsDedicated()) - { - return; - } - - Lock(); - - if (!m_initialized) - { - assert(m_pSystem == NULL); - assert(m_pConsole == NULL); - - m_pSystem = pSystem; - m_pConsole = pSystem->GetIConsole(); - - AllocConsole(); - m_inputBufferHandle = GetStdHandle(STD_INPUT_HANDLE); - m_screenBufferHandle = GetStdHandle(STD_OUTPUT_HANDLE); - SetConsoleMode(m_inputBufferHandle, ENABLE_WINDOW_INPUT); - m_consoleScreenBufferSize.X = WINDOWS_CONSOLE_WIDTH; - m_consoleScreenBufferSize.Y = WINDOWS_CONSOLE_HEIGHT; - m_consoleWindow.Left = 0; - m_consoleWindow.Top = 0; - m_consoleWindow.Right = WINDOWS_CONSOLE_WIDTH - 1; - m_consoleWindow.Bottom = WINDOWS_CONSOLE_HEIGHT - 1; - SetConsoleScreenBufferSize(m_screenBufferHandle, m_consoleScreenBufferSize); - SetConsoleWindowInfo(m_screenBufferHandle, TRUE, &m_consoleWindow); - SetConsoleTitle(m_header.c_str()); - - if (m_pConsole) - { - m_pConsole->AddOutputPrintSink(this); - } - - DrawCommand(); - - m_pInputThread = new CWindowsConsoleInputThread(*this); - m_pInputThread->Start(); - -#if !defined(NDEBUG) - BOOL handlerInstalled = -#endif - SetConsoleCtrlHandler(CtrlHandler, TRUE); - CRY_ASSERT(handlerInstalled); - - m_initialized = true; - } - - Unlock(); -} - -void CWindowsConsole::OnShutdown() -{ - CleanUp(); -} - -void CWindowsConsole::OnUpdate() -{ - if (m_initialized) - { - Lock(); - - bool updateStatus = false; - - if (!m_OnUpdateCalled) - { - assert(m_pCVarSvMap == NULL); - assert(m_pCVarSvGameRules == NULL); - assert(m_pTimer == NULL); - - m_pCVarSvMap = m_pConsole->GetCVar("sv_map"); - m_pCVarSvGameRules = m_pConsole->GetCVar("sv_gamerules"); - m_pTimer = m_pSystem->GetITimer(); - m_OnUpdateCalled = true; - - assert(m_pCVarSvMission == NULL); - m_pCVarSvMission = m_pConsole->GetCVar("sv_mission"); - } - - if (!m_progressString.empty()) - { - m_progressString.clear(); - updateStatus = true; - } - - CTimeValue now = m_pTimer->GetAsyncTime(); - - if ((now - m_lastStatusUpdate).GetSeconds() > 0.1F) - { - updateStatus = true; - } - - m_lastUpdateTime = now; - - m_pSystem->GetUpdateStats(m_updStats); - - if (updateStatus) - { - DrawStatus(); - m_lastStatusUpdate = now; - } - - while (m_commandQueue.size()) - { - const string& command = m_commandQueue[0]; - Unlock(); - // 'm_pConsole' will be set to NULL when executing 'quit' command - // Cache pointer in local variable to prevent crash when adding the last command to the history - IConsole* pConsole = m_pConsole; - pConsole->ExecuteString(command.c_str()); - pConsole->AddCommandToHistory(command.c_str()); - Lock(); - m_commandQueue.pop_front(); - } - - if (!m_drawCmds.empty()) - { - DrawFull(); - } - - Repaint(); - - Unlock(); - } -} - -void CWindowsConsole::OnConsoleInputEvent(INPUT_RECORD inputRecord) -{ - switch (inputRecord.EventType) - { - case KEY_EVENT: - OnKey(inputRecord.Event.KeyEvent); - break; - case WINDOW_BUFFER_SIZE_EVENT: - OnResize(inputRecord.Event.WindowBufferSizeEvent.dwSize); - break; - } -} - -void CWindowsConsole::OnKey(const KEY_EVENT_RECORD& event) -{ - if (event.bKeyDown) - { - for (uint32 i = 0; i < event.wRepeatCount; ++i) - { - switch (event.wVirtualKeyCode) - { - case VK_BACK: - OnBackspace(); - break; - case VK_TAB: - OnTab(); - break; - case VK_RETURN: - OnReturn(); - break; - case VK_PRIOR: - OnPgUp(); - break; - case VK_NEXT: - OnPgDn(); - break; - case VK_LEFT: - OnLeft(); - break; - case VK_UP: - OnUp(); - break; - case VK_RIGHT: - OnRight(); - break; - case VK_DOWN: - OnDown(); - break; - case VK_DELETE: - OnDelete(); - break; - default: - OnChar(event.uChar.AsciiChar); - break; - } - } - } -} - -void CWindowsConsole::OnResize(const COORD& size) -{ - if ((size.X != m_consoleScreenBufferSize.X) || (size.Y != m_consoleScreenBufferSize.Y)) - { - SetConsoleScreenBufferSize(m_screenBufferHandle, m_consoleScreenBufferSize); - SetConsoleWindowInfo(m_screenBufferHandle, TRUE, &m_consoleWindow); - } -} - -void CWindowsConsole::OnBackspace() -{ - if (m_commandCursor > 0) - { - m_command.erase(--m_commandCursor, 1); - m_pConsole->ResetAutoCompletion(); - DrawCommand(); - } -} - -void CWindowsConsole::OnTab() -{ - const char* pCompletion; - - pCompletion = m_pConsole->ProcessCompletion(m_command.c_str()); - - if (pCompletion) - { - m_command = pCompletion; - m_commandCursor = m_command.length(); - DrawCommand(); - } -} - -void CWindowsConsole::OnReturn() -{ - m_commandQueue.push_back(m_command); - m_command.clear(); - m_pConsole->ResetAutoCompletion(); - m_commandCursor = 0; - DrawCommand(); -} - -void CWindowsConsole::OnPgUp() -{ - if (m_logBuffer.Scroll(-WINDOWS_CONSOLE_LOG_SCROLL_LINES)) - { - m_dirtyCellBuffers |= eCBB_Log; - } -} - -void CWindowsConsole::OnPgDn() -{ - if (m_logBuffer.Scroll(WINDOWS_CONSOLE_LOG_SCROLL_LINES)) - { - m_dirtyCellBuffers |= eCBB_Log; - } -} - -void CWindowsConsole::OnLeft() -{ - if (m_commandCursor > 0) - { - --m_commandCursor; - m_commandBuffer.SetCursor(m_screenBufferHandle, m_commandCursor + m_commandPromptLength); - } -} - -void CWindowsConsole::OnUp() -{ - OnHistory(m_pConsole->GetHistoryElement(true)); -} - -void CWindowsConsole::OnRight() -{ - if (m_commandCursor < m_command.length()) - { - ++m_commandCursor; - m_commandBuffer.SetCursor(m_screenBufferHandle, m_commandCursor + m_commandPromptLength); - } -} - -void CWindowsConsole::OnDown() -{ - OnHistory(m_pConsole->GetHistoryElement(false)); -} - -void CWindowsConsole::OnDelete() -{ - if (m_commandCursor < m_command.length()) - { - m_command.erase(m_commandCursor, 1); - m_pConsole->ResetAutoCompletion(); - DrawCommand(); - } -} - -void CWindowsConsole::OnChar(CHAR ch) -{ - if ((ch >= ' ') && (ch <= '~')) - { - m_command.insert(m_commandCursor++, ch); - m_pConsole->ResetAutoCompletion(); - DrawCommand(); - } -} - -void CWindowsConsole::OnHistory(const char* pHistoryElement) -{ - if (pHistoryElement) - { - m_command = pHistoryElement; - } - else - { - m_command.clear(); - } - - m_commandCursor = m_command.length(); - DrawCommand(); -} - -void CWindowsConsole::DrawCommand() -{ - m_commandBuffer.Clear(); - m_commandBuffer.PutText(0, 0, m_commandPrompt.c_str()); - m_commandBuffer.PutText(m_commandPromptLength, 0, m_command); - m_commandBuffer.SetCursor(m_screenBufferHandle, m_commandCursor + m_commandPromptLength); - m_dirtyCellBuffers |= eCBB_Command; -} - -void CWindowsConsole::GetMemoryUsage(ICrySizer* pSizer) -{ - pSizer->Add(this); - pSizer->Add(m_command); - pSizer->Add(m_logLine); - pSizer->Add(m_pInputThread); - m_logBuffer.GetMemoryUsage(pSizer); - m_fullScreenBuffer.GetMemoryUsage(pSizer); - m_statusBuffer.GetMemoryUsage(pSizer); - m_commandBuffer.GetMemoryUsage(pSizer); -} - -void CWindowsConsole::SetRequireDedicatedServer(bool value) -{ - m_requireDedicatedServer = value; -} - -void CWindowsConsole::SetHeader(const char* pHeader) -{ - m_header = pHeader; - SetConsoleTitle(pHeader); -} - -void CWindowsConsole::InputIdle() -{ - if (m_pTimer) - { - CTimeValue now = m_pTimer->GetAsyncTime(); - float timePassed = (now - m_lastUpdateTime).GetSeconds(); - - if (timePassed > 0.2F) - { - int nDots = ( int )(timePassed + 0.5) / 3; - int nDotsMax = m_statusBuffer.Width() - 2; - - if (nDots > nDotsMax) - { - nDots = nDotsMax; - } - - if (m_progressString.length() != nDots) - { - m_progressString.clear(); - m_progressString.append(nDots, '.'); - DrawStatus(); - } - } - } - - Repaint(); -} - -void CWindowsConsole::Lock() -{ - m_lock.Lock(); -} - -void CWindowsConsole::Unlock() -{ - m_lock.Unlock(); -} - -bool CWindowsConsole::TryLock() -{ - return m_lock.TryLock(); -} - -void CWindowsConsole::Repaint() -{ - if (m_dirtyCellBuffers) - { - if (m_dirtyCellBuffers & eCBB_Full) - { - m_fullScreenBuffer.Blit(m_screenBufferHandle); - m_dirtyCellBuffers &= ~eCBB_Full; - } - else if (m_dirtyCellBuffers & eCBB_Log) - { - m_logBuffer.Blit(m_screenBufferHandle); - m_dirtyCellBuffers &= ~eCBB_Log; - } - - if (m_dirtyCellBuffers & eCBB_Status) - { - m_statusBuffer.Blit(m_screenBufferHandle); - m_dirtyCellBuffers &= ~eCBB_Status; - } - - if (m_dirtyCellBuffers & eCBB_Command) - { - m_commandBuffer.Blit(m_screenBufferHandle); - m_dirtyCellBuffers &= ~eCBB_Command; - } - } -} - -void CWindowsConsole::DrawStatus() -{ - const char* pStatusLeft = NULL; - const char* pStatusRight = NULL; - char bufferLeft[ 256 ]; - char bufferRight[ 256 ]; - - // If we're scrolled, then the right size shows a scroll indicator. - if (m_logBuffer.IsScrolledUp()) - { - m_logBuffer.FmtScrollStatus(sizeof bufferRight, bufferRight); - bufferRight[ sizeof bufferRight - 1 ] = 0; - pStatusRight = bufferRight; - } - - if (!m_progressString.empty()) - { - azsnprintf(bufferLeft, sizeof bufferLeft, " %s", m_progressString.c_str()); - bufferLeft [sizeof bufferLeft - 1 ] = 0; - pStatusLeft = bufferLeft; - } - else if (m_OnUpdateCalled) - { - // Standard status display. - // Map name and game rules on the left. - // Current update rate and player count on the right. - - const char* pMapName = m_pCVarSvMap->GetString(); - - const char* pMissionName = m_pCVarSvMission ? m_pCVarSvMission->GetString() : ""; - azsnprintf(bufferLeft, sizeof bufferLeft, " mission: %s map:%s", pMissionName, pMapName); - - bufferLeft[ sizeof bufferLeft - 1 ] = 0; - pStatusLeft = bufferLeft; - - if (!pStatusRight) - { - float updateRate = 0.f; - - if (m_pTimer != NULL) - { - updateRate = m_pTimer->GetFrameRate(); - } - else - { - updateRate = 0.f; - } - - char* pBufferRight = bufferRight; - char* const pBufferRightEnd = bufferRight + sizeof bufferRight; - - azstrcpy(pBufferRight, AZ_ARRAY_SIZE(bufferRight), "| "); - pBufferRight += strlen(pBufferRight); - - if (pBufferRight < pBufferRightEnd) - { - if (m_pConsole != NULL) - { - pBufferRight += azsnprintf( - pBufferRight, - pBufferRightEnd - pBufferRight, - "upd:%.1fms(%.2f..%.2f) " \ - "rate:%.1f/s", - m_updStats.avgUpdateTime, m_updStats.minUpdateTime, m_updStats.maxUpdateTime, - updateRate); - } - else - { - cry_strcpy(pBufferRight, pBufferRightEnd - pBufferRight, "BUSY "); - } - } - - bufferRight[ sizeof bufferRight - 1 ] = 0; - pStatusRight = bufferRight; - } - } - - if (pStatusLeft == NULL) - { - pStatusLeft = ""; - } - - if (pStatusRight == NULL) - { - pStatusRight = ""; - } - - int rightWidth = strlen(pStatusRight); - - m_statusBuffer.Clear(); - m_statusBuffer.PutText(0, 0, pStatusLeft); - m_statusBuffer.PutText(-rightWidth, 0, pStatusRight); - m_dirtyCellBuffers |= eCBB_Status; -} - -void CWindowsConsole::CleanUp() -{ - Lock(); - - if (m_initialized) - { - if (m_pInputThread) - { - m_pInputThread->Cancel(); - - // The input thread may continue to lock before it gets our cancel event, so - // we need to release the lock until we confirm that it has canceled its operations. - Unlock(); - m_pInputThread->WaitForThread(); - Lock(); - - delete m_pInputThread; - m_pInputThread = NULL; - } - - if (m_pConsole) - { - m_pConsole->RemoveOutputPrintSink(this); - } - - m_pSystem = NULL; - m_pConsole = NULL; - m_pTimer = NULL; - m_pCVarSvMap = NULL; - m_pCVarSvGameRules = NULL; - m_inputBufferHandle = INVALID_HANDLE_VALUE; - m_screenBufferHandle = INVALID_HANDLE_VALUE; - m_initialized = false; - } - - Unlock(); -} - -void CWindowsConsole::DrawFull() -{ - for (DynArray< SConDrawCmd >::iterator iter = m_drawCmds.begin(); iter != m_drawCmds.end(); ++iter) - { - m_fullScreenBuffer.PutText(iter->x, iter->y, iter->text); - } - - m_dirtyCellBuffers |= eCBB_Full; -} - -CWindowsConsole::CCellBuffer::CCellBuffer(SHORT x, short y, SHORT w, SHORT h, SHORT lines, WCHAR emptyChar, uint8 defaultFgColor, uint8 defaultBgColor) -{ - m_emptyCell.Char.UnicodeChar = emptyChar; - m_emptyCell.Attributes = s_colorTable[ defaultFgColor ] | (s_colorTable[ defaultBgColor ] << WINDOWS_CONSOLE_BGCOLOR_SHIFT); - m_attr = m_emptyCell.Attributes; - m_size.X = w; - m_size.Y = lines; - m_screenArea.Left = x; - m_screenArea.Top = y; - m_screenArea.Right = x + w - 1; - m_screenArea.Bottom = y + h - 1; - m_position.head = 0; - m_position.lines = 1; - m_position.wrap = 0; - m_position.offset = 0; - m_position.scroll = 0; - m_escape = false; - m_color = false; - m_buffer.resize(w * lines, m_emptyCell); -} - -CWindowsConsole::CCellBuffer::~CCellBuffer() -{ -} - -void CWindowsConsole::CCellBuffer::PutText(int x, int y, const char* pMsg) -{ - SPosition position; - - position.head = m_position.head; - position.offset = x; - position.lines = y; - position.scroll = 0; - position.wrap = 0; - - if (position.offset < 0) - { - position.offset += m_screenArea.Right - 1; - } - - if (position.lines < 0) - { - position.lines += m_screenArea.Bottom - 1; - } - - Print(pMsg, position); -} - -void CWindowsConsole::CCellBuffer::Print(const char* pInszText) -{ - Print(pInszText, m_position); -} - -void CWindowsConsole::CCellBuffer::ClearCells(TBuffer::iterator pDst, TBuffer::iterator pDstEnd) -{ - std::fill(pDst, pDstEnd, m_emptyCell); -} - -bool CWindowsConsole::CCellBuffer::Scroll(SHORT numLines) -{ - bool result = false; - SHORT newScroll = m_position.scroll + numLines; - SHORT maxScroll = m_position.lines - 1 - (m_screenArea.Bottom - m_screenArea.Top); - - if (newScroll > maxScroll) - { - newScroll = maxScroll; - } - - if (newScroll < 0) - { - newScroll = 0; - } - - if (newScroll != m_position.scroll) - { - m_position.scroll = newScroll; - result = true; - } - - return result; -} - -void CWindowsConsole::CCellBuffer::SetCursor(HANDLE hScreenBuffer, SHORT offset) -{ - COORD position; - - position.X = m_screenArea.Left + offset; - position.Y = m_screenArea.Top; - SetConsoleCursorPosition(hScreenBuffer, position); -} - -void CWindowsConsole::CCellBuffer::AddCharacter(WCHAR ch, SPosition& position) -{ - if (position.offset == m_size.X) - { - WrapLine(position); - } - - int32 index = (((position.head + position.lines + m_size.Y - 1) % m_size.Y) * m_size.X) + position.offset; - - CHAR_INFO& info = m_buffer[ index ]; - - info.Attributes = m_attr; - info.Char.UnicodeChar = ch; - ++position.offset; -} - -void CWindowsConsole::CCellBuffer::WrapLine(SPosition& position) -{ - ++position.wrap; - AdvanceLine(position); -} - -void CWindowsConsole::CCellBuffer::NewLine() -{ - NewLine(m_position); -} - -void CWindowsConsole::CCellBuffer::NewLine(SPosition& position) -{ - m_attr = m_emptyCell.Attributes; - position.wrap = 0; - AdvanceLine(position); -} - -void CWindowsConsole::CCellBuffer::ClearLine(SPosition& position) -{ - ClearCells(m_buffer.begin() + ((position.head + position.lines - position.wrap) % m_size.Y) * m_size.X, m_buffer.begin() + ((position.head + position.lines + 1) % m_size.Y) * m_size.X); - position.lines -= position.wrap; - position.wrap = 0; - position.offset = 0; -} - -void CWindowsConsole::CCellBuffer::Tab(SPosition& position) -{ - do - { - AddCharacter(' ', position); - } while (position.offset % WINDOWS_CONSOLE_TAB_SIZE); -} - -void CWindowsConsole::CCellBuffer::Blit(HANDLE hScreenBuffer) -{ - COORD src; - SMALL_RECT dst; - - src.X = 0; - src.Y = (m_position.head + m_position.scroll) % m_size.Y; - dst = m_screenArea; - WriteConsoleOutput(hScreenBuffer, &*m_buffer.begin(), m_size, src, &dst); - - if ((m_size.Y - src.Y) < (m_screenArea.Bottom - m_screenArea.Top + 1)) - { - src.Y = 0; - dst.Top = dst.Bottom + 1; - dst.Bottom = m_screenArea.Bottom; - WriteConsoleOutput(hScreenBuffer, &*m_buffer.begin(), m_size, src, &dst); - } -} - -void CWindowsConsole::CCellBuffer::AdvanceLine(SPosition& position) -{ - position.offset = 0; - - if (position.lines == m_size.Y) - { - position.head = (position.head + 1) % m_size.Y; - } - else - { - ++position.lines; - - if (position.lines > m_screenArea.Bottom - m_screenArea.Top + 1) - { - ++position.scroll; - } - } - - TBuffer::iterator start = m_buffer.begin() + ((position.head + position.lines + m_size.Y - 1) % m_size.Y) * m_size.X; - TBuffer::iterator end = start + m_size.X; - - ClearCells(start, end); -} - -void CWindowsConsole::CCellBuffer::SetFgColor(WORD color) -{ - m_attr = (m_attr & ~WINDOWS_CONSOLE_COLOR_MASK) | s_colorTable[ color ]; -} - -void CWindowsConsole::CCellBuffer::Print(const char* pInszText, SPosition& position) -{ - while (*pInszText) - { - switch (*pInszText) - { - case '$': - if (!m_escape) - { - m_color = true; - break; - } - case '\\': - m_escape = !m_escape; - if (m_escape) - { - break; - } - case 'n': - if (m_escape) - { - case '\n': - NewLine(position); - m_escape = false; - break; - } - case 'r': - if (m_escape) - { - case '\r': - ClearLine(position); - m_escape = false; - break; - } - case 't': - if (m_escape) - { - case '\t': - Tab(position); - m_escape = false; - break; - } - default: - if (m_color) - { - if (isdigit(*pInszText)) - { - SetFgColor(*pInszText - '0'); - } - - m_color = false; - } - else - { - if (m_escape && (*pInszText != '\\')) - { - AddCharacter('\\', position); - } - AddCharacter(*pInszText, position); - } - m_escape = false; - break; - } - - ++pInszText; - } -} - -void CWindowsConsole::CCellBuffer::GetMemoryUsage(ICrySizer* pSizer) -{ - pSizer->Add(m_buffer); -} - -bool CWindowsConsole::CCellBuffer::IsScrolledUp() -{ - return (m_position.lines - m_position.scroll) > (m_screenArea.Bottom - m_screenArea.Top + 1); -} - -void CWindowsConsole::CCellBuffer::FmtScrollStatus(uint32 size, char* pBuffer) -{ - if (m_position.scroll) - { - azsnprintf(pBuffer, size, "| SCROLL: %.1f%%", 100.0F * static_cast< float >(m_position.scroll) / static_cast< float >(m_position.lines - (m_screenArea.Bottom - m_screenArea.Top + 1))); - } - else - { - cry_strcpy(pBuffer, size, "| SCROLL:TOP "); - } -} - -void CWindowsConsole::CCellBuffer::Clear() -{ - ClearCells(m_buffer.begin(), m_buffer.end()); -} - -SHORT CWindowsConsole::CCellBuffer::Width() -{ - return m_screenArea.Right - m_screenArea.Left + 1; -} - - -CWindowsConsoleInputThread::CWindowsConsoleInputThread(CWindowsConsole& console) - : m_WindowsConsole(console) -{ - m_handles[ eWH_Event ] = CreateEvent(NULL, TRUE, FALSE, NULL); - m_handles[ eWH_Console ] = m_WindowsConsole.m_inputBufferHandle; -} - -CWindowsConsoleInputThread::~CWindowsConsoleInputThread() -{ - CloseHandle(m_handles[ eWH_Event ]); -} - -void CWindowsConsoleInputThread::Run() -{ - bool cancelled = false; - - do - { - DWORD inputRecordCount = 0; - DWORD waitResult; - - waitResult = WaitForMultipleObjects(eWH_NumWaitHandles, m_handles, FALSE, 100); - - switch (waitResult) - { - case WAIT_OBJECT_0 + eWH_Event: - - cancelled = true; - break; - - case WAIT_OBJECT_0 + eWH_Console: - - ReadConsoleInput(m_WindowsConsole.m_inputBufferHandle, m_inputRecords, WINDOWS_CONSOLE_MAX_INPUT_RECORDS, &inputRecordCount); - - // FALL THROUGH - - case WAIT_TIMEOUT: - - if (inputRecordCount || (m_WindowsConsole.m_dirtyCellBuffers && !m_WindowsConsole.m_OnUpdateCalled)) - { - m_WindowsConsole.Lock(); - - if (inputRecordCount) - { - PINPUT_RECORD pInputRecordEnd = m_inputRecords + inputRecordCount; - - for (PINPUT_RECORD pInputRecord = m_inputRecords; pInputRecord < pInputRecordEnd; ++pInputRecord) - { - m_WindowsConsole.OnConsoleInputEvent(*pInputRecord); - } - - m_WindowsConsole.DrawCommand(); - } - else - { - m_WindowsConsole.InputIdle(); - } - - m_WindowsConsole.Unlock(); - } - - break; - } - } while (!cancelled); -} - -void CWindowsConsoleInputThread::Cancel() -{ - SetEvent(m_handles[ eWH_Event ]); -} - -#endif // def USE_WINDOWSCONSOLE diff --git a/Code/CryEngine/CrySystem/WindowsConsole.h b/Code/CryEngine/CrySystem/WindowsConsole.h deleted file mode 100644 index cfecd06db2..0000000000 --- a/Code/CryEngine/CrySystem/WindowsConsole.h +++ /dev/null @@ -1,245 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : CWindowsConsole class definition - - -#ifndef CRYINCLUDE_CRYSYSTEM_WINDOWSCONSOLE_H -#define CRYINCLUDE_CRYSYSTEM_WINDOWSCONSOLE_H -#pragma once - - -#include -#include - -#if defined(USE_WINDOWSCONSOLE) - -class CWindowsConsole; -class CWindowsConsoleInputThread; - -#define WINDOWS_CONSOLE_MAX_INPUT_RECORDS 256 -#define WINDOWS_CONSOLE_NUM_CRYENGINE_COLORS 10 - -class CWindowsConsoleInputThread - : public CrySimpleThread<> -{ -public: - CWindowsConsoleInputThread(CWindowsConsole& console); - - ~CWindowsConsoleInputThread(); - - virtual void Run(); - virtual void Cancel(); - void Interrupt() - { - } - -private: - - enum EWaitHandle - { - eWH_Event, - eWH_Console, - eWH_NumWaitHandles - }; - - CWindowsConsole& m_WindowsConsole; - HANDLE m_handles[ eWH_NumWaitHandles ]; - INPUT_RECORD m_inputRecords[ WINDOWS_CONSOLE_MAX_INPUT_RECORDS ]; -}; - -class CWindowsConsole - : public ITextModeConsole - , public IOutputPrintSink - , public ISystemUserCallback -{ -public: - - CWindowsConsole(); - virtual ~CWindowsConsole(); - - // ITextModeConsole - virtual Vec2_tpl< int > BeginDraw(); - virtual void PutText(int x, int y, const char* pMsg); - virtual void EndDraw(); - virtual void SetTitle(const char* title); - - // ~ITextModeConsole - - // IOutputPrintSink - virtual void Print(const char* pInszText); - // ~IOutputPrintSink - - // ISystemUserCallback - virtual bool OnError(const char* szErrorString); - virtual bool OnSaveDocument(); - virtual bool OnBackupDocument(); - virtual void OnProcessSwitch(); - virtual void OnInitProgress(const char* sProgressMsg); - virtual void OnInit(ISystem* pSystem); - virtual void OnShutdown(); - virtual void OnUpdate(); - virtual void GetMemoryUsage(ICrySizer* pSizer); - // ~ISystemUserCallback - - void SetRequireDedicatedServer(bool value); - void SetHeader(const char* pHeader); - void InputIdle(); - -private: - - struct SConDrawCmd - { - int x; - int y; - char text[ 256 ]; - }; - - DynArray m_drawCmds; - DynArray m_newCmds; - - enum ECellBuffer - { - eCB_Log, - eCB_Full, - eCB_Status, - eCB_Command, - eCB_NumCellBuffers - }; - - enum ECellBufferBit - { - eCBB_Log = BIT(eCB_Log), - eCBB_Full = BIT(eCB_Full), - eCBB_Status = BIT(eCB_Status), - eCBB_Command = BIT(eCB_Command) - }; - - class CCellBuffer - { - public: - - CCellBuffer(SHORT x, short y, SHORT w, SHORT h, SHORT lines, WCHAR emptyChar, uint8 defaultFgColor, uint8 defaultBgColor); - ~CCellBuffer(); - - void PutText(int x, int y, const char* pMsg); - void Print(const char* pInszText); - void NewLine(); - void SetCursor(HANDLE hScreenBuffer, SHORT offset); - void SetFgColor(WORD color); - void Blit(HANDLE hScreenBuffer); - bool Scroll(SHORT numLines); - bool IsScrolledUp(); - void FmtScrollStatus(uint32 size, char* pBuffer); - void GetMemoryUsage(ICrySizer* pSizer); - void Clear(); - SHORT Width(); - - private: - - struct SPosition - { - SHORT head; - SHORT lines; - SHORT wrap; - SHORT offset; - SHORT scroll; - }; - - typedef std::vector< CHAR_INFO > TBuffer; - - void Print(const char* pInszText, SPosition& position); - void AddCharacter(WCHAR ch, SPosition& position); - void NewLine(SPosition& position); - void ClearLine(SPosition& position); - void Tab(SPosition& position); - void WrapLine(SPosition& position); - void AdvanceLine(SPosition& position); - void ClearCells(TBuffer::iterator pDst, TBuffer::iterator pDstEnd); - - TBuffer m_buffer; - CHAR_INFO m_emptyCell; - WORD m_attr; - COORD m_size; - SMALL_RECT m_screenArea; - SPosition m_position; - bool m_escape; - bool m_color; - }; - - void Lock(); - void Unlock(); - bool TryLock(); - void OnConsoleInputEvent(INPUT_RECORD inputRecord); - void OnKey(const KEY_EVENT_RECORD& event); - void OnResize(const COORD& size); - void OnBackspace(); - void OnTab(); - void OnReturn(); - void OnPgUp(); - void OnPgDn(); - void OnLeft(); - void OnUp(); - void OnRight(); - void OnDown(); - void OnDelete(); - void OnHistory(const char* pHistoryElement); - void OnChar(CHAR ch); - void DrawFull(); - void DrawStatus(); - void DrawCommand(); - void Repaint(); - void CleanUp(); - - CryCriticalSection m_lock; - COORD m_consoleScreenBufferSize; - SMALL_RECT m_consoleWindow; - HANDLE m_inputBufferHandle; - HANDLE m_screenBufferHandle; - CCellBuffer m_logBuffer; - CCellBuffer m_fullScreenBuffer; - CCellBuffer m_statusBuffer; - CCellBuffer m_commandBuffer; - uint32 m_dirtyCellBuffers; - std::deque< CryStringT< char > > m_commandQueue; - CryStringT< char > m_commandPrompt; - uint32 m_commandPromptLength; - CryStringT< char > m_command; - uint32 m_commandCursor; - CryStringT< char > m_logLine; - CryStringT< char > m_progressString; - CryStringT< char > m_header; - SSystemUpdateStats m_updStats; - CWindowsConsoleInputThread* m_pInputThread; - ISystem* m_pSystem; - IConsole* m_pConsole; - ITimer* m_pTimer; - ICVar* m_pCVarSvMap; - ICVar* m_pCVarSvMission; - CryStringT< char > m_title; - - ICVar* m_pCVarSvGameRules; - CTimeValue m_lastStatusUpdate; - CTimeValue m_lastUpdateTime; - bool m_initialized; - bool m_OnUpdateCalled; - bool m_requireDedicatedServer; - - static const uint8 s_colorTable[ WINDOWS_CONSOLE_NUM_CRYENGINE_COLORS ]; - - friend class CWindowsConsoleInputThread; -}; - -#endif // USE_WINDOWSCONSOLE - -#endif // CRYINCLUDE_CRYSYSTEM_WINDOWSCONSOLE_H diff --git a/Code/CryEngine/CrySystem/WindowsErrorReporting.cpp b/Code/CryEngine/CrySystem/WindowsErrorReporting.cpp deleted file mode 100644 index bd6f0c3ee2..0000000000 --- a/Code/CryEngine/CrySystem/WindowsErrorReporting.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : Support for Windows Error Reporting (WER) - - -#include "CrySystem_precompiled.h" - -#ifdef WIN32 - -#include "System.h" -#include -#include -#include "errorrep.h" -#include "ISystem.h" - -#include - -static WCHAR szPath[MAX_PATH + 1]; -static WCHAR szFR[] = L"\\System32\\FaultRep.dll"; - -WCHAR* GetFullPathToFaultrepDll(void) -{ - UINT rc = GetSystemWindowsDirectoryW(szPath, ARRAYSIZE(szPath)); - if (rc == 0 || rc > ARRAYSIZE(szPath) - ARRAYSIZE(szFR) - 1) - { - return NULL; - } - - wcscat_s(szPath, szFR); - return szPath; -} - - -typedef BOOL (WINAPI * MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, - CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, - CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, - CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam - ); - -////////////////////////////////////////////////////////////////////////// -LONG WINAPI CryEngineExceptionFilterMiniDump(struct _EXCEPTION_POINTERS* pExceptionPointers, const char* szDumpPath, MINIDUMP_TYPE DumpType) -{ - // note: In debug mode, this dll is loaded on startup anyway, so this should not incur an additional load unless it crashes - // very early during startup. - - fflush(nullptr); // according to MSDN on fflush, calling fflush on null flushes all buffers. - HMODULE hndDBGHelpDLL = LoadLibraryA("DBGHELP.DLL"); - - if (!hndDBGHelpDLL) - { - CryLogAlways("Failed to record DMP file: Could not open DBGHELP.DLL"); - return EXCEPTION_CONTINUE_SEARCH; - } - - MINIDUMPWRITEDUMP dumpFnPtr = (MINIDUMPWRITEDUMP)::GetProcAddress(hndDBGHelpDLL, "MiniDumpWriteDump"); - if (!dumpFnPtr) - { - CryLogAlways("Failed to record DMP file: Unable to find MiniDumpWriteDump in DBGHELP.DLL"); - return EXCEPTION_CONTINUE_SEARCH; - } - - HANDLE hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) - { - CryLogAlways("Failed to record DMP file: could not open file '%s' for writing - error code: %d", szDumpPath, GetLastError()); - return EXCEPTION_CONTINUE_SEARCH; - } - - _MINIDUMP_EXCEPTION_INFORMATION ExInfo; - ExInfo.ThreadId = ::GetCurrentThreadId(); - ExInfo.ExceptionPointers = pExceptionPointers; - ExInfo.ClientPointers = NULL; - - BOOL bOK = dumpFnPtr(GetCurrentProcess(), GetCurrentProcessId(), hFile, DumpType, &ExInfo, NULL, NULL); - ::CloseHandle(hFile); - - if (bOK) - { - CryLogAlways("Successfully recorded DMP file: '%s'", szDumpPath); - return EXCEPTION_EXECUTE_HANDLER; // SUCCESS! you can execute your handlers now - } - else - { - CryLogAlways("Failed to record DMP file: '%s' - error code: %d", szDumpPath, GetLastError()); - } - - return EXCEPTION_CONTINUE_SEARCH; -} - -/* -struct AutoSetCryEngineExceptionFilter -{ - AutoSetCryEngineExceptionFilter() - { - WCHAR * psz = GetFullPathToFaultrepDll(); - SetUnhandledExceptionFilter(CryEngineExceptionFilterWER); - } -}; -AutoSetCryEngineExceptionFilter g_AutoSetCryEngineExceptionFilter; -*/ - -////////////////////////////////////////////////////////////////////////// -LONG WINAPI CryEngineExceptionFilterWER(struct _EXCEPTION_POINTERS* pExceptionPointers) -{ - if (g_cvars.sys_WER > 1) - { - char szScratch [_MAX_PATH]; - const char* szDumpPath = gEnv->pCryPak->AdjustFileName("@log@/CE2Dump.dmp", szScratch, AZ_ARRAY_SIZE(szScratch), 0); - - MINIDUMP_TYPE mdumpValue = (MINIDUMP_TYPE)(MiniDumpNormal); - if (g_cvars.sys_WER > 1) - { - mdumpValue = (MINIDUMP_TYPE)(g_cvars.sys_WER - 2); - } - - return CryEngineExceptionFilterMiniDump(pExceptionPointers, szDumpPath, mdumpValue); - } - - LONG lRet = EXCEPTION_CONTINUE_SEARCH; - WCHAR* psz = GetFullPathToFaultrepDll(); - if (psz) - { - HMODULE hFaultRepDll = LoadLibraryW(psz); - if (hFaultRepDll) - { - pfn_REPORTFAULT pfn = (pfn_REPORTFAULT)GetProcAddress(hFaultRepDll, "ReportFault"); - if (pfn) - { - pfn(pExceptionPointers, 0); - lRet = EXCEPTION_EXECUTE_HANDLER; - } - FreeLibrary(hFaultRepDll); - } - } - return lRet; -} - - -#endif // WIN32 - diff --git a/Code/CryEngine/CrySystem/XML/XmlUtils.cpp b/Code/CryEngine/CrySystem/XML/XmlUtils.cpp index de5a14ecd7..d4feec04f2 100644 --- a/Code/CryEngine/CrySystem/XML/XmlUtils.cpp +++ b/Code/CryEngine/CrySystem/XML/XmlUtils.cpp @@ -272,7 +272,6 @@ void CXmlUtils::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wpar case ESYSTEM_EVENT_LEVEL_POST_UNLOAD: case ESYSTEM_EVENT_LEVEL_LOAD_END: g_pCXmlNode_PoolAlloc->FreeMemoryIfEmpty(); - STLALLOCATOR_CLEANUP; break; } } diff --git a/Code/CryEngine/CrySystem/ZLibCompressor.cpp b/Code/CryEngine/CrySystem/ZLibCompressor.cpp deleted file mode 100644 index 94d327940c..0000000000 --- a/Code/CryEngine/CrySystem/ZLibCompressor.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#include "CrySystem_precompiled.h" -#include "CryZlib.h" -#include "ZLibCompressor.h" -#include "TypeInfo_impl.h" -#include - -// keep these in sync with the enums in IZLibCompressor.h -static const int k_stratMap[] = {Z_DEFAULT_STRATEGY, Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE}; -static const int k_methodMap[] = {Z_DEFLATED}; -static const int k_flushMap[] = {Z_NO_FLUSH, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, Z_FULL_FLUSH}; - -struct CZLibDeflateStream - : public IZLibDeflateStream -{ -protected: - virtual ~CZLibDeflateStream(); - -protected: - z_stream m_compressStream; - int m_zSize; - int m_zPeak; - int m_level; - int m_windowBits; - int m_memLevel; - int m_zlibFlush; - int m_bytesInput; - int m_bytesOutput; - EZLibStrategy m_strategy; - EZLibMethod m_method; - EZDeflateState m_curState; - bool m_streamOpened; - - - static voidpf ZAlloc( - voidpf pInOpaque, - uInt inItems, - uInt inSize); - static void ZFree( - voidpf pInOpaque, - voidpf pInAddress); - - EZDeflateState RunDeflate(); - -public: - CZLibDeflateStream( - int inLevel, - EZLibMethod inMethod, - int inWindowBits, - int inMemLevel, - EZLibStrategy inStrategy, - EZLibFlush inFlushMethod); - - virtual void SetOutputBuffer( - char* pInBuffer, - int inSize); - virtual int GetBytesOutput(); - - virtual void Input( - const char* pInSource, - int inSourceSize); - virtual void EndInput(); - - virtual EZDeflateState GetState(); - - virtual void GetStats( - SStats* pOutStats); - - virtual void Release(); -}; - -inline static int Lookup(int inIndex, const int* pInValues, [[maybe_unused]] int inMaxValues) -{ - CRY_ASSERT_MESSAGE(inIndex >= 0 && inIndex < inMaxValues, "CZLibDeflateStream mapping invalid"); - return pInValues[inIndex]; -} - -IZLibDeflateStream* CZLibCompressor::CreateDeflateStream(int inLevel, EZLibMethod inMethod, int inWindowBits, int inMemLevel, EZLibStrategy inStrategy, EZLibFlush inFlushMethod) -{ - return new CZLibDeflateStream(inLevel, inMethod, inWindowBits, inMemLevel, inStrategy, inFlushMethod); -} - -void CZLibCompressor::Release() -{ - delete this; -} - -void CZLibCompressor::MD5Init(SMD5Context* pIOCtx) -{ - COMPILE_TIME_ASSERT(sizeof(*pIOCtx) == sizeof(MD5Context)); - - ::MD5Init((MD5Context*)pIOCtx); -} - -void CZLibCompressor::MD5Update(SMD5Context* pIOCtx, const char* pInBuff, unsigned int len) -{ - ::MD5Update((MD5Context*)pIOCtx, (unsigned char*)pInBuff, len); -} - -void CZLibCompressor::MD5Final(SMD5Context* pIOCtx, char outDigest[16]) -{ - ::MD5Final((unsigned char*)outDigest, (MD5Context*)pIOCtx); -} - -CZLibCompressor::~CZLibCompressor() -{ -} - -CZLibDeflateStream::CZLibDeflateStream( - int inLevel, - EZLibMethod inMethod, - int inWindowBits, - int inMemLevel, - EZLibStrategy inStrategy, - EZLibFlush inFlushMethod) - : m_zSize(0) - , m_zPeak(0) - , m_level(inLevel) - , m_windowBits(inWindowBits) - , m_memLevel(inMemLevel) - , m_bytesInput(0) - , m_bytesOutput(0) - , m_strategy(inStrategy) - , m_method(inMethod) - , m_curState(eZDefState_AwaitingInput) - , m_streamOpened(false) -{ - memset(&m_compressStream, 0, sizeof(m_compressStream)); - m_zlibFlush = Lookup(inFlushMethod, k_flushMap, ARRAY_COUNT(k_flushMap)); -} - -CZLibDeflateStream::~CZLibDeflateStream() -{ -} - -void CZLibDeflateStream::Release() -{ - if (m_streamOpened) - { - int err = deflateEnd(&m_compressStream); - if (err != Z_OK) - { - CryLog("zlib deflateEnd() error %d returned when closing stream", err); - } - } - delete this; -} - -void CZLibDeflateStream::SetOutputBuffer( - char* pInBuffer, - int inSize) -{ - m_bytesOutput += m_compressStream.total_out; - - m_compressStream.next_out = (byte*)pInBuffer; - m_compressStream.avail_out = inSize; - m_compressStream.total_out = 0; -} - -void CZLibDeflateStream::GetStats( - IZLibDeflateStream::SStats* pOutStats) -{ - pOutStats->bytesInput = m_bytesInput; - pOutStats->bytesOutput = m_bytesOutput + m_compressStream.total_out; - pOutStats->curMemoryUsed = m_zSize; - pOutStats->peakMemoryUsed = m_zPeak; -} - -int CZLibDeflateStream::GetBytesOutput() -{ - return m_compressStream.total_out; -} - -void CZLibDeflateStream::Input( - const char* pInSource, - int inSourceSize) -{ - CRY_ASSERT_MESSAGE(m_curState == eZDefState_AwaitingInput, "CZLibDeflateStream::Input() called when stream is not awaiting input"); - - m_compressStream.next_in = (Bytef*)pInSource; - m_compressStream.avail_in = inSourceSize; - m_bytesInput += inSourceSize; -} - -void CZLibDeflateStream::EndInput() -{ - CRY_ASSERT_MESSAGE(m_curState == eZDefState_AwaitingInput, "CZLibDeflateStream::EndInput() called when stream is not awaiting input"); - - m_zlibFlush = Z_FINISH; -} - -voidpf CZLibDeflateStream::ZAlloc( - voidpf pInOpaque, - uInt inItems, - uInt inSize) -{ - CZLibDeflateStream* pStr = reinterpret_cast(pInOpaque); - - int size = inItems * inSize; - - int* ptr = (int*) CryModuleMalloc(sizeof(int) + size); - if (ptr) - { - *ptr = inItems * inSize; - ptr += 1; - - int newSize = pStr->m_zSize + size; - pStr->m_zSize = newSize; - if (newSize > pStr->m_zPeak) - { - pStr->m_zPeak = newSize; - } - } - return ptr; -} - -void CZLibDeflateStream::ZFree( - voidpf pInOpaque, - voidpf pInAddress) -{ - int* pPtr = reinterpret_cast(pInAddress); - if (pPtr) - { - CZLibDeflateStream* pStr = reinterpret_cast(pInOpaque); - pStr->m_zSize -= pPtr[-1]; - CryModuleFree(pPtr - 1); - } -} - -EZDeflateState CZLibDeflateStream::RunDeflate() -{ - bool runDeflate = false; - bool inputAvailable = (m_compressStream.avail_in > 0) || (m_zlibFlush == Z_FINISH); - bool outputAvailable = (m_compressStream.avail_out > 0); - - switch (m_curState) - { - case eZDefState_AwaitingInput: - case eZDefState_ConsumeOutput: - if (inputAvailable && outputAvailable) - { - runDeflate = true; - } - else if (inputAvailable || !outputAvailable) - { - m_curState = eZDefState_ConsumeOutput; - } - else - { - m_curState = eZDefState_AwaitingInput; - } - break; - - case eZDefState_Finished: - break; - - case eZDefState_Deflating: - CRY_ASSERT_MESSAGE(0, "Shouldn't be trying to run deflate whilst a deflate is in progress"); - break; - - case eZDefState_Error: - break; - - default: - CRY_ASSERT_MESSAGE(0, "unknown state"); - break; - } - - if (runDeflate) - { - if (!m_streamOpened) - { - m_streamOpened = true; - - // initialising with deflateInit2 requires that the next_in be initialised - m_compressStream.zalloc = &CZLibDeflateStream::ZAlloc; - m_compressStream.zfree = &CZLibDeflateStream::ZFree; - m_compressStream.opaque = this; - - int error = deflateInit2(&m_compressStream, m_level, Lookup(m_method, k_methodMap, ARRAY_COUNT(k_methodMap)), m_windowBits, m_memLevel, Lookup(m_strategy, k_stratMap, ARRAY_COUNT(k_stratMap))); - if (error != Z_OK) - { - m_curState = eZDefState_Error; - CryLog("zlib deflateInit2() error, err %d", error); - } - } - - if (m_curState != eZDefState_Error) - { - int error = deflate(&m_compressStream, m_zlibFlush); - - if (error == Z_STREAM_END) - { - // end of stream has been generated, only produced if we pass Z_FINISH into deflate - m_curState = eZDefState_Finished; - } - else if ((error == Z_OK && m_compressStream.avail_out == 0) || (error == Z_BUF_ERROR && m_compressStream.avail_out == 0)) - { - // output buffer has been filled - // data should be available for consumption by caller - m_curState = eZDefState_ConsumeOutput; - } - else if (m_compressStream.avail_in == 0) - { - // ran out of input data - // data may be available for consumption - but we need more input right now - m_curState = eZDefState_AwaitingInput; - } - else - { - // some sort of error has occurred - m_curState = eZDefState_Error; - CryLog("zlib deflate() error, err %d", error); - } - } - } - - return m_curState; -} - -EZDeflateState CZLibDeflateStream::GetState() -{ - return RunDeflate(); -} diff --git a/Code/CryEngine/CrySystem/ZLibCompressor.h b/Code/CryEngine/CrySystem/ZLibCompressor.h deleted file mode 100644 index 4c026d965f..0000000000 --- a/Code/CryEngine/CrySystem/ZLibCompressor.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_ZLIBCOMPRESSOR_H -#define CRYINCLUDE_CRYSYSTEM_ZLIBCOMPRESSOR_H -#pragma once - - -#include "IZLibCompressor.h" - -class CZLibCompressor - : public IZLibCompressor -{ -protected: - virtual ~CZLibCompressor(); - -public: - virtual IZLibDeflateStream* CreateDeflateStream(int inLevel, EZLibMethod inMethod, int inWindowBits, int inMemLevel, EZLibStrategy inStrategy, EZLibFlush inFlushMethod); - virtual void Release(); - - virtual void MD5Init(SMD5Context* pIOCtx); - virtual void MD5Update(SMD5Context* pIOCtx, const char* pInBuff, unsigned int len); - virtual void MD5Final(SMD5Context * pIOCtx, char outDigest[16]); -}; - -#endif // CRYINCLUDE_CRYSYSTEM_ZLIBCOMPRESSOR_H diff --git a/Code/CryEngine/CrySystem/ZLibDecompressor.cpp b/Code/CryEngine/CrySystem/ZLibDecompressor.cpp deleted file mode 100644 index d75baf2c69..0000000000 --- a/Code/CryEngine/CrySystem/ZLibDecompressor.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -// Description : zlib inflate wrapper - - -#include "CrySystem_precompiled.h" - -#include "CryZlib.h" -#include "ZLibDecompressor.h" - -class CZLibInflateStream - : public IZLibInflateStream -{ -public: - CZLibInflateStream() - : m_bStreamOpened(false) - , m_zlibFlush(0) - , m_currentState(eZInfState_AwaitingInput) - , m_bytesInput(0) - , m_bytesOutput(0) - , m_zSize(0) - , m_zPeak(0) {} - - virtual void Release(); - - virtual void SetOutputBuffer(char* pInBuffer, unsigned int inSize); - virtual unsigned int GetBytesOutput(); - virtual void Input(const char* pInSource, unsigned int inSourceSize); - virtual void EndInput(); - virtual EZInflateState GetState(); - virtual void GetStats(IZLibInflateStream::SStats* pOutStats); - -private: - virtual ~CZLibInflateStream() {} - - EZInflateState RunInflate(); - - static voidpf ZAlloc(voidpf pInOpaque, uInt inItems, uInt inSize); - static void ZFree(voidpf pInOpaque, voidpf pInAddress); - - z_stream m_decompressStream; - bool m_bStreamOpened; - int m_zlibFlush; - EZInflateState m_currentState; - unsigned int m_bytesInput; - unsigned int m_bytesOutput; - unsigned int m_zSize; - unsigned int m_zPeak; -}; - -IZLibInflateStream* CZLibDecompressor::CreateInflateStream() -{ - return new CZLibInflateStream(); -} - -void CZLibDecompressor::Release() -{ - delete this; -} - -void CZLibInflateStream::Release() -{ - if (m_bStreamOpened) - { - int err = inflateEnd(&m_decompressStream); - if (err != Z_OK) - { - CryLog("zlib inflateEnd() error %d returned when closing stream", err); - } - } - - delete this; -} - -void CZLibInflateStream::SetOutputBuffer(char* pInBuffer, unsigned int inSize) -{ - m_bytesOutput += m_decompressStream.total_out; - - m_decompressStream.next_out = (byte*)pInBuffer; - m_decompressStream.avail_out = inSize; - m_decompressStream.total_out = 0; -} - -void CZLibInflateStream::GetStats(IZLibInflateStream::SStats* pOutStats) -{ - pOutStats->bytesInput = m_bytesInput; - pOutStats->bytesOutput = m_bytesOutput + m_decompressStream.total_out; - pOutStats->curMemoryUsed = m_zSize; - pOutStats->peakMemoryUsed = m_zPeak; -} - -unsigned int CZLibInflateStream::GetBytesOutput() -{ - return m_decompressStream.total_out; -} - -void CZLibInflateStream::Input(const char* pInSource, unsigned int inSourceSize) -{ - CRY_ASSERT_MESSAGE(m_currentState == eZInfState_AwaitingInput, "CZLibInflateStream::Input() called when stream is not awaiting input or has finished"); - - m_decompressStream.next_in = (Bytef*)pInSource; - m_decompressStream.avail_in = inSourceSize; - m_bytesInput += inSourceSize; -} - -void CZLibInflateStream::EndInput() -{ - CRY_ASSERT_MESSAGE(m_currentState == eZInfState_AwaitingInput, "CZLibInflateStream::EndInput() called when stream is not awaiting input"); - - m_zlibFlush = Z_FINISH; -} - -voidpf CZLibInflateStream::ZAlloc(voidpf pInOpaque, uInt inItems, uInt inSize) -{ - CZLibInflateStream* pStr = reinterpret_cast(pInOpaque); - - const unsigned int size = inItems * inSize; - - int* pPtr = (int*)CryModuleMalloc(sizeof(int) + size); - - if (pPtr) - { - *pPtr = inItems * inSize; - pPtr += 1; - - const unsigned int newSize = pStr->m_zSize + size; - pStr->m_zSize = newSize; - if (newSize > pStr->m_zPeak) - { - pStr->m_zPeak = newSize; - } - } - - return pPtr; -} - -void CZLibInflateStream::ZFree(voidpf pInOpaque, voidpf pInAddress) -{ - int* pPtr = reinterpret_cast(pInAddress); - - if (pPtr) - { - CZLibInflateStream* pStr = reinterpret_cast(pInOpaque); - pStr->m_zSize -= pPtr[-1]; - CryModuleFree(pPtr - 1); - } -} - -EZInflateState CZLibInflateStream::RunInflate() -{ - bool runInflate = false; - bool inputAvailable = (m_decompressStream.avail_in > 0) || (m_zlibFlush == Z_FINISH); - bool outputAvailable = (m_decompressStream.avail_out > 0); - - switch (m_currentState) - { - case eZInfState_AwaitingInput: - case eZInfState_ConsumeOutput: - if (inputAvailable && outputAvailable) - { - runInflate = true; - } - else if (inputAvailable || !outputAvailable) - { - m_currentState = eZInfState_ConsumeOutput; - } - else - { - m_currentState = eZInfState_AwaitingInput; - } - break; - - case eZInfState_Inflating: - CRY_ASSERT_MESSAGE(false, "Shouldn't be trying to run inflate whilst a inflate is in progress"); - break; - - case eZInfState_Error: - break; - - default: - CRY_ASSERT_MESSAGE(false, "unknown state"); - break; - } - - if (runInflate) - { - if (!m_bStreamOpened) - { - m_bStreamOpened = true; - - // initializing with inflateInit2 requires that the next_in be initialized - m_decompressStream.zalloc = &CZLibInflateStream::ZAlloc; - m_decompressStream.zfree = &CZLibInflateStream::ZFree; - m_decompressStream.opaque = this; - - const int error = inflateInit2(&m_decompressStream, -MAX_WBITS); - if (error != Z_OK) - { - m_currentState = eZInfState_Error; - CryLog("zlib inflateInit2() error, err %d", error); - } - } - - if (m_currentState != eZInfState_Error) - { - int error = inflate(&m_decompressStream, m_zlibFlush); - - if (error == Z_STREAM_END) - { - // end of stream has been generated, only produced if we pass Z_FINISH into inflate - m_currentState = eZInfState_Finished; - } - else if ((error == Z_OK && m_decompressStream.avail_out == 0) || (error == Z_BUF_ERROR && m_decompressStream.avail_out == 0)) - { - // output buffer has been filled - // data should be available for consumption by caller - m_currentState = eZInfState_ConsumeOutput; - } - else if (m_decompressStream.avail_in == 0) - { - // ran out of input data - // data may be available for consumption - but we need more input right now - m_currentState = eZInfState_AwaitingInput; - } - else - { - // some sort of error has occurred - m_currentState = eZInfState_Error; - CryLog("zlib inflate() error, err %d", error); - } - } - } - - return m_currentState; -} - -EZInflateState CZLibInflateStream::GetState() -{ - return RunInflate(); -} diff --git a/Code/CryEngine/CrySystem/ZStdDecompressor.cpp b/Code/CryEngine/CrySystem/ZStdDecompressor.cpp deleted file mode 100644 index 0de76b82f8..0000000000 --- a/Code/CryEngine/CrySystem/ZStdDecompressor.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include "CrySystem_precompiled.h" -#include -#include "ZStdDecompressor.h" - -bool CZStdDecompressor::DecompressData(const char* pIn, const uint inputSize, char* pOut, const uint outputSize) -{ - size_t result = ZSTD_decompress(pOut, outputSize, pIn, inputSize); - return !ZSTD_isError(result); -} - -void CZStdDecompressor::Release() -{ - delete this; -} diff --git a/Code/CryEngine/CrySystem/ZipFile.h b/Code/CryEngine/CrySystem/ZipFile.h deleted file mode 100644 index e0c42088a3..0000000000 --- a/Code/CryEngine/CrySystem/ZipFile.h +++ /dev/null @@ -1,19 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_ZIPFILE_H -#define CRYINCLUDE_CRYSYSTEM_ZIPFILE_H -#pragma once - - -#endif // CRYINCLUDE_CRYSYSTEM_ZIPFILE_H diff --git a/Code/CryEngine/CrySystem/ZipFileFormat_info.h b/Code/CryEngine/CrySystem/ZipFileFormat_info.h deleted file mode 100644 index d3fd4a3f54..0000000000 --- a/Code/CryEngine/CrySystem/ZipFileFormat_info.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#ifndef CRYINCLUDE_CRYSYSTEM_ZIPFILEFORMAT_INFO_H -#define CRYINCLUDE_CRYSYSTEM_ZIPFILEFORMAT_INFO_H -#pragma once - -#include "ZipFileFormat.h" - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Waddress-of-packed-member" -#endif - -STRUCT_INFO_BEGIN(ZipFile::CDREnd) -VAR_INFO(lSignature) -VAR_INFO(nDisk) -VAR_INFO(nCDRStartDisk) -VAR_INFO(numEntriesOnDisk) -VAR_INFO(numEntriesTotal) -VAR_INFO(lCDRSize) -VAR_INFO(lCDROffset) -VAR_INFO(nCommentLength) -STRUCT_INFO_END(ZipFile::CDREnd) - -STRUCT_INFO_BEGIN(ZipFile::DataDescriptor) -VAR_INFO(lCRC32) -VAR_INFO(lSizeCompressed) -VAR_INFO(lSizeUncompressed) -STRUCT_INFO_END(ZipFile::DataDescriptor) - -STRUCT_INFO_BEGIN(ZipFile::CDRFileHeader) -VAR_INFO(lSignature) -VAR_INFO(nVersionMadeBy) -VAR_INFO(nVersionNeeded) -VAR_INFO(nFlags) -VAR_INFO(nMethod) -VAR_INFO(nLastModTime) -VAR_INFO(nLastModDate) -VAR_INFO(desc) -VAR_INFO(nFileNameLength) -VAR_INFO(nExtraFieldLength) -VAR_INFO(nFileCommentLength) -VAR_INFO(nDiskNumberStart) -VAR_INFO(nAttrInternal) -VAR_INFO(lAttrExternal) -VAR_INFO(lLocalHeaderOffset) -STRUCT_INFO_END(ZipFile::CDRFileHeader) - -STRUCT_INFO_BEGIN(ZipFile::LocalFileHeader) -VAR_INFO(lSignature) -VAR_INFO(nVersionNeeded) -VAR_INFO(nFlags) -VAR_INFO(nMethod) -VAR_INFO(nLastModTime) -VAR_INFO(nLastModDate) -VAR_INFO(desc) -VAR_INFO(nFileNameLength) -VAR_INFO(nExtraFieldLength) -STRUCT_INFO_END(ZipFile::LocalFileHeader) - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -#endif // CRYINCLUDE_CRYSYSTEM_ZIPFILEFORMAT_INFO_H diff --git a/Code/CryEngine/CrySystem/crash_face.bmp b/Code/CryEngine/CrySystem/crash_face.bmp deleted file mode 100644 index 887e5111c9..0000000000 --- a/Code/CryEngine/CrySystem/crash_face.bmp +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ced9f21365ad5a4159f31f602be10a00becf389fa289694026425e7a6bc73077 -size 9272 diff --git a/Code/CryEngine/CrySystem/crysystem_android_files.cmake b/Code/CryEngine/CrySystem/crysystem_android_files.cmake deleted file mode 100644 index 9164dce432..0000000000 --- a/Code/CryEngine/CrySystem/crysystem_android_files.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - MobileDetectSpec_Android.cpp - MobileDetectSpec.cpp - MobileDetectSpec.h - ThermalInfoAndroid.h - ThermalInfoAndroid.cpp -) diff --git a/Code/CryEngine/CrySystem/crysystem_files.cmake b/Code/CryEngine/CrySystem/crysystem_files.cmake index 50cbdc24e4..6a56339b85 100644 --- a/Code/CryEngine/CrySystem/crysystem_files.cmake +++ b/Code/CryEngine/CrySystem/crysystem_files.cmake @@ -10,46 +10,20 @@ # set(FILES - AutoDetectSpec.cpp AZCrySystemInitLogSink.cpp - ClientHandler.cpp CmdLine.cpp CmdLineArg.cpp - CompressedFile.cpp ConsoleBatchFile.cpp ConsoleHelpGen.cpp - CryAsyncMemcpy.cpp - GeneralMemoryHeap.cpp - HandlerBase.cpp - AsyncPakManager.cpp Log.cpp - SystemRender.cpp - PhysRenderer.cpp - ResourceManager.cpp - ServerHandler.cpp - ServerThrottle.cpp - SyncLock.cpp System.cpp SystemCFG.cpp SystemEventDispatcher.cpp SystemInit.cpp SystemWin32.cpp Timer.cpp - UnixConsole.cpp - WindowsConsole.cpp XConsole.cpp XConsoleVariable.cpp - AutoDetectSpec.h - ClientHandler.h - HandlerBase.h - AsyncPakManager.h - PhysRenderer.h - ResourceManager.h - ServerHandler.h - ServerThrottle.h - SyncLock.h - UnixConsole.h - SystemInit.h XML/ReadWriteXMLSink.h AZCrySystemInitLogSink.h AZCoreLogSink.h @@ -57,32 +31,15 @@ set(FILES CmdLineArg.h ConsoleBatchFile.h ConsoleHelpGen.h - CryWaterMark.h - GeneralMemoryHeap.h Log.h - resource.h SimpleStringPool.h CrySystem_precompiled.h System.h SystemCFG.h SystemEventDispatcher.h Timer.h - Validator.h - WindowsConsole.h XConsole.h XConsoleVariable.h - crash_face.bmp - ImageHandler.h - ImageHandler.cpp - MemoryAddressRange.cpp - PageMappingHeap.cpp - CustomMemoryHeap.cpp - MemoryManager.cpp - MTSafeAllocator.cpp - MemoryAddressRange.h - PageMappingHeap.h - MemoryManager.h - MTSafeAllocator.h XML/SerializeXMLReader.cpp XML/SerializeXMLWriter.cpp XML/xml.cpp @@ -96,24 +53,14 @@ set(FILES XML/XmlUtils.h XML/ReadXMLSink.cpp XML/WriteXMLSource.cpp - ZipFile.h - ZipFileFormat_info.h - Sampler.cpp - Sampler.h LocalizedStringManager.cpp LocalizedStringManager.h - ZLibCompressor.cpp - ZLibCompressor.h Huffman.cpp Huffman.h RemoteConsole/RemoteConsole.cpp RemoteConsole/RemoteConsole.h RemoteConsole/RemoteConsole_impl.inl RemoteConsole/RemoteConsole_none.inl - ZLibDecompressor.h - ZLibDecompressor.cpp - LZ4Decompressor.h - LZ4Decompressor.cpp LevelSystem/LevelSystem.cpp LevelSystem/LevelSystem.h LevelSystem/SpawnableLevelSystem.cpp @@ -124,22 +71,5 @@ set(FILES ViewSystem/View.h ViewSystem/ViewSystem.cpp ViewSystem/ViewSystem.h - ZStdDecompressor.h - ZStdDecompressor.cpp - StreamEngine/StreamAsyncFileRequest.cpp - StreamEngine/StreamAsyncFileRequest_Jobs.cpp - StreamEngine/StreamEngine.cpp - StreamEngine/StreamIOThread.cpp - StreamEngine/StreamReadStream.cpp - StreamEngine/AZRequestReadStream.cpp - StreamEngine/StreamAsyncFileRequest.h - StreamEngine/StreamEngine.h - StreamEngine/StreamIOThread.h - StreamEngine/StreamReadStream.h - StreamEngine/AZRequestReadStream.h - CrashHandler.rc CrySystem_precompiled.cpp - CPUDetect.cpp - CPUDetect.h - WindowsErrorReporting.cpp ) diff --git a/Code/CryEngine/CrySystem/crysystem_ios_files.cmake b/Code/CryEngine/CrySystem/crysystem_ios_files.cmake deleted file mode 100644 index eca0f5142c..0000000000 --- a/Code/CryEngine/CrySystem/crysystem_ios_files.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - MobileDetectSpec_Ios.cpp - MobileDetectSpec.cpp - MobileDetectSpec.h -) diff --git a/Code/CryEngine/CrySystem/crysystem_mac_files.cmake b/Code/CryEngine/CrySystem/crysystem_mac_files.cmake deleted file mode 100644 index f5b9ea77a2..0000000000 --- a/Code/CryEngine/CrySystem/crysystem_mac_files.cmake +++ /dev/null @@ -1,11 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - diff --git a/Code/CryEngine/CrySystem/crysystem_test_files.cmake b/Code/CryEngine/CrySystem/crysystem_test_files.cmake deleted file mode 100644 index d8f6887da6..0000000000 --- a/Code/CryEngine/CrySystem/crysystem_test_files.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - Components/MathConversionTests.cpp - Tests/Test_CLog.cpp - Tests/Test_CommandRegistration.cpp - Tests/Test_CryPrimitives.cpp - Tests/test_CrySystem.cpp - Tests/Test_Localization.cpp - Tests/test_Main.cpp - Tests/test_MaterialUtils.cpp - DllMain.cpp -) diff --git a/Code/CryEngine/CrySystem/resource.h b/Code/CryEngine/CrySystem/resource.h deleted file mode 100644 index a5970a6475..0000000000 --- a/Code/CryEngine/CrySystem/resource.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// Original file Copyright Crytek GMBH or its affiliates, used under license. - -#define VS_VERSION_INFO 1 -#define IDD_CRITICAL_ERROR 101 -#define IDB_CONFIRM_SAVE 102 -#define IDB_DONT_SAVE 103 -#define IDD_CONFIRM_SAVE_LEVEL 127 -#define IDB_CRASH_FACE 128 -#define IDD_EXCEPTION 245 -#define IDC_CALLSTACK 1001 -#define IDC_EXCEPTION_CODE 1002 -#define IDC_EXCEPTION_ADDRESS 1003 -#define IDC_EXCEPTION_MODULE 1004 -#define IDC_EXCEPTION_DESC 1005 -#define IDB_EXIT 1008 -#define IDB_IGNORE 1010 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 129 -#define _APS_NEXT_COMMAND_VALUE 40072 -#define _APS_NEXT_CONTROL_VALUE 1003 -#define _APS_NEXT_SYMED_VALUE 104 -#endif -#endif diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetContainer.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetContainer.cpp index 2ff6143912..4028f48b27 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetContainer.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetContainer.cpp @@ -269,13 +269,13 @@ namespace AZ { for (auto& [assetId, dependentAsset] : m_dependencies) { - if (dependentAsset->IsReady()) + if (dependentAsset->IsReady() || dependentAsset->IsError()) { HandleReadyAsset(dependentAsset); } } } - if (auto asset = m_rootAsset.GetStrongReference(); asset.IsReady()) + if (auto asset = m_rootAsset.GetStrongReference(); asset.IsReady() || asset.IsError()) { HandleReadyAsset(asset); } @@ -496,10 +496,10 @@ namespace AZ m_waitingCount -= 1; disconnectEbus = true; - if (m_waitingAssets.empty()) - { - allReady = true; - } + } + if (m_waitingAssets.empty()) + { + allReady = true; } } @@ -510,8 +510,15 @@ namespace AZ } } - if (allReady && m_initComplete) + // If there are no assets left to be loaded, trigger the final AssetContainer notification (ready or canceled). + // We guard against prematurely sending it (m_initComplete) because it's possible for assets to get removed from our waiting + // list *while* we're still building up the list, so the list would appear to be empty too soon. + // We also guard against sending it multiple times (m_finalNotificationSent), because in some error conditions, it may be + // possible to try to remove the same asset multiple times, which if it's the last asset, it could trigger multiple + // notifications. + if (allReady && m_initComplete && !m_finalNotificationSent) { + m_finalNotificationSent = true; if (m_rootAsset) { AssetManagerBus::Broadcast(&AssetManagerBus::Events::OnAssetContainerReady, this); diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetContainer.h b/Code/Framework/AzCore/AzCore/Asset/AssetContainer.h index fe385efae9..5fef0ba7fb 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetContainer.h +++ b/Code/Framework/AzCore/AzCore/Asset/AssetContainer.h @@ -137,6 +137,7 @@ namespace AZ AZStd::atomic_int m_invalidDependencies{ 0 }; AZStd::unordered_set m_unloadedDependencies; AZStd::atomic_bool m_initComplete{ false }; + AZStd::atomic_bool m_finalNotificationSent{false}; mutable AZStd::recursive_mutex m_preloadMutex; // AssetId -> List of assets it is still waiting on diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index b2fe4417d3..8a170f5d89 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -477,7 +477,7 @@ namespace AZ m_console = AZ::Interface::Get(); if (m_console == nullptr) { - m_console = aznew AZ::Console(); + m_console = aznew AZ::Console(*m_settingsRegistry); AZ::Interface::Register(m_console); m_ownsConsole = true; m_console->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead()); @@ -916,27 +916,49 @@ namespace AZ SetSettingsRegistrySpecializations(specializations); AZStd::vector scratchBuffer; - // Retrieves the list gem module build targets that the active project depends on - SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry, - AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) // In development builds apply the o3de registry and the command line to allow early overrides. This will // allow developers to override things like default paths or Asset Processor connection settings. Any additional // values will be replaced by later loads, so this step will happen again at the end of loading. SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); + // Project User Registry is merged after the command line here to allow make sure the any command line override of the project path + // is used for merging the project's user registry SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); + SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); #endif + //! Retrieves the list gem targets that the project has load dependencies on + //! This populates the /Amazon/Gems//SourcePaths array entries which is required + //! by the MergeSettingsToRegistry_GemRegistry() function below to locate the gem's root folder + //! and merge in the gem's registry files. + //! But when running from a pre-built app from the O3DE SDK(Editor/AssetProcessor), the projects binary + //! directory is needed in order to located the load dependency registry files + //! That project binary folder is generated with the /user/Registry when CMake is configured + //! for the project + //! Therefore the order of merging must be as follows + //! 1. MergeSettingsToRegistry_ProjectUserRegistry - Populates the /Amazon/Project/Settings/Build/project_build_path + //! which contains the path to the project binary directory + //! 2. MergeSettingsToRegistry_TargetBuildDependencyRegistry - Loads the cmake_dependencies...setreg + //! file from the locations in order of + //! 1. /Registry + //! 2. /Registry + //! 3. /bin/$/Registry + //! 3. MergeSettingsToRegistry_GemRegistries - Merges the settings registry files from each gem's /Registry directory + + SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry, + AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_EngineRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_GemRegistries(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif // Update the Runtime file paths in case the "{BootstrapSettingsRootKey}/assets" key was overriden by a setting registry - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); + SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); } void ComponentApplication::SetSettingsRegistrySpecializations(SettingsRegistryInterface::Specializations& specializations) diff --git a/Code/Framework/AzCore/AzCore/Console/Console.cpp b/Code/Framework/AzCore/AzCore/Console/Console.cpp index 788a127830..3cb33b564a 100644 --- a/Code/Framework/AzCore/AzCore/Console/Console.cpp +++ b/Code/Framework/AzCore/AzCore/Console/Console.cpp @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -43,6 +45,12 @@ namespace AZ { } + Console::Console(AZ::SettingsRegistryInterface& settingsRegistryInterface) + : Console() + { + RegisterCommandInvokerWithSettingsRegistry(settingsRegistryInterface); + } + Console::~Console() { // on console destruction relink the console functors back to the deferred head @@ -111,51 +119,51 @@ namespace AZ void Console::ExecuteConfigFile(AZStd::string_view configFileName) { - IO::FixedMaxPath filePathFixed = configFileName; - if (AZ::IO::FileIOBase* fileIOBase = AZ::IO::FileIOBase::GetInstance()) + auto settingsRegistry = AZ::SettingsRegistry::Get(); + // If the config file is a settings registry file use the SettingsRegistryInterface MergeSettingsFile function + // otherwise use the SettingsRegistryMergeUtils MergeSettingsToRegistry_ConfigFile function to merge an INI-style + // file to the settings registry + AZ::IO::PathView configFile(configFileName); + if (configFile.Extension() == ".setreg") { - fileIOBase->ResolvePath(filePathFixed, configFileName); + settingsRegistry->MergeSettingsFile(configFile.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch); } - - IO::SystemFile file; - if (!file.Open(filePathFixed.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY)) + else if (configFile.Extension() == ".setregpatch") { - AZLOG_ERROR("Failed to load '%s'. File could not be opened.", filePathFixed.c_str()); - return; + settingsRegistry->MergeSettingsFile(configFile.Native(), AZ::SettingsRegistryInterface::Format::JsonPatch); } - const IO::SizeType length = file.Length(); - if (length == 0) - { - AZLOG_ERROR("Failed to load '%s'. File is empty.", filePathFixed.c_str()); - return; - } - file.Seek(0, IO::SystemFile::SF_SEEK_BEGIN); - AZStd::string fileBuffer; - fileBuffer.resize(length); - IO::SizeType bytesRead = file.Read(length, fileBuffer.data()); - file.Close(); - // Resize again just in case bytesRead is less than length for some reason - fileBuffer.resize(bytesRead); - - AZLOG_INFO("Loading config file %s", filePathFixed.c_str()); - - AZStd::vector separatedCommands; - auto BreakCommandsByLine = [&separatedCommands](AZStd::string_view token) - { - separatedCommands.emplace_back(token); - }; - StringFunc::TokenizeVisitor(fileBuffer, BreakCommandsByLine, "\n\r"); - - for (const auto& commandView : separatedCommands) + else { - ConsoleCommandContainer commandArgsView; - auto ConvertCommandStringToArray = [&commandArgsView](AZStd::string_view token) + AZ::SettingsRegistryMergeUtils::ConfigParserSettings configParserSettings; + configParserSettings.m_registryRootPointerPath = "/Amazon/AzCore/Runtime/ConsoleCommands"; + configParserSettings.m_commandLineSettings.m_delimiterFunc = [](AZStd::string_view line) { - commandArgsView.emplace_back(token); + SettingsRegistryInterface::CommandLineArgumentSettings::JsonPathValue pathValue; + AZStd::string_view parsedLine = line; + + // Splits the line based on the or + if (auto path = AZ::StringFunc::TokenizeNext(parsedLine, "=:"); path.has_value()) + { + pathValue.m_path = AZ::StringFunc::StripEnds(*path); + pathValue.m_value = AZ::StringFunc::StripEnds(parsedLine); + } + // If the value is empty, then the line either contained an equal sign followed only by whitespace or the line was empty + // 1. line="testInit=", pathValue.m_path="testInit", pathValue.m_value="" + // 2. line="testInit 1", pathValue.m_path="testInit 1", pathValue.m_value="" + // Therefore the path is split the path on whitespace in order to retrieve a value + if (pathValue.m_value.empty()) + { + parsedLine = pathValue.m_path; + if (auto path = AZ::StringFunc::TokenizeNext(parsedLine, " \t"); path.has_value()) + { + pathValue.m_path = AZ::StringFunc::StripEnds(*path); + pathValue.m_value = AZ::StringFunc::StripEnds(parsedLine); + } + + } + return pathValue; }; - constexpr AZStd::string_view commandSeparators = " ="; - StringFunc::TokenizeVisitor(commandView, ConvertCommandStringToArray, commandSeparators); - PerformCommand(commandArgsView, ConsoleSilentMode::NotSilent, ConsoleInvokedFrom::AzConsole, ConsoleFunctorFlags::Null, ConsoleFunctorFlags::Null); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ConfigFile(*settingsRegistry, configFile.Native(), configParserSettings); } } @@ -447,4 +455,134 @@ namespace AZ return result; } + + struct ConsoleCommandKeyNotificationHandler + { + ConsoleCommandKeyNotificationHandler(AZ::SettingsRegistryInterface& registry, Console& console) + : m_settingsRegistry(registry) + , m_console(console) + { + } + + // Responsible for using the Json Serialization Issue Callback system + // to determine when a JSON Patch or JSON Merge Patch modifies a value + // at a path underneath the IConsole::ConsoleRootCommandKey JSON pointer + JsonSerializationResult::ResultCode operator()(AZStd::string_view message, + JsonSerializationResult::ResultCode result, AZStd::string_view path) + { + AZ::IO::PathView consoleRootCommandKey{ IConsole::ConsoleRootCommandKey, AZ::IO::PosixPathSeparator }; + AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator }; + if (result.GetTask() == JsonSerializationResult::Tasks::Merge + && result.GetProcessing() == JsonSerializationResult::Processing::Completed + && inputKey.IsRelativeTo(consoleRootCommandKey)) + { + if (auto type = m_settingsRegistry.GetType(path); type != SettingsRegistryInterface::Type::NoType) + { + operator()(path, type); + } + } + + // This is the default issue reporting, that logs using the warning category + if (result.GetProcessing() != JsonSerializationResult::Processing::Completed) + { + scratchBuffer.append(message.begin(), message.end()); + scratchBuffer.append("\n Reason: "); + result.AppendToString(scratchBuffer, path); + scratchBuffer.append("."); + AZ_Warning("JSON Serialization", false, "%s", scratchBuffer.c_str()); + + scratchBuffer.clear(); + } + return result; + } + + void operator()(AZStd::string_view path, SettingsRegistryInterface::Type type) + { + using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; + + AZ::IO::PathView consoleRootCommandKey{ IConsole::ConsoleRootCommandKey, AZ::IO::PosixPathSeparator }; + AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator }; + if (inputKey.IsRelativeTo(consoleRootCommandKey)) + { + FixedValueString command = inputKey.LexicallyRelative(consoleRootCommandKey).Native(); + ConsoleCommandContainer commandArgs; + // Argument string which stores the value from the Settings Registry long enough + // to pass into the PerformCommand. The ConsoleCommandContainer stores string_views + // and therefore doesn't own the memory. + FixedValueString commandArgString; + + if (type == SettingsRegistryInterface::Type::String) + { + if (m_settingsRegistry.Get(commandArgString, path)) + { + auto ConvertCommandArgumentToArray = [&commandArgs](AZStd::string_view token) + { + commandArgs.emplace_back(token); + }; + constexpr AZStd::string_view commandSeparators = " \t\n\r"; + StringFunc::TokenizeVisitor(commandArgString, ConvertCommandArgumentToArray, commandSeparators); + } + } + else if (type == SettingsRegistryInterface::Type::Boolean) + { + bool commandArgBool{}; + if (m_settingsRegistry.Get(commandArgBool, path)) + { + commandArgString = commandArgBool ? "true" : "false"; + commandArgs.emplace_back(commandArgString); + } + } + else if (type == SettingsRegistryInterface::Type::Integer) + { + // Try converting to a signed 64-bit number first and then an unsigned 64-bit number + AZ::s64 commandArgInt{}; + AZ::u64 commandArgUInt{}; + if (m_settingsRegistry.Get(commandArgInt, path)) + { + AZStd::to_string(commandArgString, commandArgInt); + commandArgs.emplace_back(commandArgString); + } + else if (m_settingsRegistry.Get(commandArgUInt, path)) + { + AZStd::to_string(commandArgString, commandArgUInt); + commandArgs.emplace_back(commandArgString); + } + } + else if (type == SettingsRegistryInterface::Type::FloatingPoint) + { + double commandArgFloat{}; + if (m_settingsRegistry.Get(commandArgFloat, path)) + { + AZStd::to_string(commandArgString, commandArgFloat); + commandArgs.emplace_back(commandArgString); + } + } + CVarFixedString commandTrace(command); + for (AZStd::string_view commandArg : commandArgs) + { + commandTrace.push_back(' '); + commandTrace += commandArg; + } + + m_console.PerformCommand(command, commandArgs, ConsoleSilentMode::NotSilent, ConsoleInvokedFrom::AzConsole, ConsoleFunctorFlags::Null, ConsoleFunctorFlags::Null); + } + } + + AZ::Console& m_console; + AZ::SettingsRegistryInterface& m_settingsRegistry; + AZStd::string scratchBuffer; + }; + + void Console::RegisterCommandInvokerWithSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry) + { + // Make sure the there is a JSON object at the path of AZ::IConsole::ConsoleRootCommandKey + // So that JSON Patch is able to add values underneath that object (JSON Patch doesn't create intermediate objects) + settingsRegistry.MergeSettings(R"({ "Amazon": { "AzCore": { "Runtime": { "ConsoleCommands": {} } }}})", + SettingsRegistryInterface::Format::JsonMergePatch); + m_consoleCommandKeyHandler = settingsRegistry.RegisterNotifier(ConsoleCommandKeyNotificationHandler{ settingsRegistry, *this }); + + JsonApplyPatchSettings applyPatchSettings; + applyPatchSettings.m_reporting = ConsoleCommandKeyNotificationHandler{ settingsRegistry, *this }; + settingsRegistry.SetApplyPatchSettings(applyPatchSettings); + } } diff --git a/Code/Framework/AzCore/AzCore/Console/Console.h b/Code/Framework/AzCore/AzCore/Console/Console.h index 1c9c6897f6..ba614824fe 100644 --- a/Code/Framework/AzCore/AzCore/Console/Console.h +++ b/Code/Framework/AzCore/AzCore/Console/Console.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -29,6 +30,9 @@ namespace AZ AZ_CLASS_ALLOCATOR(Console, AZ::OSAllocator, 0); Console(); + //! Constructor overload which registers a notifier with the Settings Registry that will execute + //! a console command whenever a key is set under the AZ::IConsole::ConsoleCommandRootKey JSON object + explicit Console(AZ::SettingsRegistryInterface& settingsRegistry); ~Console() override; //! IConsole interface @@ -67,6 +71,7 @@ namespace AZ void RegisterFunctor(ConsoleFunctorBase* functor) override; void UnregisterFunctor(ConsoleFunctorBase* functor) override; void LinkDeferredFunctors(ConsoleFunctorBase*& deferredHead) override; + void RegisterCommandInvokerWithSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry) override; //! @} private: @@ -96,6 +101,7 @@ namespace AZ ConsoleFunctorBase* m_head; using CommandMap = AZStd::unordered_map>; CommandMap m_commands; + AZ::SettingsRegistryInterface::NotifyEventHandler m_consoleCommandKeyHandler; friend class ConsoleFunctorBase; }; diff --git a/Code/Framework/AzCore/AzCore/Console/ConsoleTypeHelpers.inl b/Code/Framework/AzCore/AzCore/Console/ConsoleTypeHelpers.inl index 0257564d43..18ed27e517 100644 --- a/Code/Framework/AzCore/AzCore/Console/ConsoleTypeHelpers.inl +++ b/Code/Framework/AzCore/AzCore/Console/ConsoleTypeHelpers.inl @@ -148,7 +148,15 @@ namespace AZ { AZ::CVarFixedString convertCandidate{ arguments.front() }; char* endPtr = nullptr; - MAX_TYPE value = static_cast(strtoll(convertCandidate.c_str(), &endPtr, 0)); + MAX_TYPE value; + if constexpr (AZStd::is_unsigned_v) + { + value = aznumeric_cast(strtoull(convertCandidate.c_str(), &endPtr, 0)); + } + else + { + value = aznumeric_cast(strtoll(convertCandidate.c_str(), &endPtr, 0)); + } if (endPtr == convertCandidate.c_str()) { diff --git a/Code/Framework/AzCore/AzCore/Console/IConsole.h b/Code/Framework/AzCore/AzCore/Console/IConsole.h index 9f5ede7f4c..b976f3a9db 100644 --- a/Code/Framework/AzCore/AzCore/Console/IConsole.h +++ b/Code/Framework/AzCore/AzCore/Console/IConsole.h @@ -22,8 +22,10 @@ namespace AZ { + class SettingsRegistryInterface; class CommandLine; + //! @class IConsole //! A simple console class for providing text based variable and process interaction. class IConsole @@ -33,6 +35,8 @@ namespace AZ using FunctorVisitor = AZStd::function; + inline static constexpr AZStd::string_view ConsoleRootCommandKey = "/Amazon/AzCore/Runtime/ConsoleCommands"; + IConsole() = default; virtual ~IConsole() = default; @@ -145,6 +149,12 @@ namespace AZ //! Returns the AZ::Event<> invoked whenever a console command could not be found. DispatchCommandNotFoundEvent& GetDispatchCommandNotFoundEvent(); + //! Register a notification event handler with the Settings Registry + //! That is responsible for updating console commands whenever + //! a key is found underneath the "/Amazon/AzCore/Runtime/ConsoleCommands" JSON entry + //! @param Settings Registry reference to register notifier with + virtual void RegisterCommandInvokerWithSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry) = 0; + AZ_DISABLE_COPY_MOVE(IConsole); protected: diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptTimePoint.h b/Code/Framework/AzCore/AzCore/Script/ScriptTimePoint.h index 7cb81829ef..41d80f42a3 100644 --- a/Code/Framework/AzCore/AzCore/Script/ScriptTimePoint.h +++ b/Code/Framework/AzCore/AzCore/Script/ScriptTimePoint.h @@ -24,9 +24,7 @@ namespace AZ AZ_TYPE_INFO_SPECIALIZE(AZStd::chrono::system_clock::time_point, "{5C48FD59-7267-405D-9C06-1EA31379FE82}"); - /** - * Wrapper that reflects a AZStd::chrono::system_clock::time_point to script. - */ + //! Wrapper that reflects a AZStd::chrono::system_clock::time_point to script. class ScriptTimePoint { public: @@ -38,33 +36,45 @@ namespace AZ explicit ScriptTimePoint(AZStd::chrono::system_clock::time_point timePoint) : m_timePoint(timePoint) {} - AZStd::string ToString() const - { - return AZStd::string::format("Time %llu", m_timePoint.time_since_epoch().count()); - } + //! Formats the time point in a string formatted as: "Time ". + AZStd::string ToString() const; - const AZStd::chrono::system_clock::time_point& Get() { return m_timePoint; } + //! Returns the time point. + const AZStd::chrono::system_clock::time_point& Get() const; - // Returns the time point in seconds - double GetSeconds() const - { - typedef AZStd::chrono::duration double_seconds; - return AZStd::chrono::duration_cast(m_timePoint.time_since_epoch()).count(); - } + //! Returns the time point in seconds + double GetSeconds() const; - // Returns the time point in milliseconds - double GetMilliseconds() const - { - typedef AZStd::chrono::duration double_ms; - return AZStd::chrono::duration_cast(m_timePoint.time_since_epoch()).count(); - } + //! Returns the time point in milliseconds + double GetMilliseconds() const; static void Reflect(ReflectContext* reflection); protected: - AZStd::chrono::system_clock::time_point m_timePoint; }; + + inline AZStd::string ScriptTimePoint::ToString() const + { + return AZStd::string::format("Time %llu", m_timePoint.time_since_epoch().count()); + } + + inline const AZStd::chrono::system_clock::time_point& ScriptTimePoint::Get() const + { + return m_timePoint; + } + + inline double ScriptTimePoint::GetSeconds() const + { + typedef AZStd::chrono::duration double_seconds; + return AZStd::chrono::duration_cast(m_timePoint.time_since_epoch()).count(); + } + + inline double ScriptTimePoint::GetMilliseconds() const + { + typedef AZStd::chrono::duration double_ms; + return AZStd::chrono::duration_cast(m_timePoint.time_since_epoch()).count(); + } } diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonMerger.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonMerger.cpp index e359888da7..de9aa70362 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonMerger.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonMerger.cpp @@ -11,13 +11,17 @@ */ #include +#include #include #include #include +#include #include namespace AZ { + using ReporterString = AZStd::fixed_string<1024>; + JsonSerializationResult::ResultCode JsonMerger::ApplyPatch(rapidjson::Value& target, rapidjson::Document::AllocatorType& allocator, const rapidjson::Value& patch, JsonApplyPatchSettings& settings) @@ -105,8 +109,7 @@ namespace AZ } else { - AZ::OSString message = AZ::OSString::format(R"(Unknown operation "%.*s".)", - aznumeric_cast(operationName.length()), operationName.data()); + auto message = ReporterString::format(R"(Unknown operation "%.*s".)", AZ_STRING_ARG(operationName)); return settings.m_reporting(message.c_str(), ResultCode(Tasks::Merge, Outcomes::Unknown), element); } @@ -131,6 +134,14 @@ namespace AZ JsonSerializationResult::ResultCode JsonMerger::ApplyMergePatch(rapidjson::Value& target, rapidjson::Document::AllocatorType& allocator, const rapidjson::Value& patch, JsonApplyPatchSettings& settings) + { + StackedString element(StackedString::Format::JsonPointer); + return ApplyMergePatchInternal(target, allocator, patch, settings, element); + } + + JsonSerializationResult::ResultCode JsonMerger::ApplyMergePatchInternal(rapidjson::Value& target, + rapidjson::Document::AllocatorType& allocator, const rapidjson::Value& patch, + JsonApplyPatchSettings& settings, StackedString& element) { using namespace JsonSerializationResult; @@ -150,14 +161,18 @@ namespace AZ { if (targetField != target.MemberEnd()) { - result.Combine(ApplyMergePatch(targetField->value, allocator, field.value, settings)); + ScopedStackedString fieldNameScope{ element, + AZStd::string_view(field.name.GetString(), field.name.GetStringLength()) }; + result.Combine(ApplyMergePatchInternal(targetField->value, allocator, field.value, settings, element)); } else { rapidjson::Value name; name.CopyFrom(field.name, allocator, true); rapidjson::Value value; - result.Combine(ApplyMergePatch(value, allocator, field.value, settings)); + ScopedStackedString fieldNameScope{ element, + AZStd::string_view(field.name.GetString(), field.name.GetStringLength()) }; + result.Combine(ApplyMergePatchInternal(value, allocator, field.value, settings, element)); target.AddMember(AZStd::move(name), AZStd::move(value), allocator); } } @@ -165,7 +180,14 @@ namespace AZ { if (targetField != target.MemberEnd()) { + ScopedStackedString fieldNameScope{ element, + AZStd::string_view(field.name.GetString(), field.name.GetStringLength()) }; + AZStd::string_view jsonPath = element.Get(); + target.RemoveMember(targetField); + result.Combine(settings.m_reporting(ReporterString::format( + R"(Successfully removed member from "%.*s" using JSON Merge Patch)", AZ_STRING_ARG(jsonPath)), + ResultCode(Tasks::Merge, Outcomes::Success), element)); } } else @@ -173,6 +195,12 @@ namespace AZ if (targetField != target.MemberEnd()) { targetField->value.CopyFrom(field.value, allocator, true); + + ScopedStackedString fieldNameScope{ element, AZStd::string_view(field.name.GetString(), field.name.GetStringLength()) }; + AZStd::string_view jsonPath = element.Get(); + result.Combine(settings.m_reporting(ReporterString::format( + R"(Successfully updated JSON field "%.*s" using JSON Merge Patch)", AZ_STRING_ARG(jsonPath)), + ResultCode(Tasks::Merge, Outcomes::Success), element)); } else { @@ -181,6 +209,12 @@ namespace AZ name.CopyFrom(field.name, allocator, true); value.CopyFrom(field.value, allocator, true); target.AddMember(AZStd::move(name), AZStd::move(value), allocator); + + ScopedStackedString fieldNameScope{ element, AZStd::string_view(field.name.GetString(), field.name.GetStringLength()) }; + AZStd::string_view jsonPath = element.Get(); + result.Combine(settings.m_reporting(ReporterString::format( + R"(Successfully added JSON field "%.*s" using JSON Merge Patch)", AZ_STRING_ARG(jsonPath)), + ResultCode(Tasks::Merge, Outcomes::Success), element)); } } } @@ -190,7 +224,7 @@ namespace AZ target.CopyFrom(patch, allocator, true); } result.Combine(settings.m_reporting("Successfully applied patch to target using JSON Merge Patch.", - ResultCode(Tasks::Merge, Outcomes::Success), StackedString(StackedString::Format::JsonPointer))); + ResultCode(Tasks::Merge, Outcomes::Success), element)); return result; } @@ -268,9 +302,11 @@ namespace AZ const rapidjson::Pointer::Token* const tokens = path.GetTokens(); if (path.GetTokenCount() == 0) { + rapidjson::StringBuffer pointerPathString; + path.Stringify(pointerPathString); target = AZStd::move(newValue); return settings.m_reporting(R"(Successfully applied "add" operation.)", - ResultCode(Tasks::Merge, Outcomes::Success), element); + ResultCode(Tasks::Merge, Outcomes::Success), pointerPathString.GetString()); } rapidjson::Pointer parent = rapidjson::Pointer(tokens, path.GetTokenCount() - 1); @@ -342,8 +378,10 @@ namespace AZ ResultCode(Tasks::Merge, Outcomes::TypeMismatch), element); } + rapidjson::StringBuffer pointerPathString; + path.Stringify(pointerPathString); return settings.m_reporting(R"(Successfully applied "add" operation.)", - ResultCode(Tasks::Merge, Outcomes::Success), element); + ResultCode(Tasks::Merge, Outcomes::Success), pointerPathString.GetString()); } JsonSerializationResult::ResultCode JsonMerger::ApplyPatch_Remove(rapidjson::Value& target, const rapidjson::Pointer& path, @@ -393,8 +431,10 @@ namespace AZ ResultCode(Tasks::Merge, Outcomes::TypeMismatch), element); } + rapidjson::StringBuffer pointerPathString; + path.Stringify(pointerPathString); return settings.m_reporting(R"(Successfully applied "remove" operation.)", - ResultCode(Tasks::Merge, Outcomes::Success), element); + ResultCode(Tasks::Merge, Outcomes::Success), pointerPathString.GetString()); } JsonSerializationResult::ResultCode JsonMerger::ApplyPatch_Replace(rapidjson::Value& target, @@ -420,8 +460,10 @@ namespace AZ memberValue->CopyFrom(value->value, allocator); + rapidjson::StringBuffer pointerPathString; + path.Stringify(pointerPathString); return settings.m_reporting(R"(Successfully applied "replace" operation.)", - ResultCode(Tasks::Merge, Outcomes::Success), element); + ResultCode(Tasks::Merge, Outcomes::Success), pointerPathString.GetString()); } JsonSerializationResult::ResultCode JsonMerger::ApplyPatch_Move(rapidjson::Value& target, diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonMerger.h b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonMerger.h index a33bac117b..127897c6ff 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonMerger.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonMerger.h @@ -42,6 +42,11 @@ namespace AZ rapidjson::Document::AllocatorType& allocator, const rapidjson::Value& patch, JsonApplyPatchSettings& settings); + //! Implementation of the JSON Merge Patch algorithm: https://tools.ietf.org/html/rfc7386 + static JsonSerializationResult::ResultCode ApplyMergePatchInternal(rapidjson::Value& target, + rapidjson::Document::AllocatorType& allocator, const rapidjson::Value& patch, + JsonApplyPatchSettings& settings, StackedString& element); + //! Function to create JSON Merge Patches: https://tools.ietf.org/html/rfc7386 static JsonSerializationResult::ResultCode CreateMergePatch(rapidjson::Value& patch, rapidjson::Document::AllocatorType& allocator, const rapidjson::Value& source, diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.cpp index 609eb03a2c..f6b804494e 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.cpp @@ -88,4 +88,28 @@ namespace AZ { return index < m_names.size() ? m_names[index] : AZStd::string_view(); } + + SettingsRegistryInterface::CommandLineArgumentSettings::CommandLineArgumentSettings() + { + m_delimiterFunc = [](AZStd::string_view line) -> JsonPathValue + { + constexpr AZStd::string_view CommandLineArgumentDelimiters{ "=:" }; + JsonPathValue pathValue; + pathValue.m_value = line; + + // Splits the line on the first delimiter and stores that in the pathValue.m_path variable + // The StringFunc::TokenizeNext function updates the pathValue.m_value parameter in place + // to contain all the text after the first delimiter + // So if pathValue.m_value="foo = Hello Ice Cream=World:17", the call to TokenizeNext would + // split the value as follows + // pathValue.m_path = "foo" + // pathValue.m_value = "Hello Ice Cream=World:17" + if (auto path = AZ::StringFunc::TokenizeNext(pathValue.m_value, CommandLineArgumentDelimiters); path.has_value()) + { + pathValue.m_path = AZ::StringFunc::StripEnds(*path); + } + pathValue.m_value = AZ::StringFunc::StripEnds(pathValue.m_value); + return pathValue; + }; + } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h index 768841cc09..2d9b0d83e5 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h @@ -26,6 +26,7 @@ namespace AZ { + struct JsonApplyPatchSettings; //! The Settings Registry is the central storage for global settings. Having application-wide settings //! stored in a central location allows different tools such as command lines, consoles, configuration //! files, etc. to work in a universal way. @@ -260,21 +261,20 @@ namespace AZ virtual bool Remove(AZStd::string_view path) = 0; //! Structure which contains configuration settings for how to parse a single command line argument - //! It supports supplying a functor for determining if a character is a delimiter + //! It supports supplying a functor for splitting a line into JSON path and JSON value struct CommandLineArgumentSettings { - inline static constexpr AZStd::string_view CommandLineArgumentDelimiters{ "=:"}; - CommandLineArgumentSettings() + struct JsonPathValue { - m_delimiterFunc = [](const char delimiter) -> bool - { - return CommandLineArgumentDelimiters.find_first_of(delimiter) != AZStd::string_view::npos; - }; - } - - //! Callback function which is invoked to determine whether a delimiter has been found - //! return value of true indicates that a delimiter has been found - using DelimiterFunc = AZStd::function; + AZStd::string_view m_path; + AZStd::string_view m_value; + }; + + CommandLineArgumentSettings(); + + //! Callback function which is invoked to determine how to split a command line argument + //! into a JSON path and a JSON value + using DelimiterFunc = AZStd::function; DelimiterFunc m_delimiterFunc; }; //! Merges a single command line argument into the settings registry. Command line arguments @@ -322,6 +322,14 @@ namespace AZ //! @return True if the registry folder was successfully merged, otherwise false. virtual bool MergeSettingsFolder(AZStd::string_view path, const Specializations& specializations, AZStd::string_view platform = {}, AZStd::string_view rootKey = "", AZStd::vector* scratchBuffer = nullptr) = 0; + + //! Stores the settings structure which is used when merging settings to the Settings Registry + //! using JSON Merge Patch or JSON Merge Patch. + //! The settings contain an issue reporting callback which can be used to track patching process. + //! Potential application of the reporting callback could be to update a UI whenever a key receives an updated value + //! @param applyPatchSettings The ApplyPatchSettings which are using during JSON Merging + virtual void SetApplyPatchSettings(const AZ::JsonApplyPatchSettings& applyPatchSettings) = 0; + virtual void GetApplyPatchSettings(AZ::JsonApplyPatchSettings& applyPatchSettings) = 0; }; inline SettingsRegistryInterface::Visitor::~Visitor() = default; diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp index 9ea76817af..2421c75be3 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -419,9 +420,6 @@ namespace AZ bool SettingsRegistryImpl::MergeCommandLineArgument(AZStd::string_view argument, AZStd::string_view rootKey, const CommandLineArgumentSettings& commandLineSettings) { - const char* front = argument.begin(); - const char* back = argument.end(); - if (!commandLineSettings.m_delimiterFunc) { AZ_Error("SettingsRegistry", false, @@ -429,87 +427,40 @@ namespace AZ aznumeric_cast(argument.size()), argument.data()); return false; } - const char* split = AZStd::find_if(front, back, commandLineSettings.m_delimiterFunc); - if (split == front || // There is no key - split == (back-1) || // There is no value - split == back) // Split character not found. + + auto [key, value] = commandLineSettings.m_delimiterFunc(argument); + if (key.empty()) { + // They key where to set the JSON value cannot be empty + // The value of the JSON can be though + // This is so that a key can be set to empty string using "/KeyPath=" return false; } - const char* keyStart = front; - while (std::isspace(*keyStart)) // This is safe because it will eventually stop on = + // Prepend the rootKey as an anchor to the argument key + SettingsRegistryInterface::FixedValueString keyPath{ rootKey.ends_with('/') + ? rootKey.substr(0, rootKey.size() - 1) + : rootKey }; + // Append the JSON reference token prefix of '/' to the keyPath + if (!key.starts_with('/')) { - keyStart++; + keyPath.push_back('/'); } - if (keyStart == split) // Key is just white spaces + if ((key.size() + keyPath.size()) > keyPath.max_size()) { + // The key portion is longer than the FixedValueString max size that can be stored + // This limitation is arbitrary, if an AZStd::string is used or if the C++17 std::to_chars + // function is used, there wouldn't need to be a limitation return false; } - const char* keyEnd = split; - while (std::isspace(*--keyEnd)); - keyEnd++; - - char buffer[MaxJsonPathLength]; - AZStd::string_view key; - bool keyHasDivider = *keyStart == '/'; - if (!rootKey.empty()) - { - bool rootKeyHasDivider = (rootKey[rootKey.length() - 1]) == '/'; - size_t count; - if (!rootKeyHasDivider && !keyHasDivider) - { - count = azsnprintf(buffer, AZ_ARRAY_SIZE(buffer), "%.*s/%.*s", - aznumeric_cast(rootKey.length()), rootKey.data(), - aznumeric_cast(keyEnd - keyStart), keyStart); - } - else if (rootKeyHasDivider && keyHasDivider) - { - count = azsnprintf(buffer, AZ_ARRAY_SIZE(buffer), "%.*s%.*s", - aznumeric_cast(rootKey.length()) - 1, rootKey.data(), - aznumeric_cast(keyEnd - keyStart), keyStart); - } - else - { - count = azsnprintf(buffer, AZ_ARRAY_SIZE(buffer), "%.*s%.*s", - aznumeric_cast(rootKey.length()), rootKey.data(), - aznumeric_cast(keyEnd - keyStart), keyStart); - } - if (count >= AZ_ARRAY_SIZE(buffer) - 1) - { - return false; - } - key = AZStd::string_view(buffer, count); - } - else if (!keyHasDivider) - { - size_t count = azsnprintf(buffer, AZ_ARRAY_SIZE(buffer), "/%.*s", - aznumeric_cast(keyEnd - keyStart), keyStart); - if (count >= AZ_ARRAY_SIZE(buffer) - 1) - { - return false; - } - key = AZStd::string_view(buffer, count); - } - else - { - key = AZStd::string_view(keyStart, keyEnd); - } + keyPath += key; + key = keyPath; - const char* valueStart = split + 1; - while (std::isspace(*valueStart) && valueStart < back) - { - valueStart++; - } - if (valueStart == back) + if (value.empty()) { - return false; // The value is empty + return Set(key, value); } - const char* valueEnd = back; - while (std::isspace(*(--valueEnd))); - valueEnd++; - AZStd::string_view value(valueStart, valueEnd); if (value == "true") { return Set(key, true); @@ -519,23 +470,35 @@ namespace AZ return Set(key, false); } - if (value.length() - 1 >= MaxCommandLineArgumentLength) + SettingsRegistryInterface::FixedValueString valueString; + if (value.size() > valueString.max_size()) { + // The value portion is longer than the FixedValueString max size that can be stored + // This limitation is arbitrary, if an AZStd::string is used or if the C++17 std::to_chars + // function is used, there wouldn't need to be a limitation return false; } - char argumentString[MaxCommandLineArgumentLength]; - snprintf(argumentString, AZ_ARRAY_SIZE(argument), "%.*s", aznumeric_cast(value.length()), value.data()); - char* argumentStringEnd = argumentString + value.length(); + valueString = value; + const char* valueStringEnd = valueString.c_str() + valueString.size(); + errno = 0; char* convertEnd = nullptr; - s64 intValue = strtoll(argumentString, &convertEnd, 0); - if (convertEnd == argumentStringEnd) + s64 intValue = strtoll(valueString.c_str(), &convertEnd, 0); + if (errno != ERANGE && convertEnd == valueStringEnd) { return Set(key, intValue); } + errno = 0; convertEnd = nullptr; - double floatingPointValue = strtod(argumentString, &convertEnd); - if (convertEnd == argumentStringEnd) + u64 uintValue = strtoull(valueString.c_str(), &convertEnd, 0); + if (errno != ERANGE && convertEnd == valueStringEnd) + { + return Set(key, uintValue); + } + errno = 0; + convertEnd = nullptr; + double floatingPointValue = strtod(valueString.c_str(), &convertEnd); + if (errno != ERANGE && convertEnd == valueStringEnd) { return Set(key, floatingPointValue); } @@ -611,7 +574,7 @@ namespace AZ } else { - if (MaxFilePathLength < path.length() + 1) + if (AZ::IO::MaxPathLength < path.length() + 1) { AZ_Error("Settings Registry", false, R"(Path "%.*s" is too long. Either make sure that the provided path is terminated or use a shorter path.)", @@ -623,10 +586,8 @@ namespace AZ .AddMember(StringRef("Path"), AZStd::move(pathValue), m_settings.GetAllocator()); return false; } - char filePath[MaxFilePathLength]; - azstrncpy(filePath, AZ_ARRAY_SIZE(filePath), path.data(), path.length()); - filePath[path.length()] = 0; - result = MergeSettingsFileInternal(filePath, format, rootKey, *scratchBuffer); + AZ::IO::FixedMaxPathString filePath(path); + result = MergeSettingsFileInternal(filePath.c_str(), format, rootKey, *scratchBuffer); } scratchBuffer->clear(); @@ -660,7 +621,7 @@ namespace AZ additionalSpaceRequired += AZ_ARRAY_SIZE(PlatformFolder) + platform.length() + 2; // +2 for the two slashes. } - if (path.length() + additionalSpaceRequired > MaxFilePathLength) + if (path.length() + additionalSpaceRequired > AZ::IO::MaxPathLength) { AZ_Error("Settings Registry", false, "Folder path for the Setting Registry is too long: %.*s", static_cast(path.size()), path.data()); @@ -673,7 +634,7 @@ namespace AZ RegistryFileList fileList; scratchBuffer->clear(); - AZStd::fixed_string folderPath{ path }; + AZ::IO::FixedMaxPathString folderPath{ path }; constexpr AZStd::string_view pathSeparators{ AZ_CORRECT_AND_WRONG_DATABASE_SEPARATOR }; if (pathSeparators.find_first_of(folderPath.back()) == AZStd::string_view::npos) { @@ -926,7 +887,7 @@ namespace AZ // Sort by the name first so the registry file gets applied with all its specializations. if (lhs.m_tags[0] != rhs.m_tags[0]) { - return strcmp(lhs.m_relativePath, rhs.m_relativePath) < 0; + return lhs.m_relativePath < rhs.m_relativePath; } // Then sort by size first so the files with the fewest specializations get applied first. @@ -956,14 +917,14 @@ namespace AZ } collisionFound = true; - AZ_Error("Settings Registry", false, R"(Two registry files point to the same specialization: "%s" and "%s")", - lhs.m_relativePath, rhs.m_relativePath); + AZ_Error("Settings Registry", false, R"(Two registry files in "%.*s" point to the same specialization: "%s" and "%s")", + AZ_STRING_ARG(folderPath), lhs.m_relativePath.c_str(), rhs.m_relativePath.c_str()); historyPointer.Create(m_settings, m_settings.GetAllocator()).SetObject() .AddMember(StringRef("Error"), StringRef("Too many files in registry folder."), m_settings.GetAllocator()) .AddMember(StringRef("Path"), Value(folderPath.data(), aznumeric_caster(folderPath.length()), m_settings.GetAllocator()), m_settings.GetAllocator()) - .AddMember(StringRef("File1"), Value(lhs.m_relativePath, m_settings.GetAllocator()), m_settings.GetAllocator()) - .AddMember(StringRef("File2"), Value(rhs.m_relativePath, m_settings.GetAllocator()), m_settings.GetAllocator()); + .AddMember(StringRef("File1"), Value(lhs.m_relativePath.c_str(), m_settings.GetAllocator()), m_settings.GetAllocator()) + .AddMember(StringRef("File2"), Value(rhs.m_relativePath.c_str(), m_settings.GetAllocator()), m_settings.GetAllocator()); return false; } @@ -1036,9 +997,9 @@ namespace AZ // thats the name tag. AZStd::sort(AZStd::next(output.m_tags.begin()), output.m_tags.end()); - if (filePathSize < AZ_ARRAY_SIZE(output.m_relativePath)) + if (filePathSize < output.m_relativePath.max_size()) { - azstrcpy(output.m_relativePath, AZ_ARRAY_SIZE(output.m_relativePath), filename); + output.m_relativePath = filename; return true; } else @@ -1145,7 +1106,7 @@ namespace AZ JsonSerializationResult::ResultCode mergeResult(JsonSerializationResult::Tasks::Merge); if (rootKey.empty()) { - mergeResult = JsonSerialization::ApplyPatch(m_settings, m_settings.GetAllocator(), jsonPatch, mergeApproach); + mergeResult = JsonSerialization::ApplyPatch(m_settings, m_settings.GetAllocator(), jsonPatch, mergeApproach, m_applyPatchSettings); } else { @@ -1153,7 +1114,7 @@ namespace AZ if (root.IsValid()) { Value& rootValue = root.Create(m_settings, m_settings.GetAllocator()); - mergeResult = JsonSerialization::ApplyPatch(rootValue, m_settings.GetAllocator(), jsonPatch, mergeApproach); + mergeResult = JsonSerialization::ApplyPatch(rootValue, m_settings.GetAllocator(), jsonPatch, mergeApproach, m_applyPatchSettings); } else { @@ -1180,4 +1141,13 @@ namespace AZ return true; } + + void SettingsRegistryImpl::SetApplyPatchSettings(const AZ::JsonApplyPatchSettings& applyPatchSettings) + { + m_applyPatchSettings = applyPatchSettings; + } + void SettingsRegistryImpl::GetApplyPatchSettings(AZ::JsonApplyPatchSettings& applyPatchSettings) + { + applyPatchSettings = m_applyPatchSettings; + } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h index 0cd5da131a..a80c12534b 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -35,9 +36,6 @@ namespace AZ AZ_CLASS_ALLOCATOR(SettingsRegistryImpl, AZ::OSAllocator, 0); AZ_RTTI(AZ::SettingsRegistryImpl, "{E9C34190-F888-48CA-83C9-9F24B4E21D72}", AZ::SettingsRegistryInterface); - static constexpr size_t MaxFilePathLength = AZ_MAX_PATH_LEN; - static constexpr size_t MaxJsonPathLength = 1024; - static constexpr size_t MaxCommandLineArgumentLength = 1024; static constexpr size_t MaxRegistryFolderEntries = 128; SettingsRegistryImpl(); @@ -80,11 +78,14 @@ namespace AZ bool MergeSettingsFolder(AZStd::string_view path, const Specializations& specializations, AZStd::string_view platform, AZStd::string_view rootKey = "", AZStd::vector* scratchBuffer = nullptr) override; + void SetApplyPatchSettings(const AZ::JsonApplyPatchSettings& applyPatchSettings) override; + void GetApplyPatchSettings(AZ::JsonApplyPatchSettings& applyPatchSettings) override; + private: using TagList = AZStd::fixed_vector; struct RegistryFile { - char m_relativePath[MaxFilePathLength]{ 0 }; + AZ::IO::FixedMaxPathString m_relativePath; TagList m_tags; bool m_isPatch{ false }; bool m_isPlatformFile{ false }; @@ -109,5 +110,6 @@ namespace AZ rapidjson::Document m_settings; JsonSerializerSettings m_serializationSettings; JsonDeserializerSettings m_deserializationSettings; + JsonApplyPatchSettings m_applyPatchSettings; }; } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 56dfbdcb71..82bf1db484 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -340,46 +340,6 @@ namespace AZ::SettingsRegistryMergeUtils return sectionName; } - // Encodes a key, value delimited line such that the entire "key" can be stored as a single - // JSON Pointer key by escaping the tilde(~) and forward slash(/) - template - static AZStd::fixed_string EncodeLineForJsonPointer(AZStd::string_view token, - const AZ::SettingsRegistryInterface::CommandLineArgumentSettings::DelimiterFunc& delimiterFunc) - { - if (!delimiterFunc) - { - // Since the delimiter function is not valid, return the token unchanged - return AZStd::fixed_string{ token }; - } - // Iterate over the line and escape the '~' and '/' values - AZStd::fixed_string encodedToken; - size_t chIndex = 0; - for (; chIndex < token.size(); ++chIndex) - { - const char ch = token[chIndex]; - if (delimiterFunc(ch)) - { - // If the delimiter is found, this indicates that the end of the key has been found - break; - } - switch (ch) - { - case '~': - encodedToken += "~0"; - break; - case '/': - encodedToken += "~1"; - break; - default: - encodedToken += ch; - } - } - - // Copy over the rest of the post delimited line to the encoded token - encodedToken.append(token.data() + chIndex, token.data() + token.size()); - return encodedToken; - } - void QuerySpecializationsFromRegistry(SettingsRegistryInterface& registry, SettingsRegistryInterface::Specializations& specializations) { // Append any specializations stored in the registry @@ -499,14 +459,7 @@ namespace AZ::SettingsRegistryMergeUtils } } - // Check if the "key" portion of the line has '~' or '/' as the SettingsRegistry uses JSON Pointer - // to set the "value" portion. Those characters need to be escaped with ~0 and ~1 respectively - // to allow them to be embedded in a single json key - // Iterate over the line and escape the '~' and '/' values - AZStd::fixed_string escapedLine = EncodeLineForJsonPointer(line, - configParserSettings.m_commandLineSettings.m_delimiterFunc); - - registry.MergeCommandLineArgument(escapedLine, currentJsonPointerPath, configParserSettings.m_commandLineSettings); + registry.MergeCommandLineArgument(line, currentJsonPointerPath, configParserSettings.m_commandLineSettings); // Skip past the newline character if found frontIter = lineEndIter + (foundNewLine ? 1 : 0); @@ -599,6 +552,34 @@ namespace AZ::SettingsRegistryMergeUtils ? devWriteStorage.value() : projectUserPath.Native()); + // Set the project in-memory build path if the ProjectBuildPath key has been supplied + if (AZ::IO::FixedMaxPath projectBuildPath; registry.Get(projectBuildPath.Native(), ProjectBuildPath)) + { + registry.Remove(FilePathKey_ProjectBuildPath); + registry.Remove(FilePathKey_ProjectConfigurationBinPath); + AZ::IO::FixedMaxPath buildConfigurationPath = normalizedProjectPath / projectBuildPath; + if (IO::SystemFile::Exists(buildConfigurationPath.c_str())) + { + registry.Set(FilePathKey_ProjectBuildPath, buildConfigurationPath.LexicallyNormal().Native()); + } + + // Add the specific build configuration paths to the Settings Registry + // First try /bin/$ and if that path doesn't exist + // try /bin/$/$ + buildConfigurationPath /= "bin"; + if (IO::SystemFile::Exists((buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE).c_str())) + { + registry.Set(FilePathKey_ProjectConfigurationBinPath, + (buildConfigurationPath / AZ_BUILD_CONFIGURATION_TYPE).LexicallyNormal().Native()); + } + else if (IO::SystemFile::Exists((buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME / AZ_BUILD_CONFIGURATION_TYPE).c_str())) + { + registry.Set(FilePathKey_ProjectConfigurationBinPath, + (buildConfigurationPath / AZ_TRAIT_OS_PLATFORM_CODENAME / AZ_BUILD_CONFIGURATION_TYPE).LexicallyNormal().Native()); + } + + } + // Project name - if it was set via merging project.json use that value, otherwise use the project path's folder name. auto projectNameKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey) @@ -689,6 +670,14 @@ namespace AZ::SettingsRegistryMergeUtils mergePath /= SettingsRegistryInterface::RegistryFolder; registry.MergeSettingsFolder(mergePath.Native(), specializations, platform, "", scratchBuffer); } + + AZ::IO::FixedMaxPath projectBinPath; + if (registry.Get(projectBinPath.Native(), FilePathKey_ProjectConfigurationBinPath)) + { + // Append the project build path path to the project root + projectBinPath /= SettingsRegistryInterface::RegistryFolder; + registry.MergeSettingsFolder(projectBinPath.Native(), specializations, platform, "", scratchBuffer); + } } void MergeSettingsToRegistry_EngineRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform, @@ -934,7 +923,8 @@ namespace AZ::SettingsRegistryMergeUtils "project-path", AZStd::string::format("%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)}, OptionKeyToRegsetKey{ "project-cache-path", - AZStd::string::format("%s/project_cache_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)}}; + AZStd::string::format("%s/project_cache_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)}, + OptionKeyToRegsetKey{"project-build-path", ProjectBuildPath} }; AZStd::fixed_vector overrideArgs; diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h index 4e00c0e6ec..576066c29f 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h @@ -52,6 +52,14 @@ namespace AZ::SettingsRegistryMergeUtils //! project settings can be stored inline static constexpr char FilePathKey_ProjectUserPath[] = "/Amazon/AzCore/Runtime/FilePaths/SourceProjectUserPath"; + //! User facing key which represents the root of a project cmake build tree. i.e the ${CMAKE_BINARY_DIR} + //! A relative path is taking relative to the *project* root, NOT *engine* root. + inline constexpr AZStd::string_view ProjectBuildPath = "/Amazon/Project/Settings/Build/project_build_path"; + //! In-Memory only key which stores an absolute path to the project build directory + inline constexpr AZStd::string_view FilePathKey_ProjectBuildPath = "/Amazon/AzCore/Runtime/FilePaths/ProjectBuildPath"; + //! In-Memory only key which stores the configuration directory containing the built binaries + inline constexpr AZStd::string_view FilePathKey_ProjectConfigurationBinPath = "/Amazon/AzCore/Runtime/FilePaths/ProjectConfigurationBinPath"; + //! Development write storage path may be considered temporary or cache storage on some platforms inline static constexpr char FilePathKey_DevWriteStorage[] = "/Amazon/AzCore/Runtime/FilePaths/DevWriteStorage"; @@ -128,7 +136,7 @@ namespace AZ::SettingsRegistryMergeUtils //! Callback function that is after a has been filtered through the CommentPrefixFunc //! to determine if the text matches a section header //! returns a view of the section name if the line contains a section - //! Otherwise an empty view is returend + //! Otherwise an empty view is returned using SectionHeaderFunc = AZStd::function; //! Root JSON pointer path to place all key=values pairs of configuration data within diff --git a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h index f4abbd9867..447b38e553 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h @@ -54,6 +54,9 @@ namespace AZ MOCK_METHOD5( MergeSettingsFolder, bool(AZStd::string_view, const Specializations&, AZStd::string_view, AZStd::string_view, AZStd::vector*)); + + MOCK_METHOD1(SetApplyPatchSettings, void(const JsonApplyPatchSettings&)); + MOCK_METHOD1(GetApplyPatchSettings, void(JsonApplyPatchSettings&)); }; } // namespace AZ diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/Module/DynamicModuleHandle_Android.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/Module/DynamicModuleHandle_Android.cpp index 169a4db6ff..30ec08538a 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/Module/DynamicModuleHandle_Android.cpp +++ b/Code/Framework/AzCore/Platform/Android/AzCore/Module/DynamicModuleHandle_Android.cpp @@ -17,8 +17,9 @@ namespace AZ { namespace Platform { - void GetModulePath(AZ::OSString& path) + AZ::IO::FixedMaxPath GetModulePath() { + return {}; } void* OpenModule(const AZ::OSString& fileName, bool&) @@ -26,10 +27,9 @@ namespace AZ // Android 19 does not have RTLD_NOLOAD but it should be OK since only the Editor expects to reopen modules return dlopen(fileName.c_str(), RTLD_NOW); } - - void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath) + + void ConstructModuleFullFileName(AZ::IO::FixedMaxPath&) { - fullPath = path + fileName; } } } diff --git a/Code/Framework/AzCore/Platform/Common/Apple/AzCore/Module/DynamicModuleHandle_Apple.cpp b/Code/Framework/AzCore/Platform/Common/Apple/AzCore/Module/DynamicModuleHandle_Apple.cpp index 8457ff14a6..7dd889e94d 100644 --- a/Code/Framework/AzCore/Platform/Common/Apple/AzCore/Module/DynamicModuleHandle_Apple.cpp +++ b/Code/Framework/AzCore/Platform/Common/Apple/AzCore/Module/DynamicModuleHandle_Apple.cpp @@ -10,7 +10,6 @@ * */ -#include // for AZ_MAX_PATH_LEN #include #include #include @@ -19,15 +18,9 @@ namespace AZ { namespace Platform { - void GetModulePath(AZ::OSString& path) + AZ::IO::FixedMaxPath GetModulePath() { - char exePath[AZ_MAX_PATH_LEN]; - if (AZ::Utils::GetExecutableDirectory(exePath, AZ_ARRAY_SIZE(exePath)) == - AZ::Utils::ExecutablePathResult::Success) - { - path = exePath; - path.push_back('/'); - } + return AZ::Utils::GetExecutableDirectory(); } void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen) @@ -40,10 +33,9 @@ namespace AZ } return handle; } - - void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath) + + void ConstructModuleFullFileName(AZ::IO::FixedMaxPath&) { - fullPath = path + fileName; } } } diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp index 1c16f50203..8e2b40aaca 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Module/DynamicModuleHandle_UnixLike.cpp @@ -11,9 +11,11 @@ */ #include -#include // for AZ_MAX_PATH_LEN +#include +#include #include +#include #include #include @@ -21,9 +23,9 @@ namespace AZ { namespace Platform { - void GetModulePath(AZ::OSString& path); + AZ::IO::FixedMaxPath GetModulePath(); void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen); - void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath); + void ConstructModuleFullFileName(AZ::IO::FixedMaxPath& fullPath); } class DynamicModuleHandleUnixLike @@ -36,40 +38,55 @@ namespace AZ : DynamicModuleHandle(fullFileName) , m_handle(nullptr) { - AZ::OSString path; - AZ::OSString fileName; - AZ::OSString fullPath = ""; - AZ::OSString::size_type finalSlash = m_fileName.find_last_of("/"); - if (finalSlash != AZ::OSString::npos) + AZ::IO::FixedMaxPath fullFilePath(AZStd::string_view{m_fileName}); + if (fullFilePath.HasFilename()) { - // Path up to and including final slash - path = m_fileName.substr(0, finalSlash + 1); - // Everything after the final slash - // If m_fileName ends in /, the end result is path/lib.dylib, which just fails to load. - fileName = m_fileName.substr(finalSlash + 1); - } - else - { - // If no slash found, assume empty path, only file name - path = ""; - Platform::GetModulePath(path); - fileName = m_fileName; + AZ::IO::FixedMaxPathString fileNamePath{fullFilePath.Filename().Native()}; + if (!fileNamePath.starts_with(AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX)) + { + fileNamePath = AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX + fileNamePath; + } + + if (!fileNamePath.ends_with(AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION)) + { + fileNamePath += AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION; + } + + fullFilePath.ReplaceFilename(AZStd::string_view(fileNamePath)); } - if (fileName.substr(0, 3) != AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX) + Platform::ConstructModuleFullFileName(fullFilePath); + + // Check if the module exist at the given path within the current working directory + // If it doesn't attempt to append the path to the executable path + if (!AZ::IO::SystemFile::Exists(fullFilePath.c_str())) { - fileName = AZ_TRAIT_OS_DYNAMIC_LIBRARY_PREFIX + fileName; + auto candidatePath = Platform::GetModulePath() / fullFilePath; + if (AZ::IO::SystemFile::Exists(candidatePath.c_str())) + { + fullFilePath = candidatePath; + } } - size_t extensionLen = strlen(AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION); - if (fileName.substr(fileName.length() - extensionLen, extensionLen) != AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION) + // If the path still doesn't exist at this point, check the SettingsRegistryMergeUtils + // FilePathKey_ProjectBuildPath key to see if a project-build-path argument has been supplied + if (!AZ::IO::SystemFile::Exists(fullFilePath.c_str())) { - fileName = fileName + AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if(AZ::IO::FixedMaxPath projectModulePath; + settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath)) + { + projectModulePath /= fullFilePath; + if (AZ::IO::SystemFile::Exists(projectModulePath.c_str())) + { + fullFilePath = projectModulePath; + } + } + } } - - Platform::ConstructModuleFullFileName(path, fileName, fullPath); - m_fileName = fullPath; + m_fileName = AZStd::string_view{fullFilePath.Native()}; } ~DynamicModuleHandleUnixLike() override @@ -81,9 +98,9 @@ namespace AZ { AZ::Debug::Trace::Printf("Module", "Attempting to load module:%s\n", m_fileName.c_str()); bool alreadyOpen = false; - + m_handle = Platform::OpenModule(m_fileName, alreadyOpen); - + if(m_handle) { if (alreadyOpen) diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp index 49d5360faa..9daabfb86b 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Module/DynamicModuleHandle_WinAPI.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace AZ @@ -31,13 +32,13 @@ namespace AZ { // Ensure filename ends in ".dll" // Otherwise filenames like "gem.1.0.0" fail to load (.0 is assumed to be the extension). - if (m_fileName.substr(m_fileName.length() - 4) != AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION) + if (!m_fileName.ends_with(AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION)) { - m_fileName = m_fileName + AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION; + m_fileName += AZ_TRAIT_OS_DYNAMIC_LIBRARY_EXTENSION; } AZ::IO::PathView modulePathView{ m_fileName }; - // If the module path doesn't have a directory within it, prepend it to the path + // If the module path doesn't have a directory within it, prepend the executable directory to the path // and check if the new path exist if (modulePathView.HasFilename() && !modulePathView.HasParentPath()) { @@ -54,6 +55,27 @@ namespace AZ } } } + + // If the module file path does not exist, attempt to search for the module within + // the project's build directory + if (!AZ::IO::SystemFile::Exists(m_fileName.c_str())) + { + // The Settings Registry may not exist in early startup if modules are loaded + // before the ComponentApplication is crated(such as in the Editor main.cpp) + // Therefore an existence check is needed + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if(AZ::IO::FixedMaxPath projectModulePath; + settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath)) + { + projectModulePath /= AZStd::string_view(m_fileName); + if (AZ::IO::SystemFile::Exists(projectModulePath.c_str())) + { + m_fileName.assign(projectModulePath.c_str(), projectModulePath.Native().size()); + } + } + } + } } ~DynamicModuleHandleWindows() override diff --git a/Code/Framework/AzCore/Platform/Linux/AzCore/Module/DynamicModuleHandle_Linux.cpp b/Code/Framework/AzCore/Platform/Linux/AzCore/Module/DynamicModuleHandle_Linux.cpp index 8457ff14a6..7dd889e94d 100644 --- a/Code/Framework/AzCore/Platform/Linux/AzCore/Module/DynamicModuleHandle_Linux.cpp +++ b/Code/Framework/AzCore/Platform/Linux/AzCore/Module/DynamicModuleHandle_Linux.cpp @@ -10,7 +10,6 @@ * */ -#include // for AZ_MAX_PATH_LEN #include #include #include @@ -19,15 +18,9 @@ namespace AZ { namespace Platform { - void GetModulePath(AZ::OSString& path) + AZ::IO::FixedMaxPath GetModulePath() { - char exePath[AZ_MAX_PATH_LEN]; - if (AZ::Utils::GetExecutableDirectory(exePath, AZ_ARRAY_SIZE(exePath)) == - AZ::Utils::ExecutablePathResult::Success) - { - path = exePath; - path.push_back('/'); - } + return AZ::Utils::GetExecutableDirectory(); } void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen) @@ -40,10 +33,9 @@ namespace AZ } return handle; } - - void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath) + + void ConstructModuleFullFileName(AZ::IO::FixedMaxPath&) { - fullPath = path + fileName; } } } diff --git a/Code/Framework/AzCore/Platform/iOS/AzCore/Module/DynamicModuleHandle_iOS.cpp b/Code/Framework/AzCore/Platform/iOS/AzCore/Module/DynamicModuleHandle_iOS.cpp index 8a082a01a6..569aae6f53 100644 --- a/Code/Framework/AzCore/Platform/iOS/AzCore/Module/DynamicModuleHandle_iOS.cpp +++ b/Code/Framework/AzCore/Platform/iOS/AzCore/Module/DynamicModuleHandle_iOS.cpp @@ -10,7 +10,6 @@ * */ -#include // for AZ_MAX_PATH_LEN #include #include #include @@ -19,15 +18,9 @@ namespace AZ { namespace Platform { - void GetModulePath(AZ::OSString& path) + AZ::IO::FixedMaxPath GetModulePath() { - char exePath[AZ_MAX_PATH_LEN]; - if (AZ::Utils::GetExecutableDirectory(exePath, AZ_ARRAY_SIZE(exePath)) == - AZ::Utils::ExecutablePathResult::Success) - { - AZ::OSString frameworks = "/Frameworks/"; - path = exePath + frameworks; - } + return AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "Frameworks"; } void* OpenModule(const AZ::OSString& fileName, bool& alreadyOpen) @@ -40,10 +33,15 @@ namespace AZ } return handle; } - - void ConstructModuleFullFileName(const AZ::OSString& path, const AZ::OSString& fileName, AZ::OSString& fullPath) + + void ConstructModuleFullFileName(AZ::IO::FixedMaxPath& fullPath) { - fullPath = path + fileName + ".framework/" + fileName; + // Append .framework to the name of full path + // Afterwards use the AZ::IO::Path Append function append the filename as a child + // of the framework directory + AZ::IO::FixedMaxPathString fileName = fullPath.Filename().Native(); + fullPath.ReplaceFilename(fileName + ".framework"); + fullPath /= fileName; } } } diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerStreamingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerStreamingTests.cpp index c55a95cf2a..f29c9ac6c4 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerStreamingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerStreamingTests.cpp @@ -351,6 +351,7 @@ namespace UnitTest public AZ::Data::AssetCatalog { static inline const AZ::Uuid TestAssetId{"{E970B177-5F45-44EB-A2C4-9F29D9A0B2A2}"}; + static inline const AZ::Uuid MissingAssetId{"{11111111-1111-1111-1111-111111111111}"}; static inline constexpr AZStd::string_view TestAssetPath = "test"; void SetUp() override @@ -431,24 +432,40 @@ namespace UnitTest // AssetCatalogRequestBus implementation // Minimalist mocks to provide our desired asset path or asset id - AZStd::string GetAssetPathById([[maybe_unused]] const AZ::Data::AssetId& id) override + AZStd::string GetAssetPathById(const AZ::Data::AssetId& id) override { - return TestAssetPath; + if (id == TestAssetId) + { + return TestAssetPath; + } + + return ""; } + AZ::Data::AssetId GetAssetIdByPath( - [[maybe_unused]] const char* path, [[maybe_unused]] const AZ::Data::AssetType& typeToRegister, + const char* path, [[maybe_unused]] const AZ::Data::AssetType& typeToRegister, [[maybe_unused]] bool autoRegisterIfNotFound) override { - return TestAssetId; + if (path == TestAssetPath) + { + return TestAssetId; + } + + return AZ::Data::AssetId(); } // Return the mocked-out information for our test asset - AZ::Data::AssetInfo GetAssetInfoById([[maybe_unused]] const AZ::Data::AssetId& id) override + AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override { AZ::Data::AssetInfo assetInfo; - assetInfo.m_assetId = TestAssetId; - assetInfo.m_assetType = AZ::AzTypeInfo::Uuid(); - assetInfo.m_relativePath = TestAssetPath; + + if (id == TestAssetId) + { + assetInfo.m_assetId = TestAssetId; + assetInfo.m_assetType = AZ::AzTypeInfo::Uuid(); + assetInfo.m_relativePath = TestAssetPath; + } + return assetInfo; } @@ -456,15 +473,20 @@ namespace UnitTest // Set the mocked-out asset load to have a 0-byte length so that the load skips I/O and immediately returns success AZ::Data::AssetStreamInfo GetStreamInfoForLoad( - [[maybe_unused]] const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override + const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override { EXPECT_TRUE(type == AZ::AzTypeInfo::Uuid()); AZ::Data::AssetStreamInfo info; + info.m_dataOffset = 0; - info.m_streamName = TestAssetPath; info.m_dataLen = 0; info.m_streamFlags = AZ::IO::OpenMode::ModeRead; + if (id == TestAssetId) + { + info.m_streamName = TestAssetPath; + } + return info; } @@ -489,4 +511,27 @@ namespace UnitTest EXPECT_TRUE(testAsset.IsReady()); } + // This test verifies that even if the asset loading returns immediately with an error, all of the loading code works + // successfully. The test itself loads a missing asset twice - the first time is a non-immediate error, where the error + // isn't reported until the DispatchEvents() call. The second time is an immediate error, because now the asset is already + // registered in an Error state. If the test fails, it will likely get caught in the shutdown of the test class, if any + // assets still exist at the point that the asset handler is unregistered. If they're present, then handling of the immediate + // error didn't work, as it left around extra references to the asset that haven't been cleaned up. + TEST_F(AssetManagerStreamerImmediateCompletionTests, ImmediateAssetError_WorksSuccessfully) + { + AZ::Data::AssetLoadParameters loadParams; + + // Attempt to load a missing asset the first time. It will get an error, but not until the DispatchEvents() call happens. + auto testAsset1 = AssetManager::Instance().GetAsset(MissingAssetId, AZ::Data::AssetLoadBehavior::Default, loadParams); + AZ::Data::AssetManager::Instance().DispatchEvents(); + EXPECT_TRUE(testAsset1.IsError()); + + // While the reference to the missing asset still exists, try to get it again. This will cause a more immediate error in + // the AssetContainer code, which should still get handled correctly. In the failure condition, it will instead leave the + // AssetContainer in a state where it never sends the final OnAssetContainerReady/Canceled message. + auto testAsset2 = AssetManager::Instance().GetAsset(MissingAssetId, AZ::Data::AssetLoadBehavior::Default, loadParams); + AZ::Data::AssetManager::Instance().DispatchEvents(); + EXPECT_TRUE(testAsset2.IsError()); + } + } // namespace UnitTest diff --git a/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp b/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp index e56ae53646..5f3debca90 100644 --- a/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp +++ b/Code/Framework/AzCore/Tests/Console/ConsoleTests.cpp @@ -13,24 +13,25 @@ #include #include #include - +#include +#include namespace AZ { using namespace UnitTest; - AZ_CVAR(bool, testBool, false, nullptr, ConsoleFunctorFlags::Null, ""); - AZ_CVAR(char, testChar, 0, nullptr, ConsoleFunctorFlags::Null, ""); - AZ_CVAR(int8_t, testInt8, 0, nullptr, ConsoleFunctorFlags::Null, ""); - AZ_CVAR(int16_t, testInt16, 0, nullptr, ConsoleFunctorFlags::Null, ""); - AZ_CVAR(int32_t, testInt32, 0, nullptr, ConsoleFunctorFlags::Null, ""); - AZ_CVAR(int64_t, testInt64, 0, nullptr, ConsoleFunctorFlags::Null, ""); - AZ_CVAR(uint8_t, testUInt8, 0, nullptr, ConsoleFunctorFlags::Null, ""); + AZ_CVAR(bool, testBool, false, nullptr, ConsoleFunctorFlags::Null, ""); + AZ_CVAR(char, testChar, 0, nullptr, ConsoleFunctorFlags::Null, ""); + AZ_CVAR(int8_t, testInt8, 0, nullptr, ConsoleFunctorFlags::Null, ""); + AZ_CVAR(int16_t, testInt16, 0, nullptr, ConsoleFunctorFlags::Null, ""); + AZ_CVAR(int32_t, testInt32, 0, nullptr, ConsoleFunctorFlags::Null, ""); + AZ_CVAR(int64_t, testInt64, 0, nullptr, ConsoleFunctorFlags::Null, ""); + AZ_CVAR(uint8_t, testUInt8, 0, nullptr, ConsoleFunctorFlags::Null, ""); AZ_CVAR(uint16_t, testUInt16, 0, nullptr, ConsoleFunctorFlags::Null, ""); AZ_CVAR(uint32_t, testUInt32, 0, nullptr, ConsoleFunctorFlags::Null, ""); AZ_CVAR(uint64_t, testUInt64, 0, nullptr, ConsoleFunctorFlags::Null, ""); - AZ_CVAR(float, testFloat, 0, nullptr, ConsoleFunctorFlags::Null, ""); - AZ_CVAR(double, testDouble, 0, nullptr, ConsoleFunctorFlags::Null, ""); + AZ_CVAR(float, testFloat, 0, nullptr, ConsoleFunctorFlags::Null, ""); + AZ_CVAR(double, testDouble, 0, nullptr, ConsoleFunctorFlags::Null, ""); AZ_CVAR(AZ::CVarFixedString, testString, "default", nullptr, ConsoleFunctorFlags::Null, ""); @@ -189,7 +190,7 @@ namespace AZ TEST_F(ConsoleTests, CVar_GetSetTest_Vector2) { - testVec2 = AZ::Vector2{ 0.0f, 0.0f}; + testVec2 = AZ::Vector2{ 0.0f, 0.0f }; TestCVarHelper(testVec2, "testVec2", "testVec2 1 1", "testVec2 asdf", AZ::Vector2(100, 100), AZ::Vector2(0, 0), AZ::Vector2(1, 1)); } @@ -350,3 +351,245 @@ namespace AZ } } } + + +namespace ConsoleSettingsRegistryTests +{ + //! ConfigFile MergeUtils Test + struct ConfigFileParams + { + AZStd::string_view m_testConfigFileName; + AZStd::string_view m_testConfigContents; + }; + class ConsoleSettingsRegistryFixture + : public UnitTest::ScopedAllocatorSetupFixture + , public ::testing::WithParamInterface + { + public: + void SetUp() override + { + m_registry = AZStd::make_unique(); + // Store off the old global settings registry to restore after each test + m_oldSettingsRegistry = AZ::SettingsRegistry::Get(); + if (m_oldSettingsRegistry != nullptr) + { + AZ::SettingsRegistry::Unregister(m_oldSettingsRegistry); + } + AZ::SettingsRegistry::Register(m_registry.get()); + + // Create a TestFile in the Test Directory + m_testFolder = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "ConsoleTestFolder"; + auto configFileParams = GetParam(); + CreateTestFile(m_testFolder / configFileParams.m_testConfigFileName, configFileParams.m_testConfigContents); + } + + void TearDown() override + { + // Remove the Test Directory + DeleteFolderRecursive(m_testFolder); + + // Restore the old global settings registry + AZ::SettingsRegistry::Unregister(m_registry.get()); + if (m_oldSettingsRegistry != nullptr) + { + AZ::SettingsRegistry::Register(m_oldSettingsRegistry); + m_oldSettingsRegistry = {}; + } + m_registry.reset(); + } + + void TestClassFunc(const AZ::ConsoleCommandContainer& someStrings) + { + m_stringArgCount = someStrings.size(); + } + + AZ_CONSOLEFUNC(ConsoleSettingsRegistryFixture, TestClassFunc, AZ::ConsoleFunctorFlags::Null, ""); + + static void DeleteFolderRecursive(const AZ::IO::PathView& path) + { + auto callback = [&path](AZStd::string_view filename, bool isFile) -> bool + { + if (isFile) + { + auto filePath = AZ::IO::FixedMaxPath(path) / filename; + AZ::IO::SystemFile::Delete(filePath.c_str()); + } + else + { + if (filename != "." && filename != "..") + { + auto folderPath = AZ::IO::FixedMaxPath(path) / filename; + DeleteFolderRecursive(folderPath); + } + } + return true; + }; + auto searchPath = AZ::IO::FixedMaxPath(path) / "*"; + AZ::IO::SystemFile::FindFiles(searchPath.c_str(), callback); + AZ::IO::SystemFile::DeleteDir(AZ::IO::FixedMaxPathString(path.Native()).c_str()); + } + + static bool CreateTestFile(const AZ::IO::FixedMaxPath& testPath, AZStd::string_view content) + { + AZ::IO::SystemFile file; + if (!file.Open(testPath.c_str(), AZ::IO::SystemFile::OpenMode::SF_OPEN_CREATE + | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY)) + { + AZ_Assert(false, "Unable to open test file for writing: %s", testPath.c_str()); + return false; + } + + if (file.Write(content.data(), content.size()) != content.size()) + { + AZ_Assert(false, "Unable to write content to test file: %s", testPath.c_str()); + return false; + } + + return true; + } + + protected: + size_t m_stringArgCount{}; + AZStd::unique_ptr m_registry; + AZ::IO::FixedMaxPath m_testFolder; + + private: + AZ::SettingsRegistryInterface* m_oldSettingsRegistry{}; + }; + + static bool s_consoleFreeFunctionInvoked = false; + static void TestSettingsRegistryFreeFunc(const AZ::ConsoleCommandContainer& someStrings) + { + EXPECT_TRUE(someStrings.empty()); + s_consoleFreeFunctionInvoked = true; + } + + AZ_CONSOLEFREEFUNC(TestSettingsRegistryFreeFunc, AZ::ConsoleFunctorFlags::Null, ""); + + TEST_P(ConsoleSettingsRegistryFixture, Console_AbleToLoadSettingsFile_Successfully) + { + AZ::Console testConsole(*m_registry); + testConsole.LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead()); + AZ::Interface::Register(&testConsole); + AZ_CVAR_SCOPED(int32_t, testInit, 0, nullptr, AZ::ConsoleFunctorFlags::Null, ""); + s_consoleFreeFunctionInvoked = false; + testInit = {}; + AZ::testChar = {}; + AZ::testBool = {}; + AZ::testInt8 = {}; + AZ::testInt16 = {}; + AZ::testInt32 = {}; + AZ::testInt64 = {}; + AZ::testUInt8 = {}; + AZ::testUInt16 = {}; + AZ::testUInt32 = {}; + AZ::testUInt64 = {}; + AZ::testFloat= {}; + AZ::testDouble = {}; + AZ::testString = {}; + + auto configFileParams = GetParam(); + auto testFilePath = m_testFolder / configFileParams.m_testConfigFileName; + EXPECT_TRUE(AZ::IO::SystemFile::Exists(testFilePath.c_str())); + testConsole.ExecuteConfigFile(testFilePath.Native()); + EXPECT_TRUE(s_consoleFreeFunctionInvoked); + EXPECT_EQ(3, testInit); + EXPECT_TRUE(static_cast(AZ::testBool)); + EXPECT_EQ('Q', AZ::testChar); + EXPECT_EQ(24, AZ::testInt8); + EXPECT_EQ(-32, AZ::testInt16); + EXPECT_EQ(41, AZ::testInt32); + EXPECT_EQ(-51, AZ::testInt64); + EXPECT_EQ(3, AZ::testUInt8); + EXPECT_EQ(5, AZ::testUInt16); + EXPECT_EQ(6, AZ::testUInt32); + EXPECT_EQ(0xFFFF'FFFF'FFFF'FFFF, AZ::testUInt64); + EXPECT_FLOAT_EQ(1.0f, AZ::testFloat); + EXPECT_DOUBLE_EQ(2, AZ::testDouble); + EXPECT_STREQ("Stable", static_cast(AZ::testString).c_str()); + EXPECT_EQ(3, m_stringArgCount); + AZ::Interface::Unregister(&testConsole); + } + + + static constexpr AZStd::string_view UserINIStyleContent = + R"( + testInit = 3 + testBool true + testChar Q + testInt8 24 + testInt16 -32 + testInt32 41 + testInt64 -51 + testUInt8 3 + testUInt16 5 + testUInt32 6 + testUInt64 18446744073709551615 + testFloat 1.0 + testDouble 2 + testString Stable + ConsoleSettingsRegistryFixture.testClassFunc Foo Bar Baz + TestSettingsRegistryFreeFunc + )"; + + static constexpr AZStd::string_view UserJsonMergePatchContent = + R"( + { + "Amazon": { + "AzCore": { + "Runtime": { + "ConsoleCommands": { + "testInit": 3, + "testBool": true, + "testChar": "Q", + "testInt8": 24, + "testInt16": -32, + "testInt32": 41, + "testInt64": -51, + "testUInt8": 3, + "testUInt16": 5, + "testUInt32": 6, + "testUInt64": 18446744073709551615, + "testFloat": 1.0, + "testDouble": 2, + "testString": "Stable", + "ConsoleSettingsRegistryFixture.testClassFunc": "Foo Bar Baz", + "TestSettingsRegistryFreeFunc": "" + } + } + } + } + } + )"; + static constexpr AZStd::string_view UserJsonPatchContent = + R"( + [ + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testInit", "value": 3 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testBool", "value": true }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testChar", "value": "Q" }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testInt8", "value": 24 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testInt16", "value": -32 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testInt32", "value": 41 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testInt64", "value": -51 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testUInt8", "value": 3 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testUInt16", "value": 5 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testUInt32", "value": 6 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testUInt64", "value": 18446744073709551615 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testFloat", "value": 1.0 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testDouble", "value": 2 }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/testString", "value": "Stable" }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/ConsoleSettingsRegistryFixture.testClassFunc", "value": "Foo Bar Baz" }, + { "op": "add", "path": "/Amazon/AzCore/Runtime/ConsoleCommands/TestSettingsRegistryFreeFunc", "value": "" } + ] + )"; + + INSTANTIATE_TEST_CASE_P( + ExecuteCommandFromSettingsFile, + ConsoleSettingsRegistryFixture, + ::testing::Values( + ConfigFileParams{"user.cfg", UserINIStyleContent}, + ConfigFileParams{"user.setreg", UserJsonMergePatchContent}, + ConfigFileParams{"user.setregpatch", UserJsonPatchContent} + ) + ); +} diff --git a/Code/Framework/AzCore/Tests/Settings/SettingsRegistryConsoleUtilsTests.cpp b/Code/Framework/AzCore/Tests/Settings/SettingsRegistryConsoleUtilsTests.cpp index fb9b1a4aa4..c18e83ab63 100644 --- a/Code/Framework/AzCore/Tests/Settings/SettingsRegistryConsoleUtilsTests.cpp +++ b/Code/Framework/AzCore/Tests/Settings/SettingsRegistryConsoleUtilsTests.cpp @@ -55,7 +55,7 @@ namespace SettingsRegistryConsoleUtilsTests { constexpr const char* settingsKey = "/TestKey"; constexpr const char* expectedValue = "TestValue"; - AZ::Console testConsole; + AZ::Console testConsole(*m_registry); AZ::SettingsRegistryConsoleUtils::ConsoleFunctorHandle handle{ AZ::SettingsRegistryConsoleUtils::RegisterAzConsoleCommands(*m_registry, testConsole) }; EXPECT_TRUE(testConsole.PerformCommand(AZ::SettingsRegistryConsoleUtils::SettingsRegistrySet, { settingsKey, expectedValue })); @@ -69,7 +69,7 @@ namespace SettingsRegistryConsoleUtilsTests { constexpr const char* settingsKey = "/TestKey"; constexpr const char* expectedValue = "TestValue"; - AZ::Console testConsole; + AZ::Console testConsole(*m_registry); // Scopes the console functor handle so that it destructs and unregisters the console functors { @@ -89,7 +89,7 @@ namespace SettingsRegistryConsoleUtilsTests constexpr const char* settingsKey2 = "/TestKey2"; constexpr const char* expectedValue = R"(TestValue)"; constexpr const char* expectedValue2 = R"(Hello World)"; - AZ::Console testConsole; + AZ::Console testConsole(*m_registry); AZ::SettingsRegistryConsoleUtils::ConsoleFunctorHandle handle{ AZ::SettingsRegistryConsoleUtils::RegisterAzConsoleCommands(*m_registry, testConsole) }; @@ -109,7 +109,7 @@ namespace SettingsRegistryConsoleUtilsTests constexpr const char* settingsKey2 = "/TestKey2"; constexpr const char* expectedValue = R"(TestValue)"; constexpr const char* expectedValue2 = R"(Hello World)"; - AZ::Console testConsole; + AZ::Console testConsole(*m_registry); // Add settings to settings registry EXPECT_TRUE(m_registry->Set(settingsKey, expectedValue)); @@ -137,7 +137,7 @@ namespace SettingsRegistryConsoleUtilsTests constexpr const char* settingsKey2 = "/TestKey2"; constexpr const char* expectedValue = R"(TestValue)"; constexpr const char* expectedValue2 = R"(Hello World)"; - AZ::Console testConsole; + AZ::Console testConsole(*m_registry); AZ::SettingsRegistryConsoleUtils::ConsoleFunctorHandle handle{ AZ::SettingsRegistryConsoleUtils::RegisterAzConsoleCommands(*m_registry, testConsole) }; @@ -195,7 +195,7 @@ namespace SettingsRegistryConsoleUtilsTests constexpr const char* SettingsKey2 = "TestKey2"; constexpr const char* ExpectedValue = R"(TestValue)"; constexpr const char* ExpectedValue2 = R"(Hello World)"; - AZ::Console testConsole; + AZ::Console testConsole(*m_registry); AZ::SettingsRegistryConsoleUtils::ConsoleFunctorHandle handle{ AZ::SettingsRegistryConsoleUtils::RegisterAzConsoleCommands(*m_registry, testConsole) }; diff --git a/Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp b/Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp index f7651664bd..fc07db5b52 100644 --- a/Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp +++ b/Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp @@ -1228,27 +1228,33 @@ namespace SettingsRegistryTests TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyIsTooLong_ReturnsFalse) { - AZStd::string argument = AZStd::string::format("Te%*cst=Value", aznumeric_cast(AZ::SettingsRegistryImpl::MaxJsonPathLength), ' '); + constexpr int LongKeySize = 1024; + AZStd::string argument = AZStd::string::format("Te%*cst=Value", LongKeySize, ' '); EXPECT_FALSE(m_registry->MergeCommandLineArgument(argument, {}, {})); } TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyIsTooLongWithDivider_ReturnsFalse) { - AZStd::string argument = AZStd::string::format("/Te%*cst=Value", aznumeric_cast(AZ::SettingsRegistryImpl::MaxJsonPathLength), ' '); + constexpr int LongKeySize = 1024; + AZStd::string argument = AZStd::string::format("/Te%*cst=Value", LongKeySize, ' '); EXPECT_FALSE(m_registry->MergeCommandLineArgument(argument, "/Path", {})); } TEST_F(SettingsRegistryTest, MergeCommandLineArgument_ValueIsTooLong_ReturnsFalse) { - AZStd::string argument = AZStd::string::format("Test=Val%*cue", aznumeric_cast(AZ::SettingsRegistryImpl::MaxCommandLineArgumentLength), ' '); + constexpr int LongValueSize = 1024; + AZStd::string argument = AZStd::string::format("Test=Val%*cue", LongValueSize, ' '); EXPECT_FALSE(m_registry->MergeCommandLineArgument(argument, {}, {})); EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType("/Test")); } - TEST_F(SettingsRegistryTest, MergeCommandLineArgument_MissingValue_ReturnsFalse) + TEST_F(SettingsRegistryTest, MergeCommandLineArgument_MissingValue_ReturnsEmptyString) { - EXPECT_FALSE(m_registry->MergeCommandLineArgument("Test=", {}, {})); - EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType("/Test")); + EXPECT_TRUE(m_registry->MergeCommandLineArgument("Test=", {}, {})); + EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Test")); + AZ::SettingsRegistryInterface::FixedValueString value; + EXPECT_TRUE(m_registry->Get(value, "/Test")); + EXPECT_TRUE(value.empty()); } TEST_F(SettingsRegistryTest, MergeCommandLineArgument_MissingKey_ReturnsFalse) @@ -1271,9 +1277,13 @@ namespace SettingsRegistryTests EXPECT_FALSE(m_registry->MergeCommandLineArgument(" =Value", {}, {})); } - TEST_F(SettingsRegistryTest, MergeCommandLineArgument_ValueIsSpaces_ReturnsFalse) + TEST_F(SettingsRegistryTest, MergeCommandLineArgument_ValueIsSpaces_ReturnsEmptyString) { - EXPECT_FALSE(m_registry->MergeCommandLineArgument("Key= ", {}, {})); + EXPECT_TRUE(m_registry->MergeCommandLineArgument("Key= ", {}, {})); + EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType("/Key")); + AZ::SettingsRegistryInterface::FixedValueString value; + EXPECT_TRUE(m_registry->Get(value, "/Key")); + EXPECT_TRUE(value.empty()); } TEST_F(SettingsRegistryTest, MergeCommandLineArgument_KeyAndValueAreSpaces_ReturnsFalse) @@ -1367,9 +1377,8 @@ namespace SettingsRegistryTests TEST_F(SettingsRegistryTest, MergeSettingsFile_PathAsSubStringThatsTooLong_ReturnsFalse) { - char path[AZ::SettingsRegistryImpl::MaxFilePathLength + 1]; - memset(path, '1', sizeof(path)); - AZStd::string_view subPath(path, AZ::SettingsRegistryImpl::MaxFilePathLength); + constexpr AZStd::fixed_string path(AZ::IO::MaxPathLength + 1, '1'); + const AZStd::string_view subPath(path); AZ_TEST_START_TRACE_SUPPRESSION; bool result = m_registry->MergeSettingsFile(subPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}, nullptr); @@ -1719,8 +1728,7 @@ namespace SettingsRegistryTests TEST_F(SettingsRegistryTest, MergeSettingsFolder_PathTooLong_ReportsErrorAndReturnsFalse) { - char path[AZ::SettingsRegistryImpl::MaxFilePathLength + 1]{}; - memset(path, 'a', AZ_ARRAY_SIZE(path)); + constexpr AZStd::fixed_string path(AZ::IO::MaxPathLength + 1, 'a'); AZ_TEST_START_TRACE_SUPPRESSION; bool result = m_registry->MergeSettingsFolder(path, { "editor", "test" }, {}, nullptr); @@ -1741,7 +1749,7 @@ namespace SettingsRegistryTests m_testFolder->push_back(AZ_CORRECT_DATABASE_SEPARATOR); *m_testFolder += AZ::SettingsRegistryInterface::RegistryFolder; bool result = m_registry->MergeSettingsFolder(*m_testFolder, { "editor", "test" }, {}, nullptr); - AZ_TEST_STOP_TRACE_SUPPRESSION(2); + EXPECT_GT(::UnitTest::TestRunner::Instance().StopAssertTests(), 0); EXPECT_FALSE(result); EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0")); // Folder and specialization settings. @@ -1751,11 +1759,5 @@ namespace SettingsRegistryTests EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1/Path")); EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1/File1")); EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/1/File2")); - - EXPECT_EQ(AZ::SettingsRegistryInterface::Type::Object, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2")); - EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2/Error")); - EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2/Path")); - EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2/File1")); - EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/2/File2")); } } // namespace SettingsRegistryTests diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index dc6ae684cf..e02892de4e 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -236,8 +236,6 @@ namespace AzFramework // Archive classes relies on the FileIOBase DirectInstance to close // files properly m_directFileIO.reset(); - - // The AZ::Console skips destruction and always leaks to allow it to be used in static memory } void Application::Start(const Descriptor& descriptor, const StartupParameters& startupParameters) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveVars.h b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveVars.h index 4e89e0a45c..f5f1428ed6 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveVars.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveVars.h @@ -24,7 +24,7 @@ namespace AZ::IO ePakPriorityPakOnly = 2 }; - // variables that control behavior of Archive/StreamEngine subsystems + // variables that control behavior of the Archive subsystem struct ArchiveVars { #if defined(_RELEASE) diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp index 3c05887a89..9083cb7d0d 100644 --- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp @@ -881,7 +881,7 @@ namespace AzFramework serializeContext->ClassDeprecate("NetBindable", "{80206665-D429-4703-B42E-94434F82F381}"); serializeContext->Class() - ->Version(4, &TransformComponentVersionConverter) + ->Version(5, &TransformComponentVersionConverter) ->Field("Parent", &TransformComponent::m_parentId) ->Field("Transform", &TransformComponent::m_worldTM) ->Field("LocalTransform", &TransformComponent::m_localTM) diff --git a/Code/Framework/AzFramework/AzFramework/Font/FontInterface.h b/Code/Framework/AzFramework/AzFramework/Font/FontInterface.h index 7c5bcce6d6..b64b61e22c 100644 --- a/Code/Framework/AzFramework/AzFramework/Font/FontInterface.h +++ b/Code/Framework/AzFramework/AzFramework/Font/FontInterface.h @@ -40,17 +40,18 @@ namespace AzFramework //! Standard parameters for drawing text on screen struct TextDrawParameters { - ViewportId m_drawViewportId = InvalidViewportId; //! Viewport to draw into - AZ::Vector3 m_position; //! world space position for 3d draws, screen space x,y,depth for 2d. - AZ::Color m_color = AZ::Colors::White; //! Color to draw the text - AZ::Vector2 m_scale = AZ::Vector2(1.0f); //! font scale - TextHorizontalAlignment m_hAlign = TextHorizontalAlignment::Left; //! Horizontal text alignment - TextVerticalAlignment m_vAlign = TextVerticalAlignment::Top; //! Vertical text alignment - bool m_monospace = false; //! disable character proportional spacing - bool m_depthTest = false; //! Test character against the depth buffer - bool m_virtual800x600ScreenSize = true; //! Text placement and size are scaled relative to a virtual 800x600 resolution - bool m_scaleWithWindow = false; //! Font gets bigger as the window gets bigger - bool m_multiline = true; //! text respects ascii newline characters + ViewportId m_drawViewportId = InvalidViewportId; //!< Viewport to draw into + AZ::Vector3 m_position; //!< world space position for 3d draws, screen space x,y,depth for 2d. + AZ::Color m_color = AZ::Colors::White; //!< Color to draw the text + AZ::Vector2 m_scale = AZ::Vector2(1.0f); //!< font scale + float m_lineSpacing; //!< Spacing between new lines, as a percentage of m_scale. + TextHorizontalAlignment m_hAlign = TextHorizontalAlignment::Left; //!< Horizontal text alignment + TextVerticalAlignment m_vAlign = TextVerticalAlignment::Top; //!< Vertical text alignment + bool m_monospace = false; //!< disable character proportional spacing + bool m_depthTest = false; //!< Test character against the depth buffer + bool m_virtual800x600ScreenSize = true; //!< Text placement and size are scaled relative to a virtual 800x600 resolution + bool m_scaleWithWindow = false; //!< Font gets bigger as the window gets bigger + bool m_multiline = true; //!< text respects ascii newline characters }; class FontDrawInterface @@ -63,10 +64,13 @@ namespace AzFramework virtual void DrawScreenAlignedText2d( const TextDrawParameters& params, - const AZStd::string_view& string) = 0; + AZStd::string_view text) = 0; virtual void DrawScreenAlignedText3d( const TextDrawParameters& params, - const AZStd::string_view& string) = 0; + AZStd::string_view text) = 0; + virtual AZ::Vector2 GetTextSize( + const TextDrawParameters& params, + AZStd::string_view text) = 0; }; class FontQueryInterface diff --git a/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp b/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp index 30343b1322..cdfad7f116 100644 --- a/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp @@ -979,7 +979,7 @@ namespace AzFramework }; serializeContext->Class() - ->Version(3, converter) + ->Version(4, converter) ->Field("ContextID", &ScriptComponent::m_contextId) ->Field("Properties", &ScriptComponent::m_properties) ->Field("Script", &ScriptComponent::m_script) diff --git a/Code/CryEngine/CryCommon/ThermalInfo.h b/Code/Framework/AzFramework/AzFramework/Thermal/ThermalInfo.h similarity index 100% rename from Code/CryEngine/CryCommon/ThermalInfo.h rename to Code/Framework/AzFramework/AzFramework/Thermal/ThermalInfo.h diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp index 5af44a81bc..4b8fbca36a 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ClickDetector.cpp @@ -1,68 +1,68 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#include -#include - -namespace AzFramework -{ - ClickDetector::ClickOutcome ClickDetector::DetectClick(const ClickEvent clickEvent, const ScreenVector& cursorDelta) - { - if (clickEvent == ClickEvent::Down) - { - const auto now = std::chrono::steady_clock::now(); - if (m_tryBeginTime) - { - const std::chrono::duration diff = now - m_tryBeginTime.value(); - if (diff.count() < m_doubleClickInterval) - { - return ClickOutcome::Nil; - } - } - - m_detectionState = DetectionState::WaitingForMove; - m_moveAccumulator = 0.0f; - - m_tryBeginTime = now; - } - else if (clickEvent == ClickEvent::Up) - { - const auto clickOutcome = [detectionState = m_detectionState] { - if (detectionState == DetectionState::WaitingForMove) - { - return ClickOutcome::Click; - } - if (detectionState == DetectionState::Moved) - { - return ClickOutcome::Release; - } - return ClickOutcome::Nil; - }(); - - m_detectionState = DetectionState::Nil; - return clickOutcome; - } - - if (m_detectionState == DetectionState::WaitingForMove) - { - // only allow the action to begin if the mouse has been moved a small amount - m_moveAccumulator += ScreenVectorLength(cursorDelta); - if (m_moveAccumulator > m_deadZone) - { - m_detectionState = DetectionState::Moved; - return ClickOutcome::Move; - } - } - - return ClickOutcome::Nil; - } -} // namespace AzFramework +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include + +namespace AzFramework +{ + ClickDetector::ClickOutcome ClickDetector::DetectClick(const ClickEvent clickEvent, const ScreenVector& cursorDelta) + { + if (clickEvent == ClickEvent::Down) + { + const auto now = std::chrono::steady_clock::now(); + if (m_tryBeginTime) + { + const std::chrono::duration diff = now - m_tryBeginTime.value(); + if (diff.count() < m_doubleClickInterval) + { + return ClickOutcome::Nil; + } + } + + m_detectionState = DetectionState::WaitingForMove; + m_moveAccumulator = 0.0f; + + m_tryBeginTime = now; + } + else if (clickEvent == ClickEvent::Up) + { + const auto clickOutcome = [detectionState = m_detectionState] { + if (detectionState == DetectionState::WaitingForMove) + { + return ClickOutcome::Click; + } + if (detectionState == DetectionState::Moved) + { + return ClickOutcome::Release; + } + return ClickOutcome::Nil; + }(); + + m_detectionState = DetectionState::Nil; + return clickOutcome; + } + + if (m_detectionState == DetectionState::WaitingForMove) + { + // only allow the action to begin if the mouse has been moved a small amount + m_moveAccumulator += ScreenVectorLength(cursorDelta); + if (m_moveAccumulator > m_deadZone) + { + m_detectionState = DetectionState::Moved; + return ClickOutcome::Move; + } + } + + return ClickOutcome::Nil; + } +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CursorState.h b/Code/Framework/AzFramework/AzFramework/Viewport/CursorState.h index 8bcbaabdee..437392f0fc 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CursorState.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CursorState.h @@ -1,56 +1,56 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#pragma once - -#include - -#include - -namespace AzFramework -{ - //! Utility type to wrap a current and last cursor position. - struct CursorState - { - //! Returns the delta between the current and last cursor position. - [[nodiscard]] ScreenVector CursorDelta() const; - //! Call this in a 'handle event' call to update the most recent cursor position. - void SetCurrentPosition(const ScreenPoint& currentPosition); - //! Call this in an 'update' call to copy the current cursor position to the last - //! cursor position. - void Update(); - - private: - AZStd::optional m_lastCursorPosition; - AZStd::optional m_currentCursorPosition; - }; - - inline void CursorState::SetCurrentPosition(const ScreenPoint& currentPosition) - { - m_currentCursorPosition = currentPosition; - } - - inline ScreenVector CursorState::CursorDelta() const - { - return m_currentCursorPosition.has_value() && m_lastCursorPosition.has_value() - ? m_currentCursorPosition.value() - m_lastCursorPosition.value() - : ScreenVector(0, 0); - } - - inline void CursorState::Update() - { - if (m_currentCursorPosition.has_value()) - { - m_lastCursorPosition = m_currentCursorPosition; - } - } -} // namespace AzFramework +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once + +#include + +#include + +namespace AzFramework +{ + //! Utility type to wrap a current and last cursor position. + struct CursorState + { + //! Returns the delta between the current and last cursor position. + [[nodiscard]] ScreenVector CursorDelta() const; + //! Call this in a 'handle event' call to update the most recent cursor position. + void SetCurrentPosition(const ScreenPoint& currentPosition); + //! Call this in an 'update' call to copy the current cursor position to the last + //! cursor position. + void Update(); + + private: + AZStd::optional m_lastCursorPosition; + AZStd::optional m_currentCursorPosition; + }; + + inline void CursorState::SetCurrentPosition(const ScreenPoint& currentPosition) + { + m_currentCursorPosition = currentPosition; + } + + inline ScreenVector CursorState::CursorDelta() const + { + return m_currentCursorPosition.has_value() && m_lastCursorPosition.has_value() + ? m_currentCursorPosition.value() - m_lastCursorPosition.value() + : ScreenVector(0, 0); + } + + inline void CursorState::Update() + { + if (m_currentCursorPosition.has_value()) + { + m_lastCursorPosition = m_currentCursorPosition; + } + } +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake index f73e67b94e..8cff479ec8 100644 --- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake +++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake @@ -296,6 +296,7 @@ set(FILES Spawnable/SpawnableSystemComponent.cpp Terrain/TerrainDataRequestBus.h Terrain/TerrainDataRequestBus.cpp + Thermal/ThermalInfo.h Platform/PlatformDefaults.h Windowing/WindowBus.h Windowing/NativeWindow.cpp diff --git a/Code/Framework/AzFramework/Platform/Android/AzFramework/Application/Application_Android.cpp b/Code/Framework/AzFramework/Platform/Android/AzFramework/Application/Application_Android.cpp index cc1b0b8035..cb003dd130 100644 --- a/Code/Framework/AzFramework/Platform/Android/AzFramework/Application/Application_Android.cpp +++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/Application/Application_Android.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -95,6 +96,7 @@ namespace AzFramework private: AndroidEventDispatcher* m_eventDispatcher; ApplicationLifecycleEvents::Event m_lastEvent; + AZStd::unique_ptr m_thermalInfoHandler; AZStd::atomic m_requestResponseReceived; AZStd::unique_ptr m_lumberyardActivity; @@ -125,6 +127,10 @@ namespace AzFramework AndroidLifecycleEvents::Bus::Handler::BusConnect(); AndroidAppRequests::Bus::Handler::BusConnect(); PermissionRequestResultNotification::Bus::Handler::BusConnect(); + +#if !defined(AZ_RELEASE_BUILD) + m_thermalInfoHandler = AZStd::make_unique(); +#endif } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Code/CryEngine/CrySystem/ThermalInfoAndroid.cpp b/Code/Framework/AzFramework/Platform/Android/AzFramework/Thermal/ThermalInfo_Android.cpp similarity index 99% rename from Code/CryEngine/CrySystem/ThermalInfoAndroid.cpp rename to Code/Framework/AzFramework/Platform/Android/AzFramework/Thermal/ThermalInfo_Android.cpp index 0c69a728fa..9a2100e1bd 100644 --- a/Code/CryEngine/CrySystem/ThermalInfoAndroid.cpp +++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/Thermal/ThermalInfo_Android.cpp @@ -11,7 +11,7 @@ */ #if !defined(AZ_RELEASE_BUILD) -#include "ThermalInfoAndroid.h" +#include "ThermalInfo_Android.h" #include #include diff --git a/Code/CryEngine/CrySystem/ThermalInfoAndroid.h b/Code/Framework/AzFramework/Platform/Android/AzFramework/Thermal/ThermalInfo_Android.h similarity index 95% rename from Code/CryEngine/CrySystem/ThermalInfoAndroid.h rename to Code/Framework/AzFramework/Platform/Android/AzFramework/Thermal/ThermalInfo_Android.h index 07d1b86f68..2781d2cf52 100644 --- a/Code/CryEngine/CrySystem/ThermalInfoAndroid.h +++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/Thermal/ThermalInfo_Android.h @@ -13,7 +13,7 @@ #pragma once #if !defined(AZ_RELEASE_BUILD) -#include +#include class ThermalInfoAndroidHandler : public ThermalInfoRequestsBus::Handler { diff --git a/Code/Framework/AzFramework/Platform/Android/platform_android_files.cmake b/Code/Framework/AzFramework/Platform/Android/platform_android_files.cmake index 38d07ec9f5..3721632fbb 100644 --- a/Code/Framework/AzFramework/Platform/Android/platform_android_files.cmake +++ b/Code/Framework/AzFramework/Platform/Android/platform_android_files.cmake @@ -36,4 +36,6 @@ set(FILES AzFramework/Process/ProcessCommon.h AzFramework/Process/ProcessWatcher_Android.cpp AzFramework/Process/ProcessCommunicator_Android.cpp + AzFramework/Thermal/ThermalInfo_Android.cpp + AzFramework/Thermal/ThermalInfo_Android.h ) diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index edd4af293d..1fb440e6e5 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -57,13 +57,16 @@ namespace AzGameFramework AZStd::vector scratchBuffer; - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); #endif + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + // Used the lowercase the platform name since the bootstrap.game...setreg is being loaded // from the asset cache root where all the files are in lowercased from regardless of the filesystem case-sensitivity static constexpr char filename[] = "bootstrap.game." AZ_BUILD_CONFIGURATION_TYPE "." AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER ".setreg"; @@ -77,6 +80,7 @@ namespace AzGameFramework #if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD) AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp index c7f47cbc04..479299a87b 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.cpp @@ -22,7 +22,9 @@ namespace AzNetworking AZ::HashValue32 HashSerializer::GetHash() const { // Just truncate the upper bits - return static_cast(m_hash); + const AZ::HashValue32 lower = static_cast(m_hash); + const AZ::HashValue32 upper = static_cast(m_hash >> 32); + return lower ^ upper; } SerializerMode HashSerializer::GetSerializerMode() const diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h index 2f86d1aafe..1cc44cf5bd 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/HashSerializer.h @@ -56,6 +56,6 @@ namespace AzNetworking private: - AZ::HashValue64 m_hash; + AZ::HashValue64 m_hash = AZ::HashValue64{ 0 }; }; } diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.cpp index 6cea9324c4..1a7512a4fc 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.cpp @@ -159,6 +159,8 @@ namespace AzQtComponents // Timer for updating our hovered drop zone opacity QObject::connect(m_dropZoneHoverFadeInTimer, &QTimer::timeout, this, &FancyDocking::onDropZoneHoverFadeInUpdate); m_dropZoneHoverFadeInTimer->setInterval(g_FancyDockingConstants.dropZoneHoverFadeUpdateIntervalMS); + QIcon dragIcon = QIcon(QStringLiteral(":/Cursors/Grabbing.svg")); + m_dragCursor = QCursor(dragIcon.pixmap(16), 5, 2); } FancyDocking::~FancyDocking() @@ -1884,6 +1886,8 @@ namespace AzQtComponents return; } + QApplication::setOverrideCursor(m_dragCursor); + QPoint relativePressPos = pressPos; // If we are dragging a floating window, we need to grab a reference to its @@ -3565,6 +3569,11 @@ namespace AzQtComponents */ void FancyDocking::clearDraggingState() { + if (QApplication::overrideCursor()) + { + QApplication::restoreOverrideCursor(); + } + m_ghostWidget->hide(); // Release the mouse and keyboard from our main window since we grab them when we start dragging diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.h index a466ce7087..20b90ad25c 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.h @@ -266,6 +266,8 @@ namespace AzQtComponents QString m_floatingWindowIdentifierPrefix; QString m_tabContainerIdentifierPrefix; + + QCursor m_dragCursor; }; } // namespace AzQtComponents diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TabWidget.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TabWidget.cpp index 895785f47b..48fb47d7e6 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TabWidget.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TabWidget.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -419,6 +420,14 @@ namespace AzQtComponents // a mouse move. The paint handler updates the close button's visibility setAttribute(Qt::WA_Hover); AzQtComponents::Style::addClass(this, g_emptyStyleClass); + + QIcon icon = QIcon(QStringLiteral(":/Cursors/Grab_release.svg")); + m_hoverCursor = QCursor(icon.pixmap(16), 5, 2); + + icon = QIcon(QStringLiteral(":/Cursors/Grabbing.svg")); + m_dragCursor = QCursor(icon.pixmap(16), 5, 2); + + this->setCursor(m_hoverCursor); } void TabBar::setHandleOverflow(bool handleOverflow) @@ -455,6 +464,11 @@ namespace AzQtComponents { if (mouseEvent->buttons() & Qt::LeftButton) { + if (!QApplication::overrideCursor() || *QApplication::overrideCursor() != m_dragCursor) + { + QApplication::setOverrideCursor(m_dragCursor); + } + m_lastMousePress = mouseEvent->pos(); } @@ -469,6 +483,7 @@ namespace AzQtComponents // selected tab is moved around. The close button is not explicitly rendered for the // moved tab during this operation. We need to make sure not to set it visible again // while the tab is moving. This flag makes sure it happens. + m_movingTab = true; } @@ -479,6 +494,13 @@ namespace AzQtComponents void TabBar::mouseReleaseEvent(QMouseEvent* mouseEvent) { + // Ensure we don't reset the cursor in the case of a dummy event being sent from DockTabWidget to trigger the animation. + Qt::MouseButtons realButtons = QApplication::mouseButtons(); + if (QApplication::overrideCursor() && !(realButtons & Qt::LeftButton)) + { + QApplication::restoreOverrideCursor(); + } + if (m_movingTab && !(mouseEvent->buttons() & Qt::LeftButton)) { // When a moving tab is released, there is a short animation to put the moving tab @@ -632,13 +654,7 @@ namespace AzQtComponents { QPoint p = tabRect(i).topLeft(); - int rightPadding = g_closeButtonPadding; - if (m_overflowing == Overflowing) - { - rightPadding = 0; - } - - p.setX(p.x() + tabRect(i).width() - rightPadding - g_closeButtonWidth); + p.setX(p.x() + tabRect(i).width() - g_closeButtonPadding - g_closeButtonWidth); p.setY(p.y() + 1 + (tabRect(i).height() - g_closeButtonWidth) / 2); tabBtn->move(p); } diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TabWidget.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TabWidget.h index 3f12f79907..e86deef7b4 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TabWidget.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TabWidget.h @@ -203,6 +203,9 @@ namespace AzQtComponents bool m_movingTab = false; QPoint m_lastMousePress; + QCursor m_dragCursor; + QCursor m_hoverCursor; + void resetOverflow(); void overflowIfNeeded(); void showCloseButtonAt(int index); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/Cursors/Grab_release.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/Cursors/Grab_release.svg new file mode 100644 index 0000000000..ad89e7d1b1 --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/Cursors/Grab_release.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/Cursors/Grabbing.svg b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/Cursors/Grabbing.svg new file mode 100644 index 0000000000..96de4e997b --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/img/UI20/Cursors/Grabbing.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc index b995874a41..8ea4755a24 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/resources.qrc @@ -637,5 +637,7 @@ img/UI20/Cursors/Pointer.svg + img/UI20/Cursors/Grab_release.svg + img/UI20/Cursors/Grabbing.svg diff --git a/Code/Framework/AzTest/AzTest/AzTest.h b/Code/Framework/AzTest/AzTest/AzTest.h index a3d43bd521..c82598cb0c 100644 --- a/Code/Framework/AzTest/AzTest/AzTest.h +++ b/Code/Framework/AzTest/AzTest/AzTest.h @@ -17,7 +17,7 @@ #include AZ_PUSH_DISABLE_WARNING(4389 4800, "-Wunknown-warning-option"); // 'int' : forcing value to bool 'true' or 'false' (performance warning). -#undef strdup // platform.h in CryCommon changes this define which is required by googletest +#undef strdup // This define is required by googletest #include #include AZ_POP_DISABLE_WARNING; @@ -477,8 +477,7 @@ int main(int argc, char** argv) } \ } while (0); // safe multi-line macro - creates a single statement -// Avoid accidentally being managed by CryMemory, or problems with new/delete when -// AZ allocators are not ready or properly un/initialized. +// Avoid problems with new/delete when AZ allocators are not ready or properly un/initialized. #define AZ_TEST_CLASS_ALLOCATOR(Class_) \ void* operator new (size_t size) \ { \ diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h index 9de9f0dee3..576c543dce 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/LinearManipulator.h @@ -42,6 +42,7 @@ namespace AzToolsFramework ~LinearManipulator() = default; /// A Manipulator must only be created and managed through a shared_ptr. + /// @note worldFromLocal should not contain scale. static AZStd::shared_ptr MakeShared(const AZ::Transform& worldFromLocal); /// Unchanging data set once for the linear manipulator. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp index 0bffd26be0..145a293ab8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.cpp @@ -199,6 +199,43 @@ namespace AzToolsFramework return true; } + void GetTemplateSourcePaths(const PrefabDomValue& prefabDom, AZStd::unordered_set& templateSourcePaths) + { + PrefabDomValueConstReference findSourceResult = PrefabDomUtils::FindPrefabDomValue(prefabDom, PrefabDomUtils::SourceName); + if (!findSourceResult.has_value() || !(findSourceResult->get().IsString()) || + findSourceResult->get().GetStringLength() == 0) + { + AZ_Assert( + false, + "PrefabDomUtils::GetDependentTemplatePath - Source value of prefab in the provided DOM is not a valid string."); + return; + } + + templateSourcePaths.emplace(findSourceResult->get().GetString()); + PrefabDomValueConstReference instancesReference = GetInstancesValue(prefabDom); + if (instancesReference.has_value()) + { + const PrefabDomValue& instances = instancesReference->get(); + + for (PrefabDomValue::ConstMemberIterator instanceIterator = instances.MemberBegin(); + instanceIterator != instances.MemberEnd(); ++instanceIterator) + { + GetTemplateSourcePaths(instanceIterator->value, templateSourcePaths); + } + } + } + + PrefabDomValueConstReference GetInstancesValue(const PrefabDomValue& prefabDom) + { + PrefabDomValueConstReference findInstancesResult = FindPrefabDomValue(prefabDom, PrefabDomUtils::InstancesName); + if (!findInstancesResult.has_value() || !(findInstancesResult->get().IsObject())) + { + return AZStd::nullopt; + } + + return findInstancesResult->get(); + } + void PrintPrefabDomValue( [[maybe_unused]] const AZStd::string_view printMessage, [[maybe_unused]] const PrefabDomValue& prefabDomValue) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.h index c7c2827770..5ee91c85ae 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabDomUtils.h @@ -100,6 +100,20 @@ namespace AzToolsFramework .Append(instanceName); }; + /** + * Gets a set of all the template source paths in the given dom. + * @param prefabDom The DOM to get the template source paths from. + * @param[out] templateSourcePaths The set of template source paths to populate. + */ + void GetTemplateSourcePaths(const PrefabDomValue& prefabDom, AZStd::unordered_set& templateSourcePaths); + + /** + * Gets the instances DOM value from the given prefab DOM. + * + * @return the instances DOM value or AZStd::nullopt if it instances can't be found. + */ + PrefabDomValueConstReference GetInstancesValue(const PrefabDomValue& prefabDom); + /** * Prints the contents of the given prefab DOM value to the debug output console in a readable format. * @param printMessage The message that will be printed before printing the PrefabDomValue diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 9649818ed9..200a5c96fb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -210,25 +210,30 @@ namespace AzToolsFramework auto relativePath = m_prefabLoaderInterface->GetRelativePathToProject(filePath); Prefab::TemplateId templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(relativePath); - // If the template isn't currently loaded, there's no way for it to be in the hierarchy so we just skip the check. - if (templateId != Prefab::InvalidTemplateId && IsPrefabInInstanceAncestorHierarchy(templateId, instanceToParentUnder->get())) + if (templateId == InvalidTemplateId) { - return AZ::Failure( - AZStd::string::format( - "Instantiate Prefab operation aborted - Cyclical dependency detected\n(%s depends on %s).", - relativePath.Native().c_str(), - instanceToParentUnder->get().GetTemplateSourcePath().Native().c_str() - ) - ); + // Load the template from the file + templateId = m_prefabLoaderInterface->LoadTemplateFromFile(filePath); + AZ_Assert(templateId != InvalidTemplateId, "Template with source path %s couldn't be loaded correctly.", filePath); } - + + const PrefabDom& templateDom = m_prefabSystemComponentInterface->FindTemplateDom(templateId); + AZStd::unordered_set templatePaths; + PrefabDomUtils::GetTemplateSourcePaths(templateDom, templatePaths); + + if (IsCyclicalDependencyFound(instanceToParentUnder->get(), templatePaths)) + { + return AZ::Failure(AZStd::string::format( + "Instantiate Prefab operation aborted - Cyclical dependency detected\n(%s depends on %s).", + relativePath.Native().c_str(), instanceToParentUnder->get().GetTemplateSourcePath().Native().c_str())); + } + { // Initialize Undo Batch object ScopedUndoBatch undoBatch("Instantiate Prefab"); PrefabDom instanceToParentUnderDomBeforeCreate; - m_instanceToTemplateInterface->GenerateDomForInstance( - instanceToParentUnderDomBeforeCreate, instanceToParentUnder->get()); + m_instanceToTemplateInterface->GenerateDomForInstance(instanceToParentUnderDomBeforeCreate, instanceToParentUnder->get()); // Instantiate the Prefab auto instanceToCreate = prefabEditorEntityOwnershipInterface->InstantiatePrefab(relativePath, instanceToParentUnder); @@ -242,8 +247,7 @@ namespace AzToolsFramework PrefabUndoHelpers::UpdatePrefabInstance( instanceToParentUnder->get(), "Update prefab instance", instanceToParentUnderDomBeforeCreate, undoBatch.GetUndoBatch()); - CreateLink({}, instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(), - undoBatch.GetUndoBatch(), parent); + CreateLink({}, instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(), undoBatch.GetUndoBatch(), parent); AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId(); // Apply position @@ -296,17 +300,17 @@ namespace AzToolsFramework return AZ::Success(); } - bool PrefabPublicHandler::IsPrefabInInstanceAncestorHierarchy(TemplateId prefabTemplateId, InstanceOptionalConstReference instance) + bool PrefabPublicHandler::IsCyclicalDependencyFound( + InstanceOptionalConstReference instance, const AZStd::unordered_set& templateSourcePaths) { InstanceOptionalConstReference currentInstance = instance; while (currentInstance.has_value()) { - if (currentInstance->get().GetTemplateId() == prefabTemplateId) + if (templateSourcePaths.contains(currentInstance->get().GetTemplateSourcePath())) { return true; } - currentInstance = currentInstance->get().GetParentInstance(); } @@ -636,11 +640,18 @@ namespace AzToolsFramework if (!EntitiesBelongToSameInstance(entityIds)) { - return AZ::Failure(AZStd::string("DeleteEntitiesAndAllDescendantsInInstance - Deletion Error. Cannot delete multiple " - "entities belonging to different instances with one operation.")); + return AZ::Failure(AZStd::string("Cannot delete multiple entities belonging to different instances with one operation.")); } - InstanceOptionalReference instance = GetOwnerInstanceByEntityId(entityIds[0]); + AZ::EntityId firstEntityIdToDelete = entityIds[0]; + InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDelete); + + // If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you + // cannot delete an instance from itself. + if (commonOwningInstance->get().GetContainerEntityId() == firstEntityIdToDelete) + { + commonOwningInstance = commonOwningInstance->get().GetParentInstance(); + } // Retrieve entityList from entityIds EntityList inputEntityList = EntityIdListToEntityList(entityIds); @@ -680,14 +691,14 @@ namespace AzToolsFramework AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "Internal::DeleteEntities:UndoCaptureAndPurgeEntities"); Prefab::PrefabDom instanceDomBefore; - m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, instance->get()); + m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, commonOwningInstance->get()); if (deleteDescendants) { AZStd::vector entities; AZStd::vector> instances; - bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, instance->get(), entities, instances); + bool success = RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonOwningInstance->get(), entities, instances); if (!success) { @@ -701,6 +712,7 @@ namespace AzToolsFramework for (auto& nestedInstance : instances) { + RemoveLink(nestedInstance, commonOwningInstance->get().GetTemplateId(), currentUndoBatch); nestedInstance.reset(); } } @@ -712,22 +724,22 @@ namespace AzToolsFramework // If this is the container entity, it actually represents the instance so get its owner if (owningInstance->get().GetContainerEntityId() == entityId) { - auto instancePtr = instance->get().DetachNestedInstance(owningInstance->get().GetInstanceAlias()); - instancePtr.reset(); + auto instancePtr = commonOwningInstance->get().DetachNestedInstance(owningInstance->get().GetInstanceAlias()); + RemoveLink(instancePtr, commonOwningInstance->get().GetTemplateId(), currentUndoBatch); } else { - instance->get().DetachEntity(entityId); + commonOwningInstance->get().DetachEntity(entityId); AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, entityId); } } } Prefab::PrefabDom instanceDomAfter; - m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfter, instance->get()); + m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfter, commonOwningInstance->get()); PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance deletion"); - command->Capture(instanceDomBefore, instanceDomAfter, instance->get().GetTemplateId()); + command->Capture(instanceDomBefore, instanceDomAfter, commonOwningInstance->get().GetTemplateId()); command->SetParent(selCommand); } @@ -995,5 +1007,5 @@ namespace AzToolsFramework return true; } - } -} + } // namespace Prefab +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index 138bc84aa0..d88086dda9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -12,8 +12,8 @@ #pragma once -#include #include +#include #include #include @@ -107,13 +107,15 @@ namespace AzToolsFramework const AZStd::vector& entityIds, EntityList& inputEntityList, EntityList& topLevelEntities, AZ::EntityId& commonRootEntityId, InstanceOptionalReference& commonRootEntityOwningInstance); - /* Detects whether an instance of prefabTemplateId is present in the hierarchy of ancestors of instance. + /* Checks whether the template source path of any of the ancestors in the instance hierarchy matches with one of the + * paths provided in a set. * - * \param prefabTemplateId The template id to test for - * \param instance The instance whose ancestor hierarchy prefabTemplateId will be tested against. - * \return true if an instance of the template of id prefabTemplateId could be found in the ancestor hierarchy of instance, false otherwise. + * \param instance The instance whose ancestor hierarchy the provided set of template source paths will be tested against. + * \param templateSourcePaths The template source paths provided to be checked against the instance ancestor hierarchy. + * \return true if any of the template source paths could be found in the ancestor hierarchy of instance, false otherwise. */ - bool IsPrefabInInstanceAncestorHierarchy(TemplateId prefabTemplateId, InstanceOptionalConstReference instance); + bool IsCyclicalDependencyFound( + InstanceOptionalConstReference instance, const AZStd::unordered_set& templateSourcePaths); static Instance* GetParentInstance(Instance* instance); static Instance* GetAncestorOfInstanceThatIsChildOfRoot(const Instance* ancestor, Instance* descendant); @@ -129,5 +131,5 @@ namespace AzToolsFramework uint64_t m_newEntityCounter = 1; }; - } -} + } // namespace Prefab +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp index a61f042049..f72de82f36 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.cpp @@ -1,20 +1,20 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ -#include +#include +#include #include #include -#include -#include +#include namespace AzToolsFramework { @@ -32,12 +32,13 @@ namespace AzToolsFramework serializeContext->Class() ->Version(1) ->Field("NonUniformScale", &EditorNonUniformScaleComponent::m_scale) - ; + ->Field("ComponentMode", &EditorNonUniformScaleComponent::m_componentModeDelegate); if (AZ::EditContext* editContext = serializeContext->GetEditContext()) { - editContext->Class("Non-uniform Scale", - "Non-uniform scale for this entity only (does not propagate through hierarchy)") + editContext + ->Class( + "Non-uniform Scale", "Non-uniform scale for this entity only (does not propagate through hierarchy)") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::FixedComponentListIndex, 1) ->Attribute(AZ::Edit::Attributes::RemoveableByUser, true) @@ -50,7 +51,10 @@ namespace AzToolsFramework ->Attribute(AZ::Edit::Attributes::Max, AZ::MaxTransformScale) ->Attribute(AZ::Edit::Attributes::Step, 0.1f) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorNonUniformScaleComponent::OnScaleChanged) - ; + ->DataElement( + AZ::Edit::UIHandlers::Default, &EditorNonUniformScaleComponent::m_componentModeDelegate, "Component Mode", + "Non-uniform Scale Component Mode") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly); } } } @@ -74,10 +78,16 @@ namespace AzToolsFramework void EditorNonUniformScaleComponent::Activate() { AZ::NonUniformScaleRequestBus::Handler::BusConnect(GetEntityId()); + + // ComponentMode + m_componentModeDelegate.ConnectWithSingleComponentMode( + AZ::EntityComponentIdPair(GetEntityId(), GetId()), nullptr); } void EditorNonUniformScaleComponent::Deactivate() { + m_componentModeDelegate.Disconnect(); + AZ::NonUniformScaleRequestBus::Handler::BusDisconnect(); } @@ -96,7 +106,8 @@ namespace AzToolsFramework else { AZ::Vector3 clampedScale = scale.GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale)); - AZ_Warning("Editor Non-uniform Scale Component", false, "SetScale value was clamped from %s to %s for entity %s", + AZ_Warning( + "Editor Non-uniform Scale Component", false, "SetScale value was clamped from %s to %s for entity %s", AZ::ToString(scale).c_str(), AZ::ToString(clampedScale).c_str(), GetEntity()->GetName().c_str()); m_scale = clampedScale; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h index ea67ab3962..eb51fe3d80 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h @@ -13,6 +13,9 @@ #pragma once #include +#include +#include +#include #include namespace AzToolsFramework @@ -52,6 +55,9 @@ namespace AzToolsFramework AZ::Vector3 m_scale = AZ::Vector3::CreateOne(); AZ::NonUniformScaleChangedEvent m_scaleChangedEvent; + + //! Responsible for detecting ComponentMode activation and creating a concrete ComponentMode. + AzToolsFramework::ComponentModeFramework::ComponentModeDelegate m_componentModeDelegate; }; } // namespace Components } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp new file mode 100644 index 0000000000..97e27ac748 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.cpp @@ -0,0 +1,92 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include +#include +#include + +namespace AzToolsFramework +{ + namespace Components + { + NonUniformScaleComponentMode::NonUniformScaleComponentMode( + const AZ::EntityComponentIdPair& entityComponentIdPair, AZ::Uuid componentType) + : EditorBaseComponentMode(entityComponentIdPair, componentType) + { + m_entityComponentIdPair = entityComponentIdPair; + + AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(worldFromLocal, m_entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM); + worldFromLocal.ExtractScale(); + m_manipulators = AZStd::make_unique(worldFromLocal); + m_manipulators->Register(g_mainManipulatorManagerId); + m_manipulators->SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + const float axisLength = 2.0f; + m_manipulators->ConfigureView( + axisLength, AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor, + AzFramework::ViewportColors::ZAxisColor); + + auto mouseDownCallback = [this](const LinearManipulator::Action& action) { + AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne(); + + AZ::NonUniformScaleRequestBus::EventResult( + nonUniformScale, m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale); + + m_initialScale = nonUniformScale + action.m_start.m_scaleSnapOffset; + + AZ::NonUniformScaleRequestBus::Event( + m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, m_initialScale); + }; + + m_manipulators->InstallAxisLeftMouseDownCallback(mouseDownCallback); + + m_manipulators->InstallAxisMouseMoveCallback([this](const LinearManipulator::Action& action) { + const AZ::Vector3 scaleMultiplier = + (AZ::Vector3::CreateOne() + ((action.LocalScaleOffset() * action.m_start.m_sign) / m_initialScale)); + + AZ::NonUniformScaleRequestBus::Event( + m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, + (scaleMultiplier * m_initialScale).GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale))); + }); + + m_manipulators->InstallUniformLeftMouseDownCallback(mouseDownCallback); + + m_manipulators->InstallUniformMouseMoveCallback([this](const LinearManipulator::Action& action) { + const auto sumVectorElements = [](const AZ::Vector3& vec) { return vec.GetX() + vec.GetY() + vec.GetZ(); }; + + const float minScaleMultiplier = AZ::MinTransformScale / m_initialScale.GetMinElement(); + const float maxScaleMultiplier = AZ::MaxTransformScale / m_initialScale.GetMaxElement(); + const float scaleMultiplier = AZ::GetClamp( + 1.0f + sumVectorElements(action.m_start.m_sign * action.LocalScaleOffset() / m_initialScale), minScaleMultiplier, + maxScaleMultiplier); + + AZ::NonUniformScaleRequestBus::Event( + m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, scaleMultiplier * m_initialScale); + }); + } + + NonUniformScaleComponentMode::~NonUniformScaleComponentMode() + { + if (m_manipulators) + { + m_manipulators->Unregister(); + } + m_manipulators.reset(); + } + + void NonUniformScaleComponentMode::Refresh() + { + } + } // namespace Components +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.h new file mode 100644 index 0000000000..1169a4f13e --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponentMode.h @@ -0,0 +1,43 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once + +#include +#include + +namespace AzToolsFramework +{ + namespace Components + { + class NonUniformScaleComponentMode : public AzToolsFramework::ComponentModeFramework::EditorBaseComponentMode + { + public: + AZ_CLASS_ALLOCATOR(NonUniformScaleComponentMode, AZ::SystemAllocator, 0) + + NonUniformScaleComponentMode(const AZ::EntityComponentIdPair& entityComponentIdPair, AZ::Uuid componentType); + NonUniformScaleComponentMode(const NonUniformScaleComponentMode&) = delete; + NonUniformScaleComponentMode& operator=(const NonUniformScaleComponentMode&) = delete; + NonUniformScaleComponentMode(NonUniformScaleComponentMode&&) = delete; + NonUniformScaleComponentMode& operator=(NonUniformScaleComponentMode&&) = delete; + ~NonUniformScaleComponentMode(); + + // EditorBaseComponentMode overrides ... + void Refresh() override; + + private: + AZ::EntityComponentIdPair m_entityComponentIdPair; + AZStd::unique_ptr m_manipulators; + AZ::Vector3 m_initialScale; + }; + } // namespace Components +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp index 70cad69268..8192e86956 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp @@ -254,7 +254,7 @@ namespace AzToolsFramework m_localTransformDirty = true; m_worldTransformDirty = true; - if (GetEntity()) + if (const AZ::Entity* entity = GetEntity()) { SetDirty(); @@ -273,6 +273,22 @@ namespace AzToolsFramework { boundsUnion->OnTransformUpdated(GetEntity()); } + // Fire a property changed notification for this component + if (const AZ::Component* component = entity->FindComponent()) + { + PropertyEditorEntityChangeNotificationBus::Event( + GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, component->GetId()); + } + + // Refresh the property editor if we're selected + bool selected = false; + ToolsApplicationRequestBus::BroadcastResult( + selected, &AzToolsFramework::ToolsApplicationRequests::IsSelected, GetEntityId()); + if (selected) + { + ToolsApplicationEvents::Bus::Broadcast( + &ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values); + } } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 7f28080e9e..bc7afbf085 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -403,9 +403,12 @@ namespace AzToolsFramework AzToolsFramework::EntityIdList selectedEntityIds; AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult( selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); - - AzToolsFramework::ToolsApplicationRequestBus::Broadcast( - &AzToolsFramework::ToolsApplicationRequests::DeleteEntitiesAndAllDescendants, selectedEntityIds); + PrefabOperationResult deleteSelectedResult = + s_prefabPublicInterface->DeleteEntitiesAndAllDescendantsInInstance(selectedEntityIds); + if (!deleteSelectedResult.IsSuccess()) + { + WarnUserOfError("Delete selected entities error", deleteSelectedResult.GetError()); + } } void PrefabIntegrationManager::GenerateSuggestedFilenameFromEntities(const EntityIdList& entityIds, AZStd::string& outName) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 06f78ecdd3..45f52704bf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -303,6 +303,8 @@ set(FILES ToolsComponents/AzToolsFrameworkConfigurationSystemComponent.cpp ToolsComponents/EditorNonUniformScaleComponent.h ToolsComponents/EditorNonUniformScaleComponent.cpp + ToolsComponents/EditorNonUniformScaleComponentMode.h + ToolsComponents/EditorNonUniformScaleComponentMode.cpp ToolsMessaging/EntityHighlightBus.h UI/Docking/DockWidgetUtils.cpp UI/Docking/DockWidgetUtils.h diff --git a/Code/Framework/Tests/ClickDetectorTests.cpp b/Code/Framework/Tests/ClickDetectorTests.cpp index 62f8069073..7e6f9634c8 100644 --- a/Code/Framework/Tests/ClickDetectorTests.cpp +++ b/Code/Framework/Tests/ClickDetectorTests.cpp @@ -1,142 +1,142 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#include -#include -#include - -namespace AzFramework -{ - std::ostream& operator<<(std::ostream& os, const ClickDetector::ClickOutcome clickOutcome) - { - switch (clickOutcome) - { - case ClickDetector::ClickOutcome::Click: - os << "ClickOutcome::Click"; - break; - case ClickDetector::ClickOutcome::Move: - os << "ClickOutcome::Move"; - break; - case ClickDetector::ClickOutcome::Release: - os << "ClickOutcome::Release"; - break; - case ClickDetector::ClickOutcome::Nil: - os << "ClickOutcome::Nil"; - break; - } - - return os; - } -} // namespace AzFramework - -namespace UnitTest -{ - using AzFramework::ClickDetector; - using AzFramework::ScreenVector; - - class ClickDetectorFixture : public ::testing::Test - { - public: - ClickDetector m_clickDetector; - }; - - TEST_F(ClickDetectorFixture, ClickIsDetectedWithNoMouseMovementOnMouseUp) - { - using ::testing::Eq; - - const ClickDetector::ClickOutcome initialDownOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); - const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); - - EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); - EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click)); - } - - TEST_F(ClickDetectorFixture, MoveIsDetectedWithMouseMovementAfterMouseDown) - { - using ::testing::Eq; - - const ClickDetector::ClickOutcome initialDownOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); - const ClickDetector::ClickOutcome initialMoveOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10)); - - EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); - EXPECT_THAT(initialMoveOutcome, Eq(ClickDetector::ClickOutcome::Move)); - } - - TEST_F(ClickDetectorFixture, ReleaseIsDetectedAfterMouseMovementOnMouseUp) - { - using ::testing::Eq; - - const ClickDetector::ClickOutcome initialDownOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); - // move - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10)); - const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); - - EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); - EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Release)); - } - - TEST_F(ClickDetectorFixture, MoveIsReturnedOnlyAfterFirstMouseMove) - { - using ::testing::Eq; - - const ClickDetector::ClickOutcome initialDownOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); - const ClickDetector::ClickOutcome initialMoveOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10)); - const ClickDetector::ClickOutcome secondaryMoveOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10)); - - EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); - EXPECT_THAT(initialMoveOutcome, Eq(ClickDetector::ClickOutcome::Move)); - EXPECT_THAT(secondaryMoveOutcome, Eq(ClickDetector::ClickOutcome::Nil)); - } - - TEST_F(ClickDetectorFixture, ClickIsNotRegisteredAfterDoubleClick) - { - using ::testing::Eq; - - const ClickDetector::ClickOutcome initialDownOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); - const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); - const ClickDetector::ClickOutcome secondaryDownOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); - const ClickDetector::ClickOutcome secondaryUpOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); - - EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); - EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click)); - EXPECT_THAT(secondaryDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // double click - EXPECT_THAT(secondaryUpOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // click not registered - } - - TEST_F(ClickDetectorFixture, ClickIsNotRegisteredAfterIgnoredDoubleClick) - { - using ::testing::Eq; - - const ClickDetector::ClickOutcome initialDownOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); - const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); - const ClickDetector::ClickOutcome secondaryDownOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(0, 0)); - const ClickDetector::ClickOutcome secondaryUpOutcome = - m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); - - EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); - EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click)); - EXPECT_THAT(secondaryDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // ignored double click - EXPECT_THAT(secondaryUpOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // click not registered - } -} // namespace UnitTest +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include + +namespace AzFramework +{ + std::ostream& operator<<(std::ostream& os, const ClickDetector::ClickOutcome clickOutcome) + { + switch (clickOutcome) + { + case ClickDetector::ClickOutcome::Click: + os << "ClickOutcome::Click"; + break; + case ClickDetector::ClickOutcome::Move: + os << "ClickOutcome::Move"; + break; + case ClickDetector::ClickOutcome::Release: + os << "ClickOutcome::Release"; + break; + case ClickDetector::ClickOutcome::Nil: + os << "ClickOutcome::Nil"; + break; + } + + return os; + } +} // namespace AzFramework + +namespace UnitTest +{ + using AzFramework::ClickDetector; + using AzFramework::ScreenVector; + + class ClickDetectorFixture : public ::testing::Test + { + public: + ClickDetector m_clickDetector; + }; + + TEST_F(ClickDetectorFixture, ClickIsDetectedWithNoMouseMovementOnMouseUp) + { + using ::testing::Eq; + + const ClickDetector::ClickOutcome initialDownOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); + const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); + + EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); + EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click)); + } + + TEST_F(ClickDetectorFixture, MoveIsDetectedWithMouseMovementAfterMouseDown) + { + using ::testing::Eq; + + const ClickDetector::ClickOutcome initialDownOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); + const ClickDetector::ClickOutcome initialMoveOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10)); + + EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); + EXPECT_THAT(initialMoveOutcome, Eq(ClickDetector::ClickOutcome::Move)); + } + + TEST_F(ClickDetectorFixture, ReleaseIsDetectedAfterMouseMovementOnMouseUp) + { + using ::testing::Eq; + + const ClickDetector::ClickOutcome initialDownOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); + // move + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10)); + const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); + + EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); + EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Release)); + } + + TEST_F(ClickDetectorFixture, MoveIsReturnedOnlyAfterFirstMouseMove) + { + using ::testing::Eq; + + const ClickDetector::ClickOutcome initialDownOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); + const ClickDetector::ClickOutcome initialMoveOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10)); + const ClickDetector::ClickOutcome secondaryMoveOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10)); + + EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); + EXPECT_THAT(initialMoveOutcome, Eq(ClickDetector::ClickOutcome::Move)); + EXPECT_THAT(secondaryMoveOutcome, Eq(ClickDetector::ClickOutcome::Nil)); + } + + TEST_F(ClickDetectorFixture, ClickIsNotRegisteredAfterDoubleClick) + { + using ::testing::Eq; + + const ClickDetector::ClickOutcome initialDownOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); + const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); + const ClickDetector::ClickOutcome secondaryDownOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); + const ClickDetector::ClickOutcome secondaryUpOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); + + EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); + EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click)); + EXPECT_THAT(secondaryDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // double click + EXPECT_THAT(secondaryUpOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // click not registered + } + + TEST_F(ClickDetectorFixture, ClickIsNotRegisteredAfterIgnoredDoubleClick) + { + using ::testing::Eq; + + const ClickDetector::ClickOutcome initialDownOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0)); + const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); + const ClickDetector::ClickOutcome secondaryDownOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(0, 0)); + const ClickDetector::ClickOutcome secondaryUpOutcome = + m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0)); + + EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); + EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click)); + EXPECT_THAT(secondaryDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // ignored double click + EXPECT_THAT(secondaryUpOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // click not registered + } +} // namespace UnitTest diff --git a/Code/Framework/Tests/CursorStateTests.cpp b/Code/Framework/Tests/CursorStateTests.cpp index 865db2391d..e04d04537b 100644 --- a/Code/Framework/Tests/CursorStateTests.cpp +++ b/Code/Framework/Tests/CursorStateTests.cpp @@ -1,54 +1,54 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#include -#include - -namespace UnitTest -{ - using AzFramework::CursorState; - using AzFramework::ScreenVector; - using AzFramework::ScreenPoint; - - class CursorStateFixture : public ::testing::Test - { - public: - CursorState m_cursorState; - }; - - TEST_F(CursorStateFixture, CursorStateHasZeroDeltaInitially) - { - using ::testing::Eq; - EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(0, 0))); - } - - TEST_F(CursorStateFixture, CursorStateReturnsZeroDeltaAfterSingleMoveAndUpdate) - { - using ::testing::Eq; - - m_cursorState.SetCurrentPosition(ScreenPoint(10, 10)); - m_cursorState.Update(); - - EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(0, 0))); - } - - TEST_F(CursorStateFixture, CursorStateReturnsDeltaAfterSecondMoveAndUpdate) - { - using ::testing::Eq; - - m_cursorState.SetCurrentPosition(ScreenPoint(10, 10)); - m_cursorState.Update(); - m_cursorState.SetCurrentPosition(ScreenPoint(15, 22)); - - EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(5, 12))); - } -} // namespace UnitTest +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include + +namespace UnitTest +{ + using AzFramework::CursorState; + using AzFramework::ScreenVector; + using AzFramework::ScreenPoint; + + class CursorStateFixture : public ::testing::Test + { + public: + CursorState m_cursorState; + }; + + TEST_F(CursorStateFixture, CursorStateHasZeroDeltaInitially) + { + using ::testing::Eq; + EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(0, 0))); + } + + TEST_F(CursorStateFixture, CursorStateReturnsZeroDeltaAfterSingleMoveAndUpdate) + { + using ::testing::Eq; + + m_cursorState.SetCurrentPosition(ScreenPoint(10, 10)); + m_cursorState.Update(); + + EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(0, 0))); + } + + TEST_F(CursorStateFixture, CursorStateReturnsDeltaAfterSecondMoveAndUpdate) + { + using ::testing::Eq; + + m_cursorState.SetCurrentPosition(ScreenPoint(10, 10)); + m_cursorState.Update(); + m_cursorState.SetCurrentPosition(ScreenPoint(15, 22)); + + EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(5, 12))); + } +} // namespace UnitTest diff --git a/Code/LauncherUnified/Platform/Windows/Launcher_Windows.cpp b/Code/LauncherUnified/Platform/Windows/Launcher_Windows.cpp index b7f04a7e10..8f8d310475 100644 --- a/Code/LauncherUnified/Platform/Windows/Launcher_Windows.cpp +++ b/Code/LauncherUnified/Platform/Windows/Launcher_Windows.cpp @@ -50,7 +50,6 @@ int APIENTRY WinMain([[maybe_unused]] HINSTANCE hInstance, [[maybe_unused]] HINS { // HACK HACK HACK - is this still needed?!?! // CrySystem module can get loaded multiple times (even from within CrySystem itself) - // and currently there is no way to track them (\ref _CryMemoryManagerPoolHelper::Init() in CryMemoryManager_impl.h) // so we will release it as many times as it takes until it actually unloads. void* hModule = CryLoadLibraryDefName("CrySystem"); if (hModule) diff --git a/Code/Sandbox/Editor/CMakeLists.txt b/Code/Sandbox/Editor/CMakeLists.txt index 7d89717391..c62e05f012 100644 --- a/Code/Sandbox/Editor/CMakeLists.txt +++ b/Code/Sandbox/Editor/CMakeLists.txt @@ -118,12 +118,12 @@ ly_add_target( Gem::LmbrCentral.Static Legacy::NewsShared AZ::AWSNativeSDKInit - Legacy::CryCommonTools AZ::AtomCore Gem::Atom_RPI.Edit Gem::Atom_RPI.Public Gem::Atom_Feature_Common.Static Gem::AtomToolsFramework.Static + Gem::AtomViewportDisplayInfo ${additional_dependencies} PUBLIC 3rdParty::AWSNativeSDK::Core @@ -244,7 +244,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzToolsFramework Legacy::EditorLib Gem::LmbrCentral - Legacy::CryCommonTools ) ly_add_googletest( NAME Legacy::EditorLib.Tests diff --git a/Code/Sandbox/Editor/GameEngine.cpp b/Code/Sandbox/Editor/GameEngine.cpp index 2112d00d64..c338a2e28d 100644 --- a/Code/Sandbox/Editor/GameEngine.cpp +++ b/Code/Sandbox/Editor/GameEngine.cpp @@ -424,7 +424,6 @@ AZ::Outcome CGameEngine::Init( sip.pLogCallback = &m_logFile; sip.sLogFileName = "@log@/Editor.log"; sip.pUserCallback = m_pSystemUserCallback; - sip.pValidator = GetIEditor()->GetErrorReport(); // Assign validator from Editor. if (sInCmdLine) { diff --git a/Code/Sandbox/Editor/GotoPositionDlg.cpp b/Code/Sandbox/Editor/GotoPositionDlg.cpp index dc0f024bcb..a09f594b7b 100644 --- a/Code/Sandbox/Editor/GotoPositionDlg.cpp +++ b/Code/Sandbox/Editor/GotoPositionDlg.cpp @@ -106,8 +106,7 @@ void CGotoPositionDlg::OnChangeEdit() { const int lengthInSw = 8; const int strNum = 6; - TArray< float > pos(strNum); - pos.Set(0); + AZStd::vector pos(strNum); m_sPos = m_ui->m_posEdit->text(); const QStringList parts = m_sPos.split(QRegularExpression("[\\s,;\\t]"), Qt::SkipEmptyParts); diff --git a/Code/Sandbox/Editor/GraphicsSettingsDialog.cpp b/Code/Sandbox/Editor/GraphicsSettingsDialog.cpp index 516e723d6b..593abeeddc 100644 --- a/Code/Sandbox/Editor/GraphicsSettingsDialog.cpp +++ b/Code/Sandbox/Editor/GraphicsSettingsDialog.cpp @@ -779,36 +779,6 @@ bool GraphicsSettingsDialog::CVarChanged(AZStd::any val, const char* cvarName, i m_cVarTracker[cvarName].fileVals[specLevel].editedValue = val; } - // If changing cvar from the platform cfg file currently running, set cvar - if (GetISystem()->GetConfigPlatform() == m_currentPlatform && GetISystem()->GetConfigSpec() == specLevel + 1) - { - if (ICVar* cvar = gEnv->pConsole->GetCVar(cvarName)) - { - int type = cvar->GetType(); - if (type == CVAR_INT) - { - int newValue; - if (AZStd::any_numeric_cast(&val, newValue)) - { - cvar->Set(newValue); - } - } - else if (type == CVAR_FLOAT) - { - float newValue; - if (AZStd::any_numeric_cast(&val, newValue)) - { - cvar->Set(newValue); - } - } - else - { - AZStd::string* currValue = AZStd::any_cast(&val); - cvar->Set(currValue->c_str()); - } - } - } - // Checking if the newly edited value is equal to the overwritten value cvarInfo = AZStd::make_pair(azcvarName, m_cVarTracker[cvarName]); if (CheckCVarStatesForDiff(&cvarInfo, specLevel, EDITED_OVERWRITTEN_COMPARE)) diff --git a/Code/Sandbox/Editor/IEditorImpl.cpp b/Code/Sandbox/Editor/IEditorImpl.cpp index 380fc80e66..0c8398050c 100644 --- a/Code/Sandbox/Editor/IEditorImpl.cpp +++ b/Code/Sandbox/Editor/IEditorImpl.cpp @@ -92,7 +92,6 @@ AZ_POP_DISABLE_WARNING #ifdef _RELEASE #undef _RELEASE #endif -#include #include "Core/QtEditorApplication.h" // for Editor::EditorQtApplication @@ -1585,16 +1584,9 @@ void CEditorImpl::AddUIEnums() m_pUIEnumsDatabase->SetEnumStrings("ShadowMinResPercent", types); } -void CEditorImpl::SetEditorConfigSpec(ESystemConfigSpec spec, ESystemConfigPlatform platform) +void CEditorImpl::SetEditorConfigSpec(ESystemConfigSpec spec, [[maybe_unused]]ESystemConfigPlatform platform) { gSettings.editorConfigSpec = spec; - if (m_pSystem->GetConfigSpec(true) != spec || m_pSystem->GetConfigPlatform() != platform) - { - m_pSystem->SetConfigSpec(spec, platform, true); - gSettings.editorConfigSpec = m_pSystem->GetConfigSpec(true); - GetObjectManager()->SendEvent(EVENT_CONFIG_SPEC_CHANGE); - AzToolsFramework::EditorEvents::Bus::Broadcast(&AzToolsFramework::EditorEvents::OnEditorSpecChange); - } } ESystemConfigSpec CEditorImpl::GetEditorConfigSpec() const diff --git a/Code/Sandbox/Editor/TrackView/TrackViewDopeSheetBase.cpp b/Code/Sandbox/Editor/TrackView/TrackViewDopeSheetBase.cpp index 407c124f5e..98123a016b 100644 --- a/Code/Sandbox/Editor/TrackView/TrackViewDopeSheetBase.cpp +++ b/Code/Sandbox/Editor/TrackView/TrackViewDopeSheetBase.cpp @@ -2734,9 +2734,6 @@ void CTrackViewDopeSheetBase::DrawKeys(CTrackViewTrack* pTrack, QPainter* painte const int kDefaultWidthForDescription = 200; const int kSmallMargin = 10; - FixedDynArray drawnKeyTimes; - drawnKeyTimes.set(ArrayT((float*)alloca(numKeys * sizeof(float)), numKeys)); - AZStd::vector sortedKeys; sortedKeys.reserve(numKeys); for (int i = 0; i < numKeys; ++i) @@ -2751,11 +2748,6 @@ void CTrackViewDopeSheetBase::DrawKeys(CTrackViewTrack* pTrack, QPainter* painte CTrackViewKeyHandle keyHandle = sortedKeys[i]; const float time = keyHandle.GetTime(); - if (!stl::push_back_unique(drawnKeyTimes, time)) - { - continue; - } - int x = TimeToClient(time); if (x - kSmallMargin > rect.right()) { diff --git a/Code/Sandbox/Editor/Util/ImageTIF.cpp b/Code/Sandbox/Editor/Util/ImageTIF.cpp index 0182d9654b..f69acc4161 100644 --- a/Code/Sandbox/Editor/Util/ImageTIF.cpp +++ b/Code/Sandbox/Editor/Util/ImageTIF.cpp @@ -440,7 +440,6 @@ bool CImageTIF::SaveRAW(const QString& fileName, const void* pData, int width, i { size_t offset = h * pitch; int err = TIFFWriteScanline(tif, raster + offset, h, 0); - assert(CryMemory::IsHeapValid()); if (err < 0) { bRet = false; diff --git a/Code/Sandbox/Editor/Util/IndexedFiles.h b/Code/Sandbox/Editor/Util/IndexedFiles.h index 641aff0333..0ae26b5adf 100644 --- a/Code/Sandbox/Editor/Util/IndexedFiles.h +++ b/Code/Sandbox/Editor/Util/IndexedFiles.h @@ -22,7 +22,6 @@ #include "FileUtil.h" -#include "STLPoolAllocator.h" #include class CIndexedFiles @@ -117,15 +116,8 @@ private: std::vector > m_updateCallbacks; IFileUtil::FileArray m_files; std::map m_pathToIndex; -#if defined(_DEBUG) || defined(AZ_COMPILER_CLANG) - // In debug, the validation phase of the pool allocator when destructed takes so much time, - // and using the STLPoolAllocator causes a strange issue when compiling with clang typedef std::set > int_set; typedef std::map > TagTable; -#else - typedef std::set, stl::STLPoolAllocator > int_set; - typedef std::map, stl::STLPoolAllocator > > TagTable; -#endif TagTable m_tags; QString m_rootPath; diff --git a/Code/Sandbox/Editor/Util/PathUtil.cpp b/Code/Sandbox/Editor/Util/PathUtil.cpp index 9f713eb0f3..6efc06c79e 100644 --- a/Code/Sandbox/Editor/Util/PathUtil.cpp +++ b/Code/Sandbox/Editor/Util/PathUtil.cpp @@ -272,21 +272,6 @@ namespace Path return str; } - //! Set the current mod NAME for editing purposes. After doing this the above functions will take this into account - //! name only, please! - void SetModName(const char* input) - { - if ( - (!input) || - ((gEnv) && (gEnv->pSystem) && (!gEnv->pSystem->IsMODValid(input))) // we can only validate - ) - { - AZ_Warning("PathUtil", false, "Invalid mod name supplied to SetModName: %s - ignored.", input ? input : "(NULL)"); - return; - } - g_currentModName = input; - } - //! Get the root folder (in source control or other writable assets) where you should save root data. AZStd::string GetEditingRootFolder() { diff --git a/Code/Tools/CryCommonTools/StringHelpers.cpp b/Code/Sandbox/Editor/Util/StringHelpers.cpp similarity index 100% rename from Code/Tools/CryCommonTools/StringHelpers.cpp rename to Code/Sandbox/Editor/Util/StringHelpers.cpp diff --git a/Code/Tools/CryCommonTools/StringHelpers.h b/Code/Sandbox/Editor/Util/StringHelpers.h similarity index 100% rename from Code/Tools/CryCommonTools/StringHelpers.h rename to Code/Sandbox/Editor/Util/StringHelpers.h diff --git a/Code/Tools/CryCommonTools/Util.h b/Code/Sandbox/Editor/Util/Util.h similarity index 100% rename from Code/Tools/CryCommonTools/Util.h rename to Code/Sandbox/Editor/Util/Util.h diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.cpp b/Code/Sandbox/Editor/ViewportTitleDlg.cpp index 95531e117c..5ccb83cd5b 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.cpp +++ b/Code/Sandbox/Editor/ViewportTitleDlg.cpp @@ -13,7 +13,7 @@ // Description : CViewportTitleDlg implementation file - +#if !defined(Q_MOC_RUN) #include "EditorDefs.h" #include "ViewportTitleDlg.h" @@ -36,10 +36,13 @@ #include "UsedResources.h" #include "Include/IObjectManager.h" +#include + AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING #include "ui_ViewportTitleDlg.h" AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING +#endif //!defined(Q_MOC_RUN) // CViewportTitleDlg dialog @@ -63,6 +66,32 @@ inline namespace Helpers } } +namespace +{ + class CViewportTitleDlgDisplayInfoHelper + : public QObject + , public AZ::AtomBridge::AtomViewportInfoDisplayNotificationBus::Handler + { + Q_OBJECT + + public: + CViewportTitleDlgDisplayInfoHelper(CViewportTitleDlg* parent) + : QObject(parent) + { + AZ::AtomBridge::AtomViewportInfoDisplayNotificationBus::Handler::BusConnect(); + } + + signals: + void ViewportInfoStatusUpdated(int newIndex); + + private: + void OnViewportInfoDisplayStateChanged(AZ::AtomBridge::ViewportInfoDisplayState state) + { + emit ViewportInfoStatusUpdated(static_cast(state)); + } + }; +} //end anonymous namespace + CViewportTitleDlg::CViewportTitleDlg(QWidget* pParent) : QWidget(pParent) , m_ui(new Ui::ViewportTitleDlg) @@ -115,14 +144,11 @@ void CViewportTitleDlg::OnInitDialog() m_ui->m_toggleHelpersBtn->setChecked(GetIEditor()->GetDisplaySettings()->IsDisplayHelpers()); - ICVar* pDisplayInfo(gEnv->pConsole->GetCVar("r_displayInfo")); - if (pDisplayInfo) - { - SFunctor oFunctor; - oFunctor.Set(OnChangedDisplayInfo, pDisplayInfo, m_ui->m_toggleDisplayInfoBtn); - m_displayInfoCallbackIndex = pDisplayInfo->AddOnChangeFunctor(oFunctor); - OnChangedDisplayInfo(pDisplayInfo, m_ui->m_toggleDisplayInfoBtn); - } + + // Add a child parented to us that listens for r_displayInfo changes. + auto displayInfoHelper = new CViewportTitleDlgDisplayInfoHelper(this); + connect(displayInfoHelper, &CViewportTitleDlgDisplayInfoHelper::ViewportInfoStatusUpdated, this, &CViewportTitleDlg::UpdateDisplayInfo); + UpdateDisplayInfo(); connect(m_ui->m_toggleHelpersBtn, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleHelpers); connect(m_ui->m_toggleDisplayInfoBtn, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleDisplayInfo); @@ -156,6 +182,29 @@ void CViewportTitleDlg::OnToggleHelpers() ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::OnToggleDisplayInfo() { + AZ::AtomBridge::ViewportInfoDisplayState state = AZ::AtomBridge::ViewportInfoDisplayState::NoInfo; + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::BroadcastResult( + state, + &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::GetDisplayState + ); + state = aznumeric_cast( + (aznumeric_cast(state)+1) % aznumeric_cast(AZ::AtomBridge::ViewportInfoDisplayState::Invalid)); + // SetDisplayState will fire OnViewportInfoDisplayStateChanged and notify us, no need to call UpdateDisplayInfo. + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast( + &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState, + state + ); +} + +////////////////////////////////////////////////////////////////////////// +void CViewportTitleDlg::UpdateDisplayInfo() +{ + AZ::AtomBridge::ViewportInfoDisplayState state = AZ::AtomBridge::ViewportInfoDisplayState::NoInfo; + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::BroadcastResult( + state, + &AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::GetDisplayState + ); + m_ui->m_toggleDisplayInfoBtn->setChecked(state != AZ::AtomBridge::ViewportInfoDisplayState::NoInfo); } ////////////////////////////////////////////////////////////////////////// @@ -544,10 +593,6 @@ void CViewportTitleDlg::UpdateCustomPresets(const QString& text, QStringList& cu } } -void CViewportTitleDlg::OnChangedDisplayInfo([[maybe_unused]] ICVar* pDisplayInfo, [[maybe_unused]] QAbstractButton* pDisplayInfoButton) -{ -} - bool CViewportTitleDlg::eventFilter(QObject* object, QEvent* event) { bool consumeEvent = false; @@ -609,4 +654,5 @@ namespace AzToolsFramework } } +#include "ViewportTitleDlg.moc" #include diff --git a/Code/Sandbox/Editor/ViewportTitleDlg.h b/Code/Sandbox/Editor/ViewportTitleDlg.h index 55741636b3..ce2f116d97 100644 --- a/Code/Sandbox/Editor/ViewportTitleDlg.h +++ b/Code/Sandbox/Editor/ViewportTitleDlg.h @@ -60,7 +60,6 @@ public: static void LoadCustomPresets(const QString& section, const QString& keyName, QStringList& outCustompresets); static void SaveCustomPresets(const QString& section, const QString& keyName, const QStringList& custompresets); static void UpdateCustomPresets(const QString& text, QStringList& custompresets); - static void OnChangedDisplayInfo(ICVar* pDisplayInfo, QAbstractButton* pDisplayInfoButton); bool eventFilter(QObject* object, QEvent* event) override; @@ -77,6 +76,7 @@ protected: void OnMaximize(); void OnToggleHelpers(); void OnToggleDisplayInfo(); + void UpdateDisplayInfo(); QString m_title; @@ -87,8 +87,6 @@ protected: QStringList m_customFOVPresets; QStringList m_customAspectRatioPresets; - uint64 m_displayInfoCallbackIndex; - void OnMenuFOVCustom(); void CreateFOVMenu(); diff --git a/Code/Sandbox/Editor/editor_lib_files.cmake b/Code/Sandbox/Editor/editor_lib_files.cmake index 401b7c6e39..8ad8c8263f 100644 --- a/Code/Sandbox/Editor/editor_lib_files.cmake +++ b/Code/Sandbox/Editor/editor_lib_files.cmake @@ -760,10 +760,13 @@ set(FILES Util/PakFile.h Util/PredefinedAspectRatios.cpp Util/PredefinedAspectRatios.h + Util/StringHelpers.cpp + Util/StringHelpers.h Util/StringNoCasePredicate.h Util/TRefCountBase.h Util/Triangulate.cpp Util/Triangulate.h + Util/Util.h Util/XmlArchive.cpp Util/XmlArchive.h Util/XmlHistoryManager.cpp diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp index df2e6bae10..053cfb45c9 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.cpp @@ -609,14 +609,6 @@ void CComponentEntityObject::InvalidateTM(int nWhyFlags) { Matrix34 worldTransform = GetWorldTM(); EBUS_EVENT_ID(m_entityId, AZ::TransformBus, SetWorldTM, LYTransformToAZTransform(worldTransform)); - - // When transformed via the editor, make sure the entity is marked dirty for undo capture. - EBUS_EVENT(AzToolsFramework::ToolsApplicationRequests::Bus, AddDirtyEntity, m_entityId); - - if (CheckFlags(OBJFLAG_SELECTED)) - { - EBUS_EVENT(AzToolsFramework::ToolsApplicationEvents::Bus, InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values); - } } } } diff --git a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp index 37c8d0adee..523e39d622 100644 --- a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp +++ b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp @@ -297,20 +297,28 @@ namespace AssetProcessor AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, platform, specialization, &scratchBuffer); // Merge the Project User and User home settings registry only in non-release builds + constexpr bool executeRegDumpCommands = false; + AZ::CommandLine* commandLine{}; + AZ::ComponentApplicationBus::Broadcast([®istry, &commandLine](AZ::ComponentApplicationRequests* appRequests) + { + commandLine = appRequests->GetAzCommandLine(); + }); + if (!specialization.Contains("release")) { AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, platform, specialization, &scratchBuffer); + if (commandLine) + { + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, *commandLine, executeRegDumpCommands); + } AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, platform, specialization, &scratchBuffer); } - AZ::ComponentApplicationBus::Broadcast([®istry](AZ::ComponentApplicationRequests* appRequests) + if (commandLine) { - if (AZ::CommandLine* commandLine = appRequests->GetAzCommandLine(); commandLine != nullptr) - { - constexpr bool executeRegDumpCommands = false; - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, *commandLine, executeRegDumpCommands); - } - }); + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, *commandLine, executeRegDumpCommands); + } + if (registry.Visit(exporter, "")) { diff --git a/Code/Tools/CMakeLists.txt b/Code/Tools/CMakeLists.txt index 278474819c..8541d9b882 100644 --- a/Code/Tools/CMakeLists.txt +++ b/Code/Tools/CMakeLists.txt @@ -14,7 +14,6 @@ add_subdirectory(AssetProcessor) add_subdirectory(AWSNativeSDKInit) add_subdirectory(AzTestRunner) add_subdirectory(CrashHandler) -add_subdirectory(CryCommonTools) add_subdirectory(News) add_subdirectory(PythonBindingsExample) add_subdirectory(RemoteConsole) diff --git a/Code/Tools/CryCommonTools/CMakeLists.txt b/Code/Tools/CryCommonTools/CMakeLists.txt deleted file mode 100644 index 63f535b1af..0000000000 --- a/Code/Tools/CryCommonTools/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -if (NOT PAL_TRAIT_BUILD_HOST_TOOLS) - return() -endif() - -ly_add_target( - NAME CryCommonTools STATIC - NAMESPACE Legacy - FILES_CMAKE - crycommontools_files.cmake - INCLUDE_DIRECTORIES - PUBLIC - . - BUILD_DEPENDENCIES - PRIVATE - AZ::AzCore - PUBLIC - Legacy::CryCommon - AZ::AzFramework -) diff --git a/Code/Tools/CryCommonTools/crycommontools_files.cmake b/Code/Tools/CryCommonTools/crycommontools_files.cmake deleted file mode 100644 index 204a65f907..0000000000 --- a/Code/Tools/CryCommonTools/crycommontools_files.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -set(FILES - StringHelpers.cpp - StringHelpers.h -) diff --git a/Code/CryEngine/CryCommon/Console_std.h b/Code/Tools/ProjectManager/Source/EngineInfo.cpp similarity index 74% rename from Code/CryEngine/CryCommon/Console_std.h rename to Code/Tools/ProjectManager/Source/EngineInfo.cpp index 55944a2960..8043a498ff 100644 --- a/Code/CryEngine/CryCommon/Console_std.h +++ b/Code/Tools/ProjectManager/Source/EngineInfo.cpp @@ -10,15 +10,12 @@ * */ -#pragma once +#include "EngineInfo.h" -#include - -#include - -namespace std +namespace O3DE::ProjectManager { -#if defined(AZ_RESTRICTED_PLATFORM) - #include AZ_RESTRICTED_FILE(Console_std_h) -#endif -} + EngineInfo::EngineInfo(const QString& path) + : m_path(path) + { + } +} // namespace O3DE::ProjectManager diff --git a/Code/CryEngine/CryCommon/IZStdDecompressor.h b/Code/Tools/ProjectManager/Source/EngineInfo.h similarity index 67% rename from Code/CryEngine/CryCommon/IZStdDecompressor.h rename to Code/Tools/ProjectManager/Source/EngineInfo.h index b5ab0f3088..ada6e73a15 100644 --- a/Code/CryEngine/CryCommon/IZStdDecompressor.h +++ b/Code/Tools/ProjectManager/Source/EngineInfo.h @@ -12,14 +12,18 @@ #pragma once +#if !defined(Q_MOC_RUN) +#include +#endif -class IZStdDecompressor +namespace O3DE::ProjectManager { -public: - virtual bool DecompressData(const char* pIn, const uint inputSize, char* pOut, const uint outputSize) = 0; - virtual void Release() = 0; - -protected: - virtual ~IZStdDecompressor() = default; // use Release() -}; + class EngineInfo + { + public: + EngineInfo() = default; + EngineInfo(const QString& path); + QString m_path; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/EngineSettings.cpp b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp similarity index 70% rename from Code/Tools/ProjectManager/Source/EngineSettings.cpp rename to Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp index bc359637e4..1adab41c0e 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettings.cpp +++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp @@ -10,26 +10,21 @@ * */ -#include +#include -#include +#include namespace O3DE::ProjectManager { - EngineSettings::EngineSettings(ProjectManagerWindow* window) - : ScreenWidget(window) + EngineSettingsScreen::EngineSettingsScreen(QWidget* parent) + : ScreenWidget(parent) , m_ui(new Ui::EngineSettingsClass()) { m_ui->setupUi(this); } - EngineSettings::~EngineSettings() + ProjectManagerScreen EngineSettingsScreen::GetScreenEnum() { + return ProjectManagerScreen::EngineSettings; } - - void EngineSettings::ConnectSlotsAndSignals() - { - // Do nothing for now - } - } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/EngineSettings.h b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h similarity index 81% rename from Code/Tools/ProjectManager/Source/EngineSettings.h rename to Code/Tools/ProjectManager/Source/EngineSettingsScreen.h index f90f760798..4baa3fb28c 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettings.h +++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h @@ -22,15 +22,13 @@ namespace Ui namespace O3DE::ProjectManager { - class EngineSettings + class EngineSettingsScreen : public ScreenWidget { public: - explicit EngineSettings(ProjectManagerWindow* window); - ~EngineSettings(); - - protected: - void ConnectSlotsAndSignals() override; + explicit EngineSettingsScreen(QWidget* parent = nullptr); + ~EngineSettingsScreen() = default; + ProjectManagerScreen GetScreenEnum() override; private: QScopedPointer m_ui; diff --git a/Code/Tools/ProjectManager/Source/EngineSettings.ui b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.ui similarity index 100% rename from Code/Tools/ProjectManager/Source/EngineSettings.ui rename to Code/Tools/ProjectManager/Source/EngineSettingsScreen.ui diff --git a/Code/Tools/ProjectManager/Source/FirstTimeUse.cpp b/Code/Tools/ProjectManager/Source/FirstTimeUse.cpp deleted file mode 100644 index 5f5dcd5087..0000000000 --- a/Code/Tools/ProjectManager/Source/FirstTimeUse.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#include - -#include - -namespace O3DE::ProjectManager -{ - FirstTimeUse::FirstTimeUse(ProjectManagerWindow* window) - : ScreenWidget(window) - , m_ui(new Ui::FirstTimeUseClass()) - { - m_ui->setupUi(this); - - ConnectSlotsAndSignals(); - } - - FirstTimeUse::~FirstTimeUse() - { - } - - void FirstTimeUse::ConnectSlotsAndSignals() - { - QObject::connect(m_ui->createProjectButton, &QPushButton::pressed, this, &FirstTimeUse::HandleNewProjectButton); - QObject::connect(m_ui->openProjectButton, &QPushButton::pressed, this, &FirstTimeUse::HandleOpenProjectButton); - } - - void FirstTimeUse::HandleNewProjectButton() - { - m_projectManagerWindow->ChangeToScreen(ProjectManagerScreen::NewProjectSettings); - } - void FirstTimeUse::HandleOpenProjectButton() - { - m_projectManagerWindow->ChangeToScreen(ProjectManagerScreen::ProjectsHome); - } - -} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.cpp b/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.cpp new file mode 100644 index 0000000000..aa4dee1aa6 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.cpp @@ -0,0 +1,44 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include + +#include + +namespace O3DE::ProjectManager +{ + FirstTimeUseScreen::FirstTimeUseScreen(QWidget* parent) + : ScreenWidget(parent) + , m_ui(new Ui::FirstTimeUseClass()) + { + m_ui->setupUi(this); + + connect(m_ui->createProjectButton, &QPushButton::pressed, this, &FirstTimeUseScreen::HandleNewProjectButton); + connect(m_ui->openProjectButton, &QPushButton::pressed, this, &FirstTimeUseScreen::HandleOpenProjectButton); + } + + ProjectManagerScreen FirstTimeUseScreen::GetScreenEnum() + { + return ProjectManagerScreen::FirstTimeUse; + } + + void FirstTimeUseScreen::HandleNewProjectButton() + { + emit ResetScreenRequest(ProjectManagerScreen::NewProjectSettingsCore); + emit ChangeScreenRequest(ProjectManagerScreen::NewProjectSettingsCore); + } + void FirstTimeUseScreen::HandleOpenProjectButton() + { + emit ChangeScreenRequest(ProjectManagerScreen::ProjectsHome); + } + +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/FirstTimeUse.h b/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.h similarity index 83% rename from Code/Tools/ProjectManager/Source/FirstTimeUse.h rename to Code/Tools/ProjectManager/Source/FirstTimeUseScreen.h index 708513d493..4b4a99f16a 100644 --- a/Code/Tools/ProjectManager/Source/FirstTimeUse.h +++ b/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.h @@ -22,15 +22,13 @@ namespace Ui namespace O3DE::ProjectManager { - class FirstTimeUse + class FirstTimeUseScreen : public ScreenWidget { public: - explicit FirstTimeUse(ProjectManagerWindow* window); - ~FirstTimeUse(); - - protected: - void ConnectSlotsAndSignals() override; + explicit FirstTimeUseScreen(QWidget* parent = nullptr); + ~FirstTimeUseScreen() = default; + ProjectManagerScreen GetScreenEnum() override; protected slots: void HandleNewProjectButton(); diff --git a/Code/Tools/ProjectManager/Source/FirstTimeUse.ui b/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.ui similarity index 100% rename from Code/Tools/ProjectManager/Source/FirstTimeUse.ui rename to Code/Tools/ProjectManager/Source/FirstTimeUseScreen.ui diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalog.cpp deleted file mode 100644 index 6bb1e4959f..0000000000 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalog.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#include -#include -#include -#include -#include - -namespace O3DE::ProjectManager -{ - GemCatalog::GemCatalog(ProjectManagerWindow* window) - : ScreenWidget(window) - { - m_gemModel = new GemModel(this); - - QVBoxLayout* vLayout = new QVBoxLayout(); - setLayout(vLayout); - - QHBoxLayout* hLayout = new QHBoxLayout(); - vLayout->addLayout(hLayout); - - QWidget* filterPlaceholderWidget = new QWidget(); - filterPlaceholderWidget->setFixedWidth(250); - hLayout->addWidget(filterPlaceholderWidget); - - m_gemListView = new GemListView(m_gemModel, this); - hLayout->addWidget(m_gemListView); - - QWidget* inspectorPlaceholderWidget = new QWidget(); - inspectorPlaceholderWidget->setFixedWidth(250); - hLayout->addWidget(inspectorPlaceholderWidget); - - // Temporary back and next buttons until they are centralized and shared. - QDialogButtonBox* backNextButtons = new QDialogButtonBox(); - vLayout->addWidget(backNextButtons); - - QPushButton* tempBackButton = backNextButtons->addButton("Back", QDialogButtonBox::RejectRole); - QPushButton* tempNextButton = backNextButtons->addButton("Next", QDialogButtonBox::AcceptRole); - connect(tempBackButton, &QPushButton::pressed, this, &GemCatalog::HandleBackButton); - connect(tempNextButton, &QPushButton::pressed, this, &GemCatalog::HandleConfirmButton); - - // Start: Temporary gem test data - { - m_gemModel->AddGem(GemInfo("EMotion FX", - "O3DE Foundation", - "EMFX is a real-time character animation system. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - (GemInfo::Android | GemInfo::iOS | GemInfo::macOS | GemInfo::Windows | GemInfo::Linux), - true)); - - m_gemModel->AddGem(O3DE::ProjectManager::GemInfo("Atom", - "O3DE Foundation", - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - GemInfo::Android | GemInfo::Windows | GemInfo::Linux | GemInfo::macOS, - true)); - - m_gemModel->AddGem(O3DE::ProjectManager::GemInfo("PhysX", - "O3DE London", - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - GemInfo::Android | GemInfo::Linux | GemInfo::macOS, - false)); - - m_gemModel->AddGem(O3DE::ProjectManager::GemInfo("Certificate Manager", - "O3DE Irvine", - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - GemInfo::Windows, - false)); - - m_gemModel->AddGem(O3DE::ProjectManager::GemInfo("Cloud Gem Framework", - "O3DE Seattle", - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", - GemInfo::iOS | GemInfo::Linux, - false)); - - m_gemModel->AddGem(O3DE::ProjectManager::GemInfo("Achievements", - "O3DE Foundation", - "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", - GemInfo::Android | GemInfo::Windows | GemInfo::Linux, - false)); - } - // End: Temporary gem test data - } - - void GemCatalog::HandleBackButton() - { - m_projectManagerWindow->ChangeToScreen(ProjectManagerScreen::NewProjectSettings); - } - void GemCatalog::HandleConfirmButton() - { - m_projectManagerWindow->ChangeToScreen(ProjectManagerScreen::ProjectsHome); - } -} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp new file mode 100644 index 0000000000..5737a188de --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -0,0 +1,167 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include +#include +#include +#include + +//#define USE_TESTGEMDATA + +namespace O3DE::ProjectManager +{ + GemCatalogScreen::GemCatalogScreen(QWidget* parent) + : ScreenWidget(parent) + { + m_gemModel = new GemModel(this); + + QVBoxLayout* vLayout = new QVBoxLayout(); + vLayout->setMargin(0); + setLayout(vLayout); + + QHBoxLayout* hLayout = new QHBoxLayout(); + vLayout->addLayout(hLayout); + + m_gemListView = new GemListView(m_gemModel, this); + m_gemInspector = new GemInspector(m_gemModel, this); + m_gemInspector->setFixedWidth(320); + + // Start: Temporary gem test data +#ifdef USE_TESTGEMDATA + QVector testGemData = GenerateTestData(); + for (const GemInfo& gemInfo : testGemData) + { + m_gemModel->AddGem(gemInfo); + } +#else + // End: Temporary gem test data + auto result = PythonBindingsInterface::Get()->GetGems(); + if (result.IsSuccess()) + { + for (auto gemInfo : result.GetValue()) + { + m_gemModel->AddGem(gemInfo); + } + } +#endif + + hLayout->addWidget(m_gemListView); + hLayout->addWidget(m_gemInspector); + + + // Select the first entry after everything got correctly sized + QTimer::singleShot(100, [=]{ + QModelIndex firstModelIndex = m_gemListView->model()->index(0,0); + m_gemListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); + }); + } + + QVector GemCatalogScreen::GenerateTestData() + { + QVector result; + + GemInfo gem("EMotion FX", + "O3DE Foundation", + "EMFX is a real-time character animation system. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + (GemInfo::Android | GemInfo::iOS | GemInfo::macOS | GemInfo::Windows | GemInfo::Linux), + true); + gem.m_directoryLink = "C:/"; + gem.m_documentationLink = "http://www.amazon.com"; + gem.m_dependingGemUuids = QStringList({"EMotionFX", "Atom"}); + gem.m_conflictingGemUuids = QStringList({"Vegetation", "Camera", "ScriptCanvas", "CloudCanvas", "Networking"}); + gem.m_version = "v1.01"; + gem.m_lastUpdatedDate = "24th April 2021"; + gem.m_binarySizeInKB = 40; + gem.m_features = QStringList({"Animation", "Assets", "Physics"}); + result.push_back(gem); + + gem.m_name = "Atom"; + gem.m_creator = "O3DE Seattle"; + gem.m_summary = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; + gem.m_platforms = (GemInfo::Android | GemInfo::Windows | GemInfo::Linux | GemInfo::macOS); + gem.m_isAdded = true; + gem.m_directoryLink = "C:/"; + gem.m_documentationLink = "https://aws.amazon.com/gametech/"; + gem.m_dependingGemUuids = QStringList({"EMotionFX", "Core", "AudioSystem", "Camera", "Particles"}); + gem.m_conflictingGemUuids = QStringList({"CloudCanvas", "NovaNet"}); + gem.m_version = "v2.31"; + gem.m_lastUpdatedDate = "24th November 2020"; + gem.m_features = QStringList({"Assets", "Rendering", "UI", "VR", "Debug", "Environment"}); + gem.m_binarySizeInKB = 2087; + result.push_back(gem); + + gem.m_name = "Physics"; + gem.m_creator = "O3DE London"; + gem.m_summary = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + gem.m_platforms = (GemInfo::Android | GemInfo::Linux | GemInfo::macOS); + gem.m_isAdded = true; + gem.m_directoryLink = "C:/"; + gem.m_documentationLink = "https://aws.amazon.com/gametech/"; + gem.m_dependingGemUuids = QStringList({"GraphCanvas", "ExpressionEvaluation", "UI Lib", "Multiplayer", "GameStateSamples"}); + gem.m_conflictingGemUuids = QStringList({"Cloud Canvas", "EMotion FX", "Streaming", "MessagePopup", "Cloth", "Graph Canvas", "Twitch Integration"}); + gem.m_version = "v1.5.102145"; + gem.m_lastUpdatedDate = "1st January 2021"; + gem.m_binarySizeInKB = 2000000; + gem.m_features = QStringList({"Physics", "Gameplay", "Debug", "Assets"}); + result.push_back(gem); + + result.push_back(O3DE::ProjectManager::GemInfo("Certificate Manager", + "O3DE Irvine", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + GemInfo::Windows, + false)); + + result.push_back(O3DE::ProjectManager::GemInfo("Cloud Gem Framework", + "O3DE Seattle", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + GemInfo::iOS | GemInfo::Linux, + false)); + + result.push_back(O3DE::ProjectManager::GemInfo("Cloud Gem Core", + "O3DE Foundation", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + GemInfo::Android | GemInfo::Windows | GemInfo::Linux, + true)); + + result.push_back(O3DE::ProjectManager::GemInfo("Gestures", + "O3DE Foundation", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + GemInfo::Android | GemInfo::Windows | GemInfo::Linux, + false)); + + result.push_back(O3DE::ProjectManager::GemInfo("Effects System", + "O3DE Foundation", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + GemInfo::Android | GemInfo::Windows | GemInfo::Linux, + true)); + + result.push_back(O3DE::ProjectManager::GemInfo("Microphone", + "O3DE Foundation", + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus euismod ligula vitae dui dictum, a sodales dolor luctus. Sed id elit dapibus, finibus neque sed, efficitur mi. Nam facilisis ligula at eleifend pellentesque. Praesent non ex consectetur, blandit tellus in, venenatis lacus. Duis nec neque in urna ullamcorper euismod id eu leo. Nam efficitur dolor sed odio vehicula venenatis. Suspendisse nec est non velit commodo cursus in sit amet dui. Ut bibendum nisl et libero hendrerit dapibus. Vestibulum ultrices ullamcorper urna, placerat porttitor est lobortis in. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer a magna ac tellus sollicitudin porttitor. Phasellus lobortis viverra justo id bibendum. Etiam ac pharetra risus. Nulla vitae justo nibh. Nulla viverra leo et molestie interdum. Duis sit amet bibendum nulla, sit amet vehicula augue.", + GemInfo::Android | GemInfo::Windows | GemInfo::Linux, + false)); + + return result; + } + + ProjectManagerScreen GemCatalogScreen::GetScreenEnum() + { + return ProjectManagerScreen::GemCatalog; + } + + QString GemCatalogScreen::GetNextButtonText() + { + return "Create Project"; + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalog.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h similarity index 71% rename from Code/Tools/ProjectManager/Source/GemCatalog/GemCatalog.h rename to Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 489752bbe7..6a9c88d0f5 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalog.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -14,24 +14,26 @@ #if !defined(Q_MOC_RUN) #include #include +#include #include #endif namespace O3DE::ProjectManager { - class GemCatalog + class GemCatalogScreen : public ScreenWidget { public: - explicit GemCatalog(ProjectManagerWindow* window); - ~GemCatalog() = default; - - protected slots: - void HandleBackButton(); - void HandleConfirmButton(); + explicit GemCatalogScreen(QWidget* parent = nullptr); + ~GemCatalogScreen() = default; + ProjectManagerScreen GetScreenEnum() override; + QString GetNextButtonText() override; private: + QVector GenerateTestData(); + GemListView* m_gemListView = nullptr; + GemInspector* m_gemInspector = nullptr; GemModel* m_gemModel = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp index b11c7a7a2c..729935fc8e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp @@ -22,4 +22,33 @@ namespace O3DE::ProjectManager , m_isAdded(isAdded) { } + + bool GemInfo::IsValid() const + { + return !m_path.isEmpty() && !m_uuid.IsNull(); + } + + QString GemInfo::GetPlatformString(Platform platform) + { + switch (platform) + { + case O3DE::ProjectManager::GemInfo::Android: + return "Android"; + case O3DE::ProjectManager::GemInfo::iOS: + return "iOS"; + case O3DE::ProjectManager::GemInfo::Linux: + return "Linux"; + case O3DE::ProjectManager::GemInfo::macOS: + return "macOS"; + case O3DE::ProjectManager::GemInfo::Windows: + return "Windows"; + default: + return ""; + } + } + + bool GemInfo::IsPlatformSupported(Platform platform) const + { + return (m_platforms & platform); + } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h index 4766187d2a..7ee619702f 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h @@ -34,8 +34,13 @@ namespace O3DE::ProjectManager NumPlatforms = 5 }; Q_DECLARE_FLAGS(Platforms, Platform) + static QString GetPlatformString(Platform platform); + GemInfo() = default; GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded); + bool IsPlatformSupported(Platform platform) const; + + bool IsValid() const; QString m_path; QString m_name; @@ -46,11 +51,13 @@ namespace O3DE::ProjectManager QString m_summary; Platforms m_platforms; QStringList m_features; + QString m_directoryLink; + QString m_documentationLink; QString m_version; QString m_lastUpdatedDate; - QString m_documentationUrl; - QVector m_dependingGemUuids; - QVector m_conflictingGemUuids; + int m_binarySizeInKB = 0; + QStringList m_dependingGemUuids; + QStringList m_conflictingGemUuids; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp new file mode 100644 index 0000000000..e7c682afd1 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp @@ -0,0 +1,176 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include +#include +#include +#include + +namespace O3DE::ProjectManager +{ + GemInspector::GemInspector(GemModel* model, QWidget* parent) + : QScrollArea(parent) + , m_model(model) + { + setWidgetResizable(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + m_mainWidget = new QWidget(); + setWidget(m_mainWidget); + + m_mainLayout = new QVBoxLayout(); + m_mainLayout->setMargin(15); + m_mainLayout->setAlignment(Qt::AlignTop); + m_mainWidget->setLayout(m_mainLayout); + + InitMainWidget(); + + connect(m_model->GetSelectionModel(), &QItemSelectionModel::selectionChanged, this, &GemInspector::OnSelectionChanged); + Update({}); + } + + void GemInspector::OnSelectionChanged(const QItemSelection& selected, [[maybe_unused]] const QItemSelection& deselected) + { + const QModelIndexList selectedIndices = selected.indexes(); + if (selectedIndices.empty()) + { + Update({}); + return; + } + + Update(selectedIndices[0]); + } + + void GemInspector::Update(const QModelIndex& modelIndex) + { + if (!modelIndex.isValid()) + { + m_mainWidget->hide(); + } + + m_nameLabel->setText(m_model->GetName(modelIndex)); + m_creatorLabel->setText(m_model->GetCreator(modelIndex)); + + m_summaryLabel->setText(m_model->GetSummary(modelIndex)); + m_summaryLabel->adjustSize(); + + m_directoryLinkLabel->SetUrl(m_model->GetDirectoryLink(modelIndex)); + m_documentationLinkLabel->SetUrl(m_model->GetDocLink(modelIndex)); + + // Depending and conflicting gems + m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGems(modelIndex)); + m_conflictingGems->Update("Conflicting Gems", "The following Gems will be automatically disabled with this Gem.", m_model->GetConflictingGems(modelIndex)); + + // Additional information + m_versionLabel->setText(QString("Gem Version: %1").arg(m_model->GetVersion(modelIndex))); + m_lastUpdatedLabel->setText(QString("Last Updated: %1").arg(m_model->GetLastUpdated(modelIndex))); + m_binarySizeLabel->setText(QString("Binary Size: %1 KB").arg(QString::number(m_model->GetBinarySizeInKB(modelIndex)))); + + m_mainWidget->adjustSize(); + m_mainWidget->show(); + } + + QLabel* GemInspector::CreateStyledLabel(QLayout* layout, int fontSize, const QString& colorCodeString) + { + QLabel* result = new QLabel(); + result->setStyleSheet(QString("font-size: %1pt; color: %2;").arg(QString::number(fontSize), colorCodeString)); + layout->addWidget(result); + return result; + } + + void GemInspector::InitMainWidget() + { + // Gem name, creator and summary + m_nameLabel = CreateStyledLabel(m_mainLayout, 17, s_headerColor); + m_creatorLabel = CreateStyledLabel(m_mainLayout, 12, s_creatorColor); + m_mainLayout->addSpacing(5); + + // TODO: QLabel seems to have issues determining the right sizeHint() for our font with the given font size. + // This results into squeezed elements in the layout in case the text is a little longer than a sentence. + m_summaryLabel = new QLabel();//CreateLabel(m_mainLayout, 12, s_textColor); + m_mainLayout->addWidget(m_summaryLabel); + m_summaryLabel->setWordWrap(true); + m_mainLayout->addSpacing(5); + + // Directory and documentation links + { + QHBoxLayout* linksHLayout = new QHBoxLayout(); + linksHLayout->setMargin(0); + m_mainLayout->addLayout(linksHLayout); + + QSpacerItem* spacerLeft = new QSpacerItem(0, 0, QSizePolicy::Expanding); + linksHLayout->addSpacerItem(spacerLeft); + + m_directoryLinkLabel = new LinkLabel("View in Directory"); + linksHLayout->addWidget(m_directoryLinkLabel); + linksHLayout->addWidget(new QLabel("|")); + m_documentationLinkLabel = new LinkLabel("Read Documentation"); + linksHLayout->addWidget(m_documentationLinkLabel); + + QSpacerItem* spacerRight = new QSpacerItem(0, 0, QSizePolicy::Expanding); + linksHLayout->addSpacerItem(spacerRight); + + m_mainLayout->addSpacing(8); + } + + // Separating line + QFrame* hLine = new QFrame(); + hLine->setFrameShape(QFrame::HLine); + hLine->setStyleSheet("color: #666666;"); + m_mainLayout->addWidget(hLine); + + m_mainLayout->addSpacing(10); + + // Depending and conflicting gems + m_dependingGems = new GemsSubWidget(); + m_mainLayout->addWidget(m_dependingGems); + m_mainLayout->addSpacing(20); + + m_conflictingGems = new GemsSubWidget(); + m_mainLayout->addWidget(m_conflictingGems); + m_mainLayout->addSpacing(20); + + // Additional information + QLabel* additionalInfoLabel = CreateStyledLabel(m_mainLayout, 14, s_headerColor); + additionalInfoLabel->setText("Additional Information"); + + m_versionLabel = CreateStyledLabel(m_mainLayout, 11, s_textColor); + m_lastUpdatedLabel = CreateStyledLabel(m_mainLayout, 11, s_textColor); + m_binarySizeLabel = CreateStyledLabel(m_mainLayout, 11, s_textColor); + } + + GemInspector::GemsSubWidget::GemsSubWidget(QWidget* parent) + : QWidget(parent) + { + m_layout = new QVBoxLayout(); + m_layout->setAlignment(Qt::AlignTop); + m_layout->setMargin(0); + setLayout(m_layout); + + m_titleLabel = GemInspector::CreateStyledLabel(m_layout, 15, s_headerColor); + m_textLabel = GemInspector::CreateStyledLabel(m_layout, 9, s_textColor); + m_textLabel->setWordWrap(true); + + m_tagWidget = new TagContainerWidget(); + m_layout->addWidget(m_tagWidget); + } + + void GemInspector::GemsSubWidget::Update(const QString& title, const QString& text, const QStringList& gemNames) + { + m_titleLabel->setText(title); + m_textLabel->setText(text); + m_tagWidget->Update(gemNames); + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h new file mode 100644 index 0000000000..69c065c81e --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h @@ -0,0 +1,88 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#include +#include +#include +#include +#endif + +QT_FORWARD_DECLARE_CLASS(QVBoxLayout) +QT_FORWARD_DECLARE_CLASS(QLabel) + +namespace O3DE::ProjectManager +{ + class GemInspector + : public QScrollArea + { + Q_OBJECT // AUTOMOC + + public: + explicit GemInspector(GemModel* model, QWidget* parent = nullptr); + ~GemInspector() = default; + + void Update(const QModelIndex& modelIndex); + static QLabel* CreateStyledLabel(QLayout* layout, int fontSize, const QString& colorCodeString); + + // Colors + inline constexpr static const char* s_headerColor = "#FFFFFF"; + inline constexpr static const char* s_textColor = "#DDDDDD"; + inline constexpr static const char* s_creatorColor = "#94D2FF"; + + private slots: + void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); + + private: + // Title, description and tag widget container used for the depending and conflicting gems + class GemsSubWidget + : public QWidget + { + public: + GemsSubWidget(QWidget* parent = nullptr); + void Update(const QString& title, const QString& text, const QStringList& gemNames); + + private: + QLabel* m_titleLabel = nullptr; + QLabel* m_textLabel = nullptr; + QVBoxLayout* m_layout = nullptr; + TagContainerWidget* m_tagWidget = nullptr; + }; + + void InitMainWidget(); + + GemModel* m_model = nullptr; + QWidget* m_mainWidget = nullptr; + QVBoxLayout* m_mainLayout = nullptr; + + // General info (top) section + QLabel* m_nameLabel = nullptr; + QLabel* m_creatorLabel = nullptr; + QLabel* m_summaryLabel = nullptr; + LinkLabel* m_directoryLinkLabel = nullptr; + LinkLabel* m_documentationLinkLabel = nullptr; + + // Depending and conflicting gems + GemsSubWidget* m_dependingGems = nullptr; + GemsSubWidget* m_conflictingGems = nullptr; + + // Additional information + QLabel* m_versionLabel = nullptr; + QLabel* m_lastUpdatedLabel = nullptr; + QLabel* m_binarySizeLabel = nullptr; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 27905fd4d2..1112c656f3 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -37,6 +37,16 @@ namespace O3DE::ProjectManager item->setData(gemInfo.m_summary, RoleSummary); item->setData(gemInfo.m_isAdded, RoleIsAdded); + item->setData(gemInfo.m_directoryLink, RoleDirectoryLink); + item->setData(gemInfo.m_documentationLink, RoleDocLink); + item->setData(gemInfo.m_dependingGemUuids, RoleDependingGems); + item->setData(gemInfo.m_conflictingGemUuids, RoleConflictingGems); + item->setData(gemInfo.m_version, RoleVersion); + item->setData(gemInfo.m_lastUpdatedDate, RoleLastUpdated); + item->setData(gemInfo.m_binarySizeInKB, RoleBinarySize); + + item->setData(gemInfo.m_features, RoleFeatures); + appendRow(item); } @@ -45,28 +55,68 @@ namespace O3DE::ProjectManager clear(); } - QString GemModel::GetName(const QModelIndex& modelIndex) const + QString GemModel::GetName(const QModelIndex& modelIndex) { return modelIndex.data(RoleName).toString(); } - QString GemModel::GetCreator(const QModelIndex& modelIndex) const + QString GemModel::GetCreator(const QModelIndex& modelIndex) { return modelIndex.data(RoleCreator).toString(); } - GemInfo::Platforms GemModel::GetPlatforms(const QModelIndex& modelIndex) const + GemInfo::Platforms GemModel::GetPlatforms(const QModelIndex& modelIndex) { return static_cast(modelIndex.data(RolePlatforms).toInt()); } - QString GemModel::GetSummary(const QModelIndex& modelIndex) const + QString GemModel::GetSummary(const QModelIndex& modelIndex) { return modelIndex.data(RoleSummary).toString(); } - bool GemModel::IsAdded(const QModelIndex& modelIndex) const + bool GemModel::IsAdded(const QModelIndex& modelIndex) { return modelIndex.data(RoleIsAdded).toBool(); } + + QString GemModel::GetDirectoryLink(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleDirectoryLink).toString(); + } + + QString GemModel::GetDocLink(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleDocLink).toString(); + } + + QStringList GemModel::GetDependingGems(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleDependingGems).toStringList(); + } + + QStringList GemModel::GetConflictingGems(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleConflictingGems).toStringList(); + } + + QString GemModel::GetVersion(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleVersion).toString(); + } + + QString GemModel::GetLastUpdated(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleLastUpdated).toString(); + } + + int GemModel::GetBinarySizeInKB(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleBinarySize).toInt(); + } + + QStringList GemModel::GetFeatures(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleFeatures).toStringList(); + } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 4ce9de32fc..fba65e7009 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -14,6 +14,7 @@ #if !defined(Q_MOC_RUN) #include "GemInfo.h" +#include #include #include #endif @@ -32,11 +33,19 @@ namespace O3DE::ProjectManager void AddGem(const GemInfo& gemInfo); void Clear(); - QString GetName(const QModelIndex& modelIndex) const; - QString GetCreator(const QModelIndex& modelIndex) const; - GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex) const; - QString GetSummary(const QModelIndex& modelIndex) const; - bool IsAdded(const QModelIndex& modelIndex) const; + static QString GetName(const QModelIndex& modelIndex); + static QString GetCreator(const QModelIndex& modelIndex); + static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex); + static QString GetSummary(const QModelIndex& modelIndex); + static bool IsAdded(const QModelIndex& modelIndex); + static QString GetDirectoryLink(const QModelIndex& modelIndex); + static QString GetDocLink(const QModelIndex& modelIndex); + static QStringList GetDependingGems(const QModelIndex& modelIndex); + static QStringList GetConflictingGems(const QModelIndex& modelIndex); + static QString GetVersion(const QModelIndex& modelIndex); + static QString GetLastUpdated(const QModelIndex& modelIndex); + static int GetBinarySizeInKB(const QModelIndex& modelIndex); + static QStringList GetFeatures(const QModelIndex& modelIndex); private: enum UserRole @@ -45,7 +54,15 @@ namespace O3DE::ProjectManager RoleCreator, RolePlatforms, RoleSummary, - RoleIsAdded + RoleIsAdded, + RoleDirectoryLink, + RoleDocLink, + RoleDependingGems, + RoleConflictingGems, + RoleVersion, + RoleLastUpdated, + RoleBinarySize, + RoleFeatures, }; QItemSelectionModel* m_selectionModel = nullptr; diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettings.cpp b/Code/Tools/ProjectManager/Source/NewProjectSettings.cpp deleted file mode 100644 index 2ebe54e682..0000000000 --- a/Code/Tools/ProjectManager/Source/NewProjectSettings.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#include - -#include - -namespace O3DE::ProjectManager -{ - NewProjectSettings::NewProjectSettings(ProjectManagerWindow* window) - : ScreenWidget(window) - , m_ui(new Ui::NewProjectSettingsClass()) - { - m_ui->setupUi(this); - - ConnectSlotsAndSignals(); - } - - NewProjectSettings::~NewProjectSettings() - { - } - - void NewProjectSettings::ConnectSlotsAndSignals() - { - QObject::connect(m_ui->backButton, &QPushButton::pressed, this, &NewProjectSettings::HandleBackButton); - QObject::connect(m_ui->nextButton, &QPushButton::pressed, this, &NewProjectSettings::HandleNextButton); - } - - void NewProjectSettings::HandleBackButton() - { - m_projectManagerWindow->ChangeToScreen(ProjectManagerScreen::FirstTimeUse); - } - void NewProjectSettings::HandleNextButton() - { - m_projectManagerWindow->ChangeToScreen(ProjectManagerScreen::GemCatalog); - } - -} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettings.ui b/Code/Tools/ProjectManager/Source/NewProjectSettings.ui deleted file mode 100644 index 98db10338e..0000000000 --- a/Code/Tools/ProjectManager/Source/NewProjectSettings.ui +++ /dev/null @@ -1,97 +0,0 @@ - - - NewProjectSettingsClass - - - - 0 - 0 - 880 - 546 - - - - Form - - - - - - Project Name - - - - - - - - - - Project Path - - - - - - - - - - Project Template - - - - - - - - - Standard (Recommened) - - - - - - - Empty - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Back - - - - - - - Next - - - - - - - - - - diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp new file mode 100644 index 0000000000..976850cb87 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp @@ -0,0 +1,82 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +namespace O3DE::ProjectManager +{ + NewProjectSettingsScreen::NewProjectSettingsScreen(QWidget* parent) + : ScreenWidget(parent) + { + QHBoxLayout* hLayout = new QHBoxLayout(); + this->setLayout(hLayout); + + QVBoxLayout* vLayout = new QVBoxLayout(this); + + QLabel* projectNameLabel = new QLabel(this); + projectNameLabel->setText("Project Name"); + vLayout->addWidget(projectNameLabel); + + QLineEdit* projectNameLineEdit = new QLineEdit(this); + vLayout->addWidget(projectNameLineEdit); + + QLabel* projectPathLabel = new QLabel(this); + projectPathLabel->setText("Project Location"); + vLayout->addWidget(projectPathLabel); + + QLineEdit* projectPathLineEdit = new QLineEdit(this); + vLayout->addWidget(projectPathLineEdit); + + QLabel* projectTemplateLabel = new QLabel(this); + projectTemplateLabel->setText("Project Template"); + vLayout->addWidget(projectTemplateLabel); + + QHBoxLayout* templateLayout = new QHBoxLayout(this); + vLayout->addItem(templateLayout); + + QRadioButton* projectTemplateStandardRadioButton = new QRadioButton(this); + projectTemplateStandardRadioButton->setText("Standard (Recommened)"); + projectTemplateStandardRadioButton->setChecked(true); + templateLayout->addWidget(projectTemplateStandardRadioButton); + + QRadioButton* projectTemplateEmptyRadioButton = new QRadioButton(this); + projectTemplateEmptyRadioButton->setText("Empty"); + templateLayout->addWidget(projectTemplateEmptyRadioButton); + + QSpacerItem* verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); + vLayout->addItem(verticalSpacer); + + hLayout->addItem(vLayout); + + QWidget* gemsListPlaceholder = new QWidget(this); + gemsListPlaceholder->setFixedWidth(250); + hLayout->addWidget(gemsListPlaceholder); + } + + ProjectManagerScreen NewProjectSettingsScreen::GetScreenEnum() + { + return ProjectManagerScreen::NewProjectSettings; + } + + QString NewProjectSettingsScreen::GetNextButtonText() + { + return "Create Project"; + } + +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h new file mode 100644 index 0000000000..2589f00fcd --- /dev/null +++ b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h @@ -0,0 +1,30 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#endif + +namespace O3DE::ProjectManager +{ + class NewProjectSettingsScreen + : public ScreenWidget + { + public: + explicit NewProjectSettingsScreen(QWidget* parent = nullptr); + ~NewProjectSettingsScreen() = default; + ProjectManagerScreen GetScreenEnum() override; + QString GetNextButtonText() override; + }; + +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp index b3bdb87224..4dc6eaa38b 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.cpp @@ -14,11 +14,20 @@ namespace O3DE::ProjectManager { - ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& productName, const AZ::Uuid projectId) + ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& productName, const AZ::Uuid projectId, + const QString& imagePath, const QString& backgroundImagePath, bool isNew) : m_path(path) , m_projectName(projectName) , m_productName(productName) , m_projectId(projectId) + , m_imagePath(imagePath) + , m_backgroundImagePath(backgroundImagePath) + , m_isNew(isNew) { } + + bool ProjectInfo::IsValid() const + { + return !m_path.isEmpty() && !m_projectId.IsNull(); + } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectInfo.h b/Code/Tools/ProjectManager/Source/ProjectInfo.h index e5dca97d5e..d86991e76e 100644 --- a/Code/Tools/ProjectManager/Source/ProjectInfo.h +++ b/Code/Tools/ProjectManager/Source/ProjectInfo.h @@ -23,14 +23,24 @@ namespace O3DE::ProjectManager { public: ProjectInfo() = default; - ProjectInfo(const QString& path, const QString& projectName, const QString& productName, const AZ::Uuid projectId); + ProjectInfo(const QString& path, const QString& projectName, const QString& productName, const AZ::Uuid projectId, + const QString& imagePath, const QString& backgroundImagePath, bool isNew); + + bool IsValid() const; // from o3de_manifest.json and o3de_projects.json QString m_path; - // from project.json + // From project.json QString m_projectName; QString m_productName; AZ::Uuid m_projectId; + + // Used on projects home screen + QString m_imagePath; + QString m_backgroundImagePath; + + // Used in project creation + bool m_isNew = false; //! Is this a new project or existing }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp index c86ebeee86..977667071f 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp @@ -30,7 +30,11 @@ namespace O3DE::ProjectManager m_pythonBindings = AZStd::make_unique(engineRootPath); - ConnectSlotsAndSignals(); + m_screensCtrl = new ScreensCtrl(); + m_ui->verticalLayout->addWidget(m_screensCtrl); + + connect(m_ui->projectsMenu, &QMenu::aboutToShow, this, &ProjectManagerWindow::HandleProjectsMenu); + connect(m_ui->engineMenu, &QMenu::aboutToShow, this, &ProjectManagerWindow::HandleEngineMenu); QDir rootDir = QString::fromUtf8(engineRootPath.Native().data(), aznumeric_cast(engineRootPath.Native().size())); const auto pathOnDisk = rootDir.absoluteFilePath("Code/Tools/ProjectManager/Resources"); @@ -39,9 +43,16 @@ namespace O3DE::ProjectManager AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("projectlauncherwindow:ProjectManagerWindow.qss")); - BuildScreens(); - - ChangeToScreen(ProjectManagerScreen::FirstTimeUse); + QVector screenEnums = + { + ProjectManagerScreen::FirstTimeUse, + ProjectManagerScreen::NewProjectSettingsCore, + ProjectManagerScreen::ProjectsHome, + ProjectManagerScreen::ProjectSettings, + ProjectManagerScreen::EngineSettings + }; + m_screensCtrl->BuildScreens(screenEnums); + m_screensCtrl->ForceChangeToScreen(ProjectManagerScreen::FirstTimeUse, false); } ProjectManagerWindow::~ProjectManagerWindow() @@ -49,61 +60,13 @@ namespace O3DE::ProjectManager m_pythonBindings.reset(); } - void ProjectManagerWindow::BuildScreens() - { - // Basically just iterate over the ProjectManagerScreen enum creating each screen - // Could add some fancy to do this but there are few screens right now - - ResetScreen(ProjectManagerScreen::FirstTimeUse); - ResetScreen(ProjectManagerScreen::NewProjectSettings); - ResetScreen(ProjectManagerScreen::GemCatalog); - ResetScreen(ProjectManagerScreen::ProjectsHome); - ResetScreen(ProjectManagerScreen::ProjectSettings); - ResetScreen(ProjectManagerScreen::EngineSettings); - } - - QStackedWidget* ProjectManagerWindow::GetScreenStack() - { - return m_ui->stackedScreens; - } - - void ProjectManagerWindow::ChangeToScreen(ProjectManagerScreen screen) - { - int index = aznumeric_cast(screen); - m_ui->stackedScreens->setCurrentIndex(index); - } - - void ProjectManagerWindow::ResetScreen(ProjectManagerScreen screen) - { - int index = aznumeric_cast(screen); - - // Fine the old screen if it exists and get rid of it so we can start fresh - QWidget* oldScreen = m_ui->stackedScreens->widget(index); - - if (oldScreen) - { - m_ui->stackedScreens->removeWidget(oldScreen); - oldScreen->deleteLater(); - } - - // Add new screen - QWidget* newScreen = BuildScreen(this, screen); - m_ui->stackedScreens->insertWidget(index, newScreen); - } - - void ProjectManagerWindow::ConnectSlotsAndSignals() - { - QObject::connect(m_ui->projectsMenu, &QMenu::aboutToShow, this, &ProjectManagerWindow::HandleProjectsMenu); - QObject::connect(m_ui->engineMenu, &QMenu::aboutToShow, this, &ProjectManagerWindow::HandleEngineMenu); - } - void ProjectManagerWindow::HandleProjectsMenu() { - ChangeToScreen(ProjectManagerScreen::ProjectsHome); + m_screensCtrl->ChangeToScreen(ProjectManagerScreen::ProjectsHome); } void ProjectManagerWindow::HandleEngineMenu() { - ChangeToScreen(ProjectManagerScreen::EngineSettings); + m_screensCtrl->ChangeToScreen(ProjectManagerScreen::EngineSettings); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h index 6a17c4464c..d5c586e59b 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h +++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h @@ -12,10 +12,9 @@ #pragma once #if !defined(Q_MOC_RUN) -#include - #include -#include + +#include #include #endif @@ -36,22 +35,13 @@ namespace O3DE::ProjectManager explicit ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath); ~ProjectManagerWindow(); - void BuildScreens(); - QStackedWidget* GetScreenStack(); - - public slots: - void ChangeToScreen(ProjectManagerScreen screen); - void ResetScreen(ProjectManagerScreen screen); - - protected: - void ConnectSlotsAndSignals(); - protected slots: void HandleProjectsMenu(); void HandleEngineMenu(); private: QScopedPointer m_ui; + ScreensCtrl* m_screensCtrl; AZStd::unique_ptr m_pythonBindings; }; diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui index 704e74e38e..789dd1b656 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui +++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui @@ -14,11 +14,7 @@ O3DE Project Manager - - - - - + diff --git a/Code/Tools/ProjectManager/Source/ProjectSettingsCtrl.cpp b/Code/Tools/ProjectManager/Source/ProjectSettingsCtrl.cpp new file mode 100644 index 0000000000..1dccabb484 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ProjectSettingsCtrl.cpp @@ -0,0 +1,95 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include + +#include +#include +#include + +namespace O3DE::ProjectManager +{ + ProjectSettingsCtrl::ProjectSettingsCtrl(QWidget* parent) + : ScreenWidget(parent) + { + QVBoxLayout* vLayout = new QVBoxLayout(); + setLayout(vLayout); + + m_screensCtrl = new ScreensCtrl(); + vLayout->addWidget(m_screensCtrl); + + QDialogButtonBox* backNextButtons = new QDialogButtonBox(); + vLayout->addWidget(backNextButtons); + + m_backButton = backNextButtons->addButton("Back", QDialogButtonBox::RejectRole); + m_nextButton = backNextButtons->addButton("Next", QDialogButtonBox::ApplyRole); + + connect(m_backButton, &QPushButton::pressed, this, &ProjectSettingsCtrl::HandleBackButton); + connect(m_nextButton, &QPushButton::pressed, this, &ProjectSettingsCtrl::HandleNextButton); + + m_screensOrder = + { + ProjectManagerScreen::NewProjectSettings, + ProjectManagerScreen::GemCatalog + }; + m_screensCtrl->BuildScreens(m_screensOrder); + m_screensCtrl->ForceChangeToScreen(ProjectManagerScreen::NewProjectSettings, false); + UpdateNextButtonText(); + } + + ProjectManagerScreen ProjectSettingsCtrl::GetScreenEnum() + { + return ProjectManagerScreen::NewProjectSettingsCore; + } + + void ProjectSettingsCtrl::HandleBackButton() + { + if (!m_screensCtrl->GotoPreviousScreen()) + { + emit GotoPreviousScreenRequest(); + } + else + { + UpdateNextButtonText(); + } + } + void ProjectSettingsCtrl::HandleNextButton() + { + ProjectManagerScreen screenEnum = m_screensCtrl->GetCurrentScreen()->GetScreenEnum(); + auto screenOrderIter = m_screensOrder.begin(); + for (; screenOrderIter != m_screensOrder.end(); ++screenOrderIter) + { + if (*screenOrderIter == screenEnum) + { + ++screenOrderIter; + break; + } + } + + if (screenOrderIter != m_screensOrder.end()) + { + m_screensCtrl->ChangeToScreen(*screenOrderIter); + UpdateNextButtonText(); + } + else + { + emit ChangeScreenRequest(ProjectManagerScreen::ProjectsHome); + } + } + + void ProjectSettingsCtrl::UpdateNextButtonText() + { + m_nextButton->setText(m_screensCtrl->GetCurrentScreen()->GetNextButtonText()); + } + +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettings.h b/Code/Tools/ProjectManager/Source/ProjectSettingsCtrl.h similarity index 65% rename from Code/Tools/ProjectManager/Source/NewProjectSettings.h rename to Code/Tools/ProjectManager/Source/ProjectSettingsCtrl.h index f5fa91a9b9..0b46436df1 100644 --- a/Code/Tools/ProjectManager/Source/NewProjectSettings.h +++ b/Code/Tools/ProjectManager/Source/ProjectSettingsCtrl.h @@ -13,31 +13,33 @@ #if !defined(Q_MOC_RUN) #include -#endif -namespace Ui -{ - class NewProjectSettingsClass; -} +#include + +#include +#endif namespace O3DE::ProjectManager { - class NewProjectSettings + class ProjectSettingsCtrl : public ScreenWidget { public: - explicit NewProjectSettings(ProjectManagerWindow* window); - ~NewProjectSettings(); - - protected: - void ConnectSlotsAndSignals() override; + explicit ProjectSettingsCtrl(QWidget* parent = nullptr); + ~ProjectSettingsCtrl() = default; + ProjectManagerScreen GetScreenEnum() override; protected slots: void HandleBackButton(); void HandleNextButton(); private: - QScopedPointer m_ui; + void UpdateNextButtonText(); + + ScreensCtrl* m_screensCtrl; + QPushButton* m_backButton; + QPushButton* m_nextButton; + QVector m_screensOrder; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectSettings.cpp b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp similarity index 57% rename from Code/Tools/ProjectManager/Source/ProjectSettings.cpp rename to Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp index bc653f9c5b..52fca439b4 100644 --- a/Code/Tools/ProjectManager/Source/ProjectSettings.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp @@ -10,33 +10,29 @@ * */ -#include +#include -#include +#include namespace O3DE::ProjectManager { - ProjectSettings::ProjectSettings(ProjectManagerWindow* window) - : ScreenWidget(window) + ProjectSettingsScreen::ProjectSettingsScreen(QWidget* parent) + : ScreenWidget(parent) , m_ui(new Ui::ProjectSettingsClass()) { m_ui->setupUi(this); - ConnectSlotsAndSignals(); + connect(m_ui->gemsButton, &QPushButton::pressed, this, &ProjectSettingsScreen::HandleGemsButton); } - ProjectSettings::~ProjectSettings() + ProjectManagerScreen ProjectSettingsScreen::GetScreenEnum() { + return ProjectManagerScreen::ProjectSettings; } - void ProjectSettings::ConnectSlotsAndSignals() + void ProjectSettingsScreen::HandleGemsButton() { - QObject::connect(m_ui->gemsButton, &QPushButton::pressed, this, &ProjectSettings::HandleGemsButton); - } - - void ProjectSettings::HandleGemsButton() - { - m_projectManagerWindow->ChangeToScreen(ProjectManagerScreen::GemCatalog); + emit ChangeScreenRequest(ProjectManagerScreen::GemCatalog); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectSettings.h b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h similarity index 82% rename from Code/Tools/ProjectManager/Source/ProjectSettings.h rename to Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h index e7781d3a2a..1ec1b46f44 100644 --- a/Code/Tools/ProjectManager/Source/ProjectSettings.h +++ b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h @@ -22,15 +22,13 @@ namespace Ui namespace O3DE::ProjectManager { - class ProjectSettings + class ProjectSettingsScreen : public ScreenWidget { public: - explicit ProjectSettings(ProjectManagerWindow* window); - ~ProjectSettings(); - - protected: - void ConnectSlotsAndSignals() override; + explicit ProjectSettingsScreen(QWidget* parent = nullptr); + ~ProjectSettingsScreen() = default; + ProjectManagerScreen GetScreenEnum() override; protected slots: void HandleGemsButton(); diff --git a/Code/Tools/ProjectManager/Source/ProjectSettings.ui b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.ui similarity index 100% rename from Code/Tools/ProjectManager/Source/ProjectSettings.ui rename to Code/Tools/ProjectManager/Source/ProjectSettingsScreen.ui diff --git a/Code/CryEngine/CrySystem/ZStdDecompressor.h b/Code/Tools/ProjectManager/Source/ProjectTemplateInfo.cpp similarity index 62% rename from Code/CryEngine/CrySystem/ZStdDecompressor.h rename to Code/Tools/ProjectManager/Source/ProjectTemplateInfo.cpp index 200e5fe350..32c3146510 100644 --- a/Code/CryEngine/CrySystem/ZStdDecompressor.h +++ b/Code/Tools/ProjectManager/Source/ProjectTemplateInfo.cpp @@ -10,19 +10,17 @@ * */ -#pragma once +#include "ProjectTemplateInfo.h" - -#include "IZStdDecompressor.h" - -class CZStdDecompressor - : public IZStdDecompressor +namespace O3DE::ProjectManager { -public: - bool DecompressData(const char* pIn, const uint inputSize, char* pOut, const uint outputSize) override; - void Release() override; - -protected: - ~CZStdDecompressor() override = default; -}; + ProjectTemplateInfo::ProjectTemplateInfo(const QString& path) + : m_path(path) + { + } + bool ProjectTemplateInfo::IsValid() const + { + return !m_path.isEmpty() && !m_name.isEmpty(); + } +} // namespace O3DE::ProjectManager diff --git a/Code/CryEngine/CrySystem/ZLibDecompressor.h b/Code/Tools/ProjectManager/Source/ProjectTemplateInfo.h similarity index 52% rename from Code/CryEngine/CrySystem/ZLibDecompressor.h rename to Code/Tools/ProjectManager/Source/ProjectTemplateInfo.h index 0a3ca0669f..0477968050 100644 --- a/Code/CryEngine/CrySystem/ZLibDecompressor.h +++ b/Code/Tools/ProjectManager/Source/ProjectTemplateInfo.h @@ -9,27 +9,29 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ -// Original file Copyright Crytek GMBH or its affiliates, used under license. -// Description : zlib inflate wrapper - - -#ifndef CRYINCLUDE_CRYSYSTEM_ZLIBDECOMPRESSOR_H -#define CRYINCLUDE_CRYSYSTEM_ZLIBDECOMPRESSOR_H #pragma once +#if !defined(Q_MOC_RUN) +#include +#include +#endif -#include "IZlibDecompressor.h" - -class CZLibDecompressor - : public IZLibDecompressor +namespace O3DE::ProjectManager { -public: - virtual IZLibInflateStream* CreateInflateStream(); - virtual void Release(); - -private: - virtual ~CZLibDecompressor() {} -}; - -#endif // CRYINCLUDE_CRYSYSTEM_ZLIBDECOMPRESSOR_H + class ProjectTemplateInfo + { + public: + ProjectTemplateInfo() = default; + ProjectTemplateInfo(const QString& path); + + bool IsValid() const; + + QString m_displayName; + QString m_name; + QString m_path; + QString m_summary; + QStringList m_canonicalTags; + QStringList m_userTags; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectsHome.cpp b/Code/Tools/ProjectManager/Source/ProjectsHome.cpp deleted file mode 100644 index a45b923946..0000000000 --- a/Code/Tools/ProjectManager/Source/ProjectsHome.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or - * its licensors. - * - * For complete copyright and license terms please see the LICENSE at the root of this - * distribution (the "License"). All use of this software is governed by the License, - * or, if provided, by the license below or the license accompanying this file. Do not - * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * - */ - -#include - -#include - -#include - -namespace O3DE::ProjectManager -{ - ProjectsHome::ProjectsHome(ProjectManagerWindow* window) - : ScreenWidget(window) - , m_ui(new Ui::ProjectsHomeClass()) - { - m_ui->setupUi(this); - - ConnectSlotsAndSignals(); - - // example of how to get the current project name - ProjectInfo currentProject = PythonBindingsInterface::Get()->GetCurrentProject(); - } - - ProjectsHome::~ProjectsHome() - { - } - - void ProjectsHome::ConnectSlotsAndSignals() - { - QObject::connect(m_ui->newProjectButton, &QPushButton::pressed, this, &ProjectsHome::HandleNewProjectButton); - QObject::connect(m_ui->addProjectButton, &QPushButton::pressed, this, &ProjectsHome::HandleAddProjectButton); - QObject::connect(m_ui->editProjectButton, &QPushButton::pressed, this, &ProjectsHome::HandleEditProjectButton); - } - - void ProjectsHome::HandleNewProjectButton() - { - m_projectManagerWindow->ChangeToScreen(ProjectManagerScreen::NewProjectSettings); - } - void ProjectsHome::HandleAddProjectButton() - { - //Do nothing for now - } - void ProjectsHome::HandleEditProjectButton() - { - m_projectManagerWindow->ChangeToScreen(ProjectManagerScreen::ProjectSettings); - } - -} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.cpp new file mode 100644 index 0000000000..539f79b017 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.cpp @@ -0,0 +1,51 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include + +#include + +#include + +namespace O3DE::ProjectManager +{ + ProjectsHomeScreen::ProjectsHomeScreen(QWidget* parent) + : ScreenWidget(parent) + , m_ui(new Ui::ProjectsHomeClass()) + { + m_ui->setupUi(this); + + connect(m_ui->newProjectButton, &QPushButton::pressed, this, &ProjectsHomeScreen::HandleNewProjectButton); + connect(m_ui->addProjectButton, &QPushButton::pressed, this, &ProjectsHomeScreen::HandleAddProjectButton); + connect(m_ui->editProjectButton, &QPushButton::pressed, this, &ProjectsHomeScreen::HandleEditProjectButton); + } + + ProjectManagerScreen ProjectsHomeScreen::GetScreenEnum() + { + return ProjectManagerScreen::ProjectsHome; + } + + void ProjectsHomeScreen::HandleNewProjectButton() + { + emit ResetScreenRequest(ProjectManagerScreen::NewProjectSettingsCore); + emit ChangeScreenRequest(ProjectManagerScreen::NewProjectSettingsCore); + } + void ProjectsHomeScreen::HandleAddProjectButton() + { + // Do nothing for now + } + void ProjectsHomeScreen::HandleEditProjectButton() + { + emit ChangeScreenRequest(ProjectManagerScreen::ProjectSettings); + } + +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectsHome.h b/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.h similarity index 83% rename from Code/Tools/ProjectManager/Source/ProjectsHome.h rename to Code/Tools/ProjectManager/Source/ProjectsHomeScreen.h index 4cc2918a38..9fd5919d2d 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsHome.h +++ b/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.h @@ -22,16 +22,14 @@ namespace Ui namespace O3DE::ProjectManager { - class ProjectsHome + class ProjectsHomeScreen : public ScreenWidget { public: - explicit ProjectsHome(ProjectManagerWindow* window); - ~ProjectsHome(); - - protected: - void ConnectSlotsAndSignals() override; + explicit ProjectsHomeScreen(QWidget* parent = nullptr); + ~ProjectsHomeScreen() = default; + ProjectManagerScreen GetScreenEnum() override; protected slots: void HandleNewProjectButton(); diff --git a/Code/Tools/ProjectManager/Source/ProjectsHome.ui b/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.ui similarity index 100% rename from Code/Tools/ProjectManager/Source/ProjectsHome.ui rename to Code/Tools/ProjectManager/Source/ProjectsHomeScreen.ui diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index cc14e9e4de..b6945e012e 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -12,12 +12,11 @@ #include + // Qt defines slots, which interferes with the use here. #pragma push_macro("slots") #undef slots -#include #include -#include #include #include #pragma pop_macro("slots") @@ -51,6 +50,9 @@ namespace Platform } // namespace Platform +#define Py_To_String(obj) obj.cast().c_str() +#define Py_To_String_Optional(dict, key, default_string) dict.contains(key) ? Py_To_String(dict[key]) : default_string + namespace O3DE::ProjectManager { PythonBindings::PythonBindings(const AZ::IO::PathView& enginePath) @@ -109,10 +111,13 @@ namespace O3DE::ProjectManager result = PyRun_SimpleString(AZStd::string::format("sys.path.append('%s')", m_enginePath.c_str()).c_str()); AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed"); + // import required modules + m_registration = pybind11::module::import("cmake.Tools.registration"); + return result == 0 && !PyErr_Occurred(); } catch ([[maybe_unused]] const std::exception& e) { - AZ_Warning("python", false, "Py_Initialize() failed with %s", e.what()); + AZ_Warning("ProjectManagerWindow", false, "Py_Initialize() failed with %s", e.what()); return false; } } @@ -125,31 +130,256 @@ namespace O3DE::ProjectManager } else { - AZ_Warning("python", false, "Did not finalize since Py_IsInitialized() was false"); + AZ_Warning("ProjectManagerWindow", false, "Did not finalize since Py_IsInitialized() was false"); } return !PyErr_Occurred(); } - void PythonBindings::ExecuteWithLock(AZStd::function executionCallback) + bool PythonBindings::ExecuteWithLock(AZStd::function executionCallback) { AZStd::lock_guard lock(m_lock); pybind11::gil_scoped_release release; pybind11::gil_scoped_acquire acquire; - executionCallback(); + + try + { + executionCallback(); + return true; + } + catch ([[maybe_unused]] const std::exception& e) + { + AZ_Warning("PythonBindings", false, "Python exception %s", e.what()); + return false; + } + } + + AZ::Outcome PythonBindings::GetEngineInfo() + { + return AZ::Failure(); + } + + bool PythonBindings::SetEngineInfo([[maybe_unused]] const EngineInfo& engineInfo) + { + return false; + } + + AZ::Outcome PythonBindings::GetGem(const QString& path) + { + GemInfo gemInfo = GemInfoFromPath(pybind11::str(path.toStdString())); + if (gemInfo.IsValid()) + { + return AZ::Success(AZStd::move(gemInfo)); + } + else + { + return AZ::Failure(); + } + } + + AZ::Outcome> PythonBindings::GetGems() + { + QVector gems; + + bool result = ExecuteWithLock([&] { + // external gems + for (auto path : m_registration.attr("get_gems")()) + { + gems.push_back(GemInfoFromPath(path)); + } + + // gems from the engine + for (auto path : m_registration.attr("get_engine_gems")()) + { + gems.push_back(GemInfoFromPath(path)); + } + }); + + if (!result) + { + return AZ::Failure(); + } + else + { + return AZ::Success(AZStd::move(gems)); + } + } + + AZ::Outcome PythonBindings::CreateProject([[maybe_unused]] const ProjectTemplateInfo& projectTemplate,[[maybe_unused]] const ProjectInfo& projectInfo) + { + return AZ::Failure(); + } + + AZ::Outcome PythonBindings::GetProject(const QString& path) + { + ProjectInfo projectInfo = ProjectInfoFromPath(pybind11::str(path.toStdString())); + if (projectInfo.IsValid()) + { + return AZ::Success(AZStd::move(projectInfo)); + } + else + { + return AZ::Failure(); + } + } + + GemInfo PythonBindings::GemInfoFromPath(pybind11::handle path) + { + GemInfo gemInfo; + gemInfo.m_path = Py_To_String(path); + + auto data = m_registration.attr("get_gem_data")(pybind11::none(), path); + if (pybind11::isinstance(data)) + { + try + { + // required + gemInfo.m_name = Py_To_String(data["Name"]); + gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"])); + + // optional + gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name); + gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); + gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); + + if (data.contains("Dependencies")) + { + for (auto dependency : data["Dependencies"]) + { + gemInfo.m_dependingGemUuids.push_back(Py_To_String(dependency["Uuid"])); + } + } + if (data.contains("Tags")) + { + for (auto tag : data["Tags"]) + { + gemInfo.m_features.push_back(Py_To_String(tag)); + } + } + } + catch ([[maybe_unused]] const std::exception& e) + { + AZ_Warning("PythonBindings", false, "Failed to get GemInfo for gem %s", Py_To_String(path)); + } + } + + return gemInfo; + } + + ProjectInfo PythonBindings::ProjectInfoFromPath(pybind11::handle path) + { + ProjectInfo projectInfo; + projectInfo.m_path = Py_To_String(path); + + auto projectData = m_registration.attr("get_project_data")(pybind11::none(), path); + if (pybind11::isinstance(projectData)) + { + try + { + // required fields + projectInfo.m_productName = Py_To_String(projectData["product_name"]); + projectInfo.m_projectName = Py_To_String(projectData["project_name"]); + projectInfo.m_projectId = AZ::Uuid(Py_To_String(projectData["project_id"])); + } + catch ([[maybe_unused]] const std::exception& e) + { + AZ_Warning("PythonBindings", false, "Failed to get ProjectInfo for project %s", Py_To_String(path)); + } + } + + return projectInfo; + } + + AZ::Outcome> PythonBindings::GetProjects() + { + QVector projects; + + bool result = ExecuteWithLock([&] { + // external projects + for (auto path : m_registration.attr("get_projects")()) + { + projects.push_back(ProjectInfoFromPath(path)); + } + + // projects from the engine + for (auto path : m_registration.attr("get_engine_projects")()) + { + projects.push_back(ProjectInfoFromPath(path)); + } + }); + + if (!result) + { + return AZ::Failure(); + } + else + { + return AZ::Success(AZStd::move(projects)); + } } - ProjectInfo PythonBindings::GetCurrentProject() + bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo) { - ProjectInfo project; + return false; + } - ExecuteWithLock([&] { - auto currentProjectTool = pybind11::module::import("cmake.Tools.current_project"); - auto getCurrentProject = currentProjectTool.attr("get_current_project"); - auto currentProject = getCurrentProject(m_enginePath.c_str()); + ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path) + { + ProjectTemplateInfo templateInfo; + templateInfo.m_path = Py_To_String(path); - project.m_path = currentProject.cast().c_str(); + auto data = m_registration.attr("get_template_data")(pybind11::none(), path); + if (pybind11::isinstance(data)) + { + try + { + // required + templateInfo.m_displayName = Py_To_String(data["display_name"]); + templateInfo.m_name = Py_To_String(data["template_name"]); + templateInfo.m_summary = Py_To_String(data["summary"]); + + // optional + if (data.contains("canonical_tags")) + { + for (auto tag : data["canonical_tags"]) + { + templateInfo.m_canonicalTags.push_back(Py_To_String(tag)); + } + } + if (data.contains("user_tags")) + { + for (auto tag : data["user_tags"]) + { + templateInfo.m_canonicalTags.push_back(Py_To_String(tag)); + } + } + } + catch ([[maybe_unused]] const std::exception& e) + { + AZ_Warning("PythonBindings", false, "Failed to get ProjectTemplateInfo for %s", Py_To_String(path)); + } + } + + return templateInfo; + } + + AZ::Outcome> PythonBindings::GetProjectTemplates() + { + QVector templates; + + bool result = ExecuteWithLock([&] { + for (auto path : m_registration.attr("get_project_templates")()) + { + templates.push_back(ProjectTemplateInfoFromPath(path)); + } }); - return project; + if (!result) + { + return AZ::Failure(); + } + else + { + return AZ::Success(AZStd::move(templates)); + } } } diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index ac55fffe80..9183ca2424 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -15,6 +15,14 @@ #include #include +// Qt defines slots, which interferes with the use here. +#pragma push_macro("slots") +#undef slots +#include +#include +#pragma pop_macro("slots") + + namespace O3DE::ProjectManager { class PythonBindings @@ -26,16 +34,35 @@ namespace O3DE::ProjectManager ~PythonBindings() override; // PythonBindings overrides - ProjectInfo GetCurrentProject() override; + // Engine + AZ::Outcome GetEngineInfo() override; + bool SetEngineInfo(const EngineInfo& engineInfo) override; + + // Gem + AZ::Outcome GetGem(const QString& path) override; + AZ::Outcome> GetGems() override; + + // Project + AZ::Outcome CreateProject(const ProjectTemplateInfo& projectTemplate, const ProjectInfo& projectInfo) override; + AZ::Outcome GetProject(const QString& path) override; + AZ::Outcome> GetProjects() override; + bool UpdateProject(const ProjectInfo& projectInfo) override; + + // ProjectTemplate + AZ::Outcome> GetProjectTemplates() override; private: AZ_DISABLE_COPY_MOVE(PythonBindings); - void ExecuteWithLock(AZStd::function executionCallback); + bool ExecuteWithLock(AZStd::function executionCallback); + GemInfo GemInfoFromPath(pybind11::handle path); + ProjectInfo ProjectInfoFromPath(pybind11::handle path); + ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path); bool StartPython(); bool StopPython(); AZ::IO::FixedMaxPath m_enginePath; AZStd::recursive_mutex m_lock; + pybind11::handle m_registration; }; } diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index 78c3625415..f696ea958d 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -15,9 +15,12 @@ #include #include #include +#include +#include #include #include +#include namespace O3DE::ProjectManager { @@ -31,8 +34,76 @@ namespace O3DE::ProjectManager IPythonBindings() = default; virtual ~IPythonBindings() = default; - //! Get the current project - virtual ProjectInfo GetCurrentProject() = 0; + + // Engine + + /** + * Get info about the engine + * @return an outcome with EngineInfo on success + */ + virtual AZ::Outcome GetEngineInfo() = 0; + + /** + * Set info about the engine + * @param engineInfo an EngineInfo object + */ + virtual bool SetEngineInfo(const EngineInfo& engineInfo) = 0; + + + // Gems + + /** + * Get info about a Gem + * @param path the absolute path to the Gem + * @return an outcome with GemInfo on success + */ + virtual AZ::Outcome GetGem(const QString& path) = 0; + + /** + * Get info about all known Gems + * @return an outcome with GemInfos on success + */ + virtual AZ::Outcome> GetGems() = 0; + + + // Projects + + /** + * Create a project + * @param projectTemplate the project template to use + * @param projectInfo the project info to use + * @return an outcome with ProjectInfo on success + */ + virtual AZ::Outcome CreateProject(const ProjectTemplateInfo& projectTemplate, const ProjectInfo& projectInfo) = 0; + + /** + * Get info about a project + * @param path the absolute path to the project + * @return an outcome with ProjectInfo on success + */ + virtual AZ::Outcome GetProject(const QString& path) = 0; + + /** + * Get info about all known projects + * @return an outcome with ProjectInfos on success + */ + virtual AZ::Outcome> GetProjects() = 0; + + /** + * Update a project + * @param projectInfo the info to use to update the project + * @return true on success, false on failure + */ + virtual bool UpdateProject(const ProjectInfo& projectInfo) = 0; + + + // Project Templates + + /** + * Get info about all known project templates + * @return an outcome with ProjectTemplateInfos on success + */ + virtual AZ::Outcome> GetProjectTemplates() = 0; }; using PythonBindingsInterface = AZ::Interface; diff --git a/Code/Tools/ProjectManager/Source/ScreenDefs.h b/Code/Tools/ProjectManager/Source/ScreenDefs.h index f02b1de1b8..658b8d88fd 100644 --- a/Code/Tools/ProjectManager/Source/ScreenDefs.h +++ b/Code/Tools/ProjectManager/Source/ScreenDefs.h @@ -13,9 +13,12 @@ namespace O3DE::ProjectManager { - enum class ProjectManagerScreen + enum ProjectManagerScreen { + Invalid = -1, + Empty, FirstTimeUse, + NewProjectSettingsCore, NewProjectSettings, GemCatalog, ProjectsHome, diff --git a/Code/Tools/ProjectManager/Source/ScreenFactory.cpp b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp index 9250b71ccd..1089f8ee94 100644 --- a/Code/Tools/ProjectManager/Source/ScreenFactory.cpp +++ b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp @@ -11,33 +11,48 @@ */ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace O3DE::ProjectManager { - QWidget* BuildScreen(ProjectManagerWindow* window, ProjectManagerScreen screen) + ScreenWidget* BuildScreen(QWidget* parent, ProjectManagerScreen screen) { + ScreenWidget* newScreen; + switch(screen) { case (ProjectManagerScreen::FirstTimeUse): - return new FirstTimeUse(window); + newScreen = new FirstTimeUseScreen(parent); + break; + case (ProjectManagerScreen::NewProjectSettingsCore): + newScreen = new ProjectSettingsCtrl(parent); + break; case (ProjectManagerScreen::NewProjectSettings): - return new NewProjectSettings(window); + newScreen = new NewProjectSettingsScreen(parent); + break; case (ProjectManagerScreen::GemCatalog): - return new GemCatalog(window); + newScreen = new GemCatalogScreen(parent); + break; case (ProjectManagerScreen::ProjectsHome): - return new ProjectsHome(window); + newScreen = new ProjectsHomeScreen(parent); + break; case (ProjectManagerScreen::ProjectSettings): - return new ProjectSettings(window); + newScreen = new ProjectSettingsScreen(parent); + break; case (ProjectManagerScreen::EngineSettings): - return new EngineSettings(window); + newScreen = new EngineSettingsScreen(parent); + break; + case (ProjectManagerScreen::Empty): default: - return new QWidget(window->GetScreenStack()); + newScreen = new ScreenWidget(parent); } + + return newScreen; } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ScreenFactory.h b/Code/Tools/ProjectManager/Source/ScreenFactory.h index ea68534a08..ad03be19c5 100644 --- a/Code/Tools/ProjectManager/Source/ScreenFactory.h +++ b/Code/Tools/ProjectManager/Source/ScreenFactory.h @@ -13,12 +13,11 @@ #include -#include - #include - namespace O3DE::ProjectManager { - QWidget* BuildScreen(ProjectManagerWindow* window, ProjectManagerScreen screen); + class ScreenWidget; + + ScreenWidget* BuildScreen(QWidget* parent = nullptr, ProjectManagerScreen screen = ProjectManagerScreen::Empty); } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ScreenWidget.h b/Code/Tools/ProjectManager/Source/ScreenWidget.h index ddf4add65b..ae235daf2b 100644 --- a/Code/Tools/ProjectManager/Source/ScreenWidget.h +++ b/Code/Tools/ProjectManager/Source/ScreenWidget.h @@ -12,7 +12,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include #include #endif @@ -22,17 +22,32 @@ namespace O3DE::ProjectManager class ScreenWidget : public QWidget { + Q_OBJECT + public: - explicit ScreenWidget(ProjectManagerWindow* window) - : QWidget(window->GetScreenStack()) - , m_projectManagerWindow(window) + explicit ScreenWidget(QWidget* parent = nullptr) + : QWidget(parent) { } + ~ScreenWidget() = default; - protected: - virtual void ConnectSlotsAndSignals() {} + virtual ProjectManagerScreen GetScreenEnum() + { + return ProjectManagerScreen::Empty; + } + virtual bool IsReadyForNextScreen() + { + return true; + } + virtual QString GetNextButtonText() + { + return "Next"; + } - ProjectManagerWindow* m_projectManagerWindow; + signals: + void ChangeScreenRequest(ProjectManagerScreen screen); + void GotoPreviousScreenRequest(); + void ResetScreenRequest(ProjectManagerScreen screen); }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp new file mode 100644 index 0000000000..69af09f496 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp @@ -0,0 +1,149 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include + +#include + +namespace O3DE::ProjectManager +{ + ScreensCtrl::ScreensCtrl(QWidget* parent) + : QWidget(parent) + { + QVBoxLayout* vLayout = new QVBoxLayout(); + setLayout(vLayout); + + m_screenStack = new QStackedWidget(); + vLayout->addWidget(m_screenStack); + + //Track the bottom of the stack + m_screenVisitOrder.push(ProjectManagerScreen::Invalid); + } + + void ScreensCtrl::BuildScreens(QVector screens) + { + for (ProjectManagerScreen screen : screens) + { + ResetScreen(screen); + } + } + + ScreenWidget* ScreensCtrl::FindScreen(ProjectManagerScreen screen) + { + const auto iterator = m_screenMap.find(screen); + if (iterator != m_screenMap.end()) + { + return iterator.value(); + } + else + { + return nullptr; + } + } + + ScreenWidget* ScreensCtrl::GetCurrentScreen() + { + return reinterpret_cast(m_screenStack->currentWidget()); + } + + bool ScreensCtrl::ChangeToScreen(ProjectManagerScreen screen) + { + if (m_screenStack->currentWidget()) + { + ScreenWidget* currentScreenWidget = GetCurrentScreen(); + if (currentScreenWidget->IsReadyForNextScreen()) + { + return ForceChangeToScreen(screen); + } + } + return false; + } + + bool ScreensCtrl::ForceChangeToScreen(ProjectManagerScreen screen, bool addVisit) + { + const auto iterator = m_screenMap.find(screen); + if (iterator != m_screenMap.end()) + { + ScreenWidget* currentScreen = GetCurrentScreen(); + if (currentScreen != iterator.value()) + { + if (addVisit) + { + m_screenVisitOrder.push(currentScreen->GetScreenEnum()); + } + m_screenStack->setCurrentWidget(iterator.value()); + return true; + } + } + + return false; + } + + bool ScreensCtrl::GotoPreviousScreen() + { + // Don't go back if we are on the first set screen + if (m_screenVisitOrder.top() != ProjectManagerScreen::Invalid) + { + // We do not check with screen if we can go back, we should always be able to go back + return ForceChangeToScreen(m_screenVisitOrder.pop(), false); + } + return false; + } + + void ScreensCtrl::ResetScreen(ProjectManagerScreen screen) + { + // Delete old screen if it exists to start fresh + DeleteScreen(screen); + + // Add new screen + ScreenWidget* newScreen = BuildScreen(this, screen); + m_screenStack->addWidget(newScreen); + m_screenMap.insert(screen, newScreen); + + connect(newScreen, &ScreenWidget::ChangeScreenRequest, this, &ScreensCtrl::ChangeToScreen); + connect(newScreen, &ScreenWidget::GotoPreviousScreenRequest, this, &ScreensCtrl::GotoPreviousScreen); + connect(newScreen, &ScreenWidget::ResetScreenRequest, this, &ScreensCtrl::ResetScreen); + } + + void ScreensCtrl::ResetAllScreens() + { + for (auto iter = m_screenMap.begin(); iter != m_screenMap.end(); ++iter) + { + ResetScreen(iter.key()); + } + } + + void ScreensCtrl::DeleteScreen(ProjectManagerScreen screen) + { + // Find the old screen if it exists and get rid of it + const auto iter = m_screenMap.find(screen); + if (iter != m_screenMap.end()) + { + m_screenStack->removeWidget(iter.value()); + iter.value()->deleteLater(); + + // Erase does not cause a rehash so interators remain valid + m_screenMap.erase(iter); + } + } + + void ScreensCtrl::DeleteAllScreens() + { + for (auto iter = m_screenMap.begin(); iter != m_screenMap.end(); ++iter) + { + DeleteScreen(iter.key()); + } + } + +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ScreensCtrl.h b/Code/Tools/ProjectManager/Source/ScreensCtrl.h new file mode 100644 index 0000000000..7912a314e3 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ScreensCtrl.h @@ -0,0 +1,53 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ +#pragma once + +#if !defined(Q_MOC_RUN) +#include + +#include +#include +#endif + +namespace O3DE::ProjectManager +{ + class ScreenWidget; + + class ScreensCtrl + : public QWidget + { + Q_OBJECT + + public: + explicit ScreensCtrl(QWidget* parent = nullptr); + ~ScreensCtrl() = default; + + void BuildScreens(QVector screens); + ScreenWidget* FindScreen(ProjectManagerScreen screen); + ScreenWidget* GetCurrentScreen(); + + public slots: + bool ChangeToScreen(ProjectManagerScreen screen); + bool ForceChangeToScreen(ProjectManagerScreen screen, bool addVisit = true); + bool GotoPreviousScreen(); + void ResetScreen(ProjectManagerScreen screen); + void ResetAllScreens(); + void DeleteScreen(ProjectManagerScreen screen); + void DeleteAllScreens(); + + private: + QStackedWidget* m_screenStack; + QHash m_screenMap; + QStack m_screenVisitOrder; + }; + +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index da0b7cdec7..9ffdb6029d 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -15,38 +15,47 @@ set(FILES Source/ScreenDefs.h Source/ScreenFactory.h Source/ScreenFactory.cpp + Source/ScreensCtrl.h + Source/ScreensCtrl.cpp Source/ScreenWidget.h - Source/FirstTimeUse.h - Source/FirstTimeUse.cpp - Source/FirstTimeUse.ui - Source/ProjectInfo.h - Source/ProjectInfo.cpp + Source/EngineInfo.h + Source/EngineInfo.cpp + Source/FirstTimeUseScreen.h + Source/FirstTimeUseScreen.cpp + Source/FirstTimeUseScreen.ui Source/ProjectManagerWindow.h Source/ProjectManagerWindow.cpp + Source/ProjectTemplateInfo.h + Source/ProjectTemplateInfo.cpp Source/ProjectManagerWindow.ui Source/PythonBindings.h Source/PythonBindings.cpp Source/PythonBindingsInterface.h - Source/NewProjectSettings.h - Source/NewProjectSettings.cpp - Source/NewProjectSettings.ui - Source/ProjectsHome.h - Source/ProjectsHome.cpp - Source/ProjectsHome.ui - Source/ProjectSettings.h - Source/ProjectSettings.cpp - Source/ProjectSettings.ui - Source/EngineSettings.h - Source/EngineSettings.cpp - Source/EngineSettings.ui + Source/ProjectInfo.h + Source/ProjectInfo.cpp + Source/NewProjectSettingsScreen.h + Source/NewProjectSettingsScreen.cpp + Source/ProjectSettingsCtrl.h + Source/ProjectSettingsCtrl.cpp + Source/ProjectsHomeScreen.h + Source/ProjectsHomeScreen.cpp + Source/ProjectsHomeScreen.ui + Source/ProjectSettingsScreen.h + Source/ProjectSettingsScreen.cpp + Source/ProjectSettingsScreen.ui + Source/EngineSettingsScreen.h + Source/EngineSettingsScreen.cpp + Source/EngineSettingsScreen.ui Source/LinkWidget.h Source/LinkWidget.cpp Source/TagWidget.h Source/TagWidget.cpp - Source/GemCatalog/GemCatalog.h - Source/GemCatalog/GemCatalog.cpp + Source/GemCatalog/GemCatalogScreen.h + Source/GemCatalog/GemCatalogScreen.cpp Source/GemCatalog/GemInfo.h Source/GemCatalog/GemInfo.cpp + Source/GemCatalog/GemInspector.h + Source/GemCatalog/GemInspector.cpp Source/GemCatalog/GemItemDelegate.h Source/GemCatalog/GemItemDelegate.cpp Source/GemCatalog/GemListView.h diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImporter.cpp index c7f7b4ad79..4242033f8b 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImporter.cpp @@ -139,6 +139,8 @@ namespace AZ if (!nodeNameMap.RegisterNode(node.m_node, scene.GetGraph(), node.m_parent)) { AZ_TracePrintf(Utilities::ErrorWindow, "Failed to register asset importer node in name table."); + // Skip this node since it could not be registered + nodes.pop(); continue; } AZStd::string nodeName = nodeNameMap.GetNodeName(node.m_node); diff --git a/Code/Tools/SerializeContextTools/Converter.cpp b/Code/Tools/SerializeContextTools/Converter.cpp index b15bb4fa8e..0b19d4e981 100644 --- a/Code/Tools/SerializeContextTools/Converter.cpp +++ b/Code/Tools/SerializeContextTools/Converter.cpp @@ -117,7 +117,7 @@ namespace AZ } return true; }; - if (!Utilities::InspectSerializedFile(filePath, convertSettings.m_serializeContext, callback)) + if (!Utilities::InspectSerializedFile(filePath.c_str(), convertSettings.m_serializeContext, callback)) { AZ_Warning("Convert", false, "Failed to load '%s'. File may not contain an object stream.", filePath.c_str()); result = false; @@ -287,7 +287,7 @@ namespace AZ } return true; }; - if (!Utilities::InspectSerializedFile(filePath, convertSettings.m_serializeContext, callback)) + if (!Utilities::InspectSerializedFile(filePath.c_str(), convertSettings.m_serializeContext, callback)) { AZ_Warning("Convert", false, "Failed to load '%s'. File may not contain an object stream.", filePath.c_str()); result = false; diff --git a/Code/Tools/SerializeContextTools/Converter.h b/Code/Tools/SerializeContextTools/Converter.h index 18f30cc562..c6338b8d29 100644 --- a/Code/Tools/SerializeContextTools/Converter.h +++ b/Code/Tools/SerializeContextTools/Converter.h @@ -42,7 +42,7 @@ namespace AZ //! Can be used to convert *.ini and *.cfg files static bool ConvertConfigFile(Application& application); - private: + protected: using PathDocumentPair = AZStd::pair; using PathDocumentContainer = AZStd::vector; diff --git a/Code/Tools/SerializeContextTools/Dumper.cpp b/Code/Tools/SerializeContextTools/Dumper.cpp index 55c9581602..590ee65571 100644 --- a/Code/Tools/SerializeContextTools/Dumper.cpp +++ b/Code/Tools/SerializeContextTools/Dumper.cpp @@ -85,7 +85,7 @@ namespace AZ::SerializeContextTools result = false; } }; - if (!Utilities::InspectSerializedFile(filePath, sc, callback)) + if (!Utilities::InspectSerializedFile(filePath.c_str(), sc, callback)) { result = false; continue; diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp new file mode 100644 index 0000000000..2df3888607 --- /dev/null +++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp @@ -0,0 +1,263 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// SliceConverter reads in a slice file (saved in an ObjectStream format), instantiates it, creates a prefab out of the data, +// and saves the prefab in a JSON format. This can be used for one-time migrations of slices or slice-based levels to prefabs. +// This converter is still in an early state. It can convert trivial slices, but it cannot handle nested slices yet. +// +// If the slice contains legacy data, it will print out warnings / errors about the data that couldn't be serialized. +// The prefab will be generated without that data. + +namespace AZ +{ + namespace SerializeContextTools + { + bool SliceConverter::ConvertSliceFiles(Application& application) + { + using namespace AZ::JsonSerializationResult; + + const AZ::CommandLine* commandLine = application.GetAzCommandLine(); + if (!commandLine) + { + AZ_Error("SerializeContextTools", false, "Command line not available."); + return false; + } + + JsonSerializerSettings convertSettings; + convertSettings.m_keepDefaults = commandLine->HasSwitch("keepdefaults"); + convertSettings.m_registrationContext = application.GetJsonRegistrationContext(); + convertSettings.m_serializeContext = application.GetSerializeContext(); + if (!convertSettings.m_serializeContext) + { + AZ_Error("Convert-Slice", false, "No serialize context found."); + return false; + } + if (!convertSettings.m_registrationContext) + { + AZ_Error("Convert-Slice", false, "No json registration context found."); + return false; + } + AZStd::string logggingScratchBuffer; + SetupLogging(logggingScratchBuffer, convertSettings.m_reporting, *commandLine); + + bool isDryRun = commandLine->HasSwitch("dryrun"); + + JsonDeserializerSettings verifySettings; + verifySettings.m_registrationContext = application.GetJsonRegistrationContext(); + verifySettings.m_serializeContext = application.GetSerializeContext(); + SetupLogging(logggingScratchBuffer, verifySettings.m_reporting, *commandLine); + + auto archiveInterface = AZ::Interface::Get(); + + // Find the Prefab System Component for use in creating and saving the prefab + AZ::Entity* systemEntity = application.FindEntity(AZ::SystemEntityId); + AZ_Assert(systemEntity != nullptr, "System entity doesn't exist."); + auto prefabSystemComponent = systemEntity->FindComponent(); + AZ_Assert(prefabSystemComponent != nullptr, "Prefab System component doesn't exist"); + + bool result = true; + rapidjson::StringBuffer scratchBuffer; + + AZStd::vector fileList = Utilities::ReadFileListFromCommandLine(application, "files"); + for (AZStd::string& filePath : fileList) + { + bool packOpened = false; + + AZ::IO::Path outputPath = filePath; + outputPath.ReplaceExtension("prefab"); + + AZ_Printf("Convert-Slice", "------------------------------------------------------------------------------------------\n"); + AZ_Printf("Convert-Slice", "Converting '%s' to '%s'\n", filePath.c_str(), outputPath.c_str()); + + AZ::IO::Path inputPath = filePath; + auto fileExtension = inputPath.Extension(); + if (fileExtension == ".ly") + { + // Special case: for level files, we need to open the .ly zip file and convert the levelentities.editor_xml file + // inside of it. All the other files can be ignored as they are deprecated legacy system files that are no longer + // loaded with prefab-based levels. + packOpened = archiveInterface->OpenPack(filePath); + inputPath.ReplaceFilename("levelentities.editor_xml"); + AZ_Warning("Convert-Slice", packOpened, " '%s' could not be opened as a pack file.\n", filePath.c_str()); + } + else + { + AZ_Warning( + "Convert-Slice", (fileExtension == ".slice"), + " Warning: Only .ly and .slice files are supported, conversion of '%.*s' may not work.\n", + AZ_STRING_ARG(fileExtension.Native())); + } + + auto callback = [prefabSystemComponent, &outputPath, isDryRun] + (void* classPtr, const Uuid& classId, [[maybe_unused]] SerializeContext* context) + { + if (classId != azrtti_typeid()) + { + AZ_Printf("Convert-Slice", " File not converted: Slice root is not an entity.\n"); + return false; + } + + AZ::Entity* rootEntity = reinterpret_cast(classPtr); + return ConvertSliceFile(prefabSystemComponent, outputPath, isDryRun, rootEntity); + }; + + if (!Utilities::InspectSerializedFile(inputPath.c_str(), convertSettings.m_serializeContext, callback)) + { + AZ_Warning("Convert-Slice", false, "Failed to load '%s'. File may not contain an object stream.", inputPath.c_str()); + result = false; + } + + if (packOpened) + { + [[maybe_unused]] bool closeResult = archiveInterface->ClosePack(filePath); + AZ_Warning("Convert-Slice", !closeResult, "Failed to close '%s'.", filePath.c_str()); + } + + AZ_Printf("Convert-Slice", "Finished converting '%s' to '%s'\n", filePath.c_str(), outputPath.c_str()); + AZ_Printf("Convert-Slice", "------------------------------------------------------------------------------------------\n"); + } + + return result; + } + + bool SliceConverter::ConvertSliceFile( + AzToolsFramework::Prefab::PrefabSystemComponent* prefabSystemComponent, AZ::IO::PathView outputPath, bool isDryRun, + AZ::Entity* rootEntity) + { + // Find the slice from the root entity. + SliceComponent* sliceComponent = AZ::EntityUtils::FindFirstDerivedComponent(rootEntity); + if (sliceComponent == nullptr) + { + AZ_Printf("Convert-Slice", " File not converted: Root entity did not contain a slice component.\n"); + return false; + } + + // Get all of the entities from the slice. + SliceComponent::EntityList sliceEntities; + bool getEntitiesResult = sliceComponent->GetEntities(sliceEntities); + if ((!getEntitiesResult) || (sliceEntities.empty())) + { + AZ_Printf("Convert-Slice", " File not converted: Slice entities could not be retrieved.\n"); + return false; + } + + // Create the Prefab with the entities from the slice + AZStd::unique_ptr sourceInstance( + prefabSystemComponent->CreatePrefab(sliceEntities, {}, outputPath)); + + // Dispatch events here, because prefab creation might trigger asset loads in rare circumstances. + AZ::Data::AssetManager::Instance().DispatchEvents(); + + // Set up the Prefab container entity to be a proper Editor entity. (This logic is normally triggered + // via an EditorRequests EBus in CreatePrefab, but the subsystem that listens for it isn't present in this tool.) + AzToolsFramework::Prefab::EntityOptionalReference container = sourceInstance->GetContainerEntity(); + AzToolsFramework::EditorEntityContextRequestBus::Broadcast( + &AzToolsFramework::EditorEntityContextRequestBus::Events::AddRequiredComponents, container->get()); + container->get().AddComponent(aznew AzToolsFramework::Prefab::EditorPrefabComponent()); + + // Reparent any root-level slice entities to the container entity. + for (auto entity : sliceEntities) + { + AzToolsFramework::Components::TransformComponent* transformComponent = + entity->FindComponent(); + if (transformComponent) + { + if (!transformComponent->GetParentId().IsValid()) + { + transformComponent->SetParent(container->get().GetId()); + } + } + } + + auto templateId = sourceInstance->GetTemplateId(); + + if (templateId == AzToolsFramework::Prefab::InvalidTemplateId) + { + AZ_Printf("Convert-Slice", " Path error. Path could be invalid, or the prefab may not be loaded in this level.\n"); + return false; + } + + // Update the prefab template with the fixed-up data in our prefab instance. + AzToolsFramework::Prefab::PrefabDom prefabDom; + bool storeResult = AzToolsFramework::Prefab::PrefabDomUtils::StoreInstanceInPrefabDom(*sourceInstance, prefabDom); + if (storeResult == false) + { + AZ_Printf("Convert-Slice", " Failed to convert prefab instance data to a PrefabDom.\n"); + return false; + } + prefabSystemComponent->UpdatePrefabTemplate(templateId, prefabDom); + + // Dispatch events here, because prefab serialization might trigger asset loads in rare circumstances. + AZ::Data::AssetManager::Instance().DispatchEvents(); + + if (isDryRun) + { + PrintPrefab(prefabDom, sourceInstance->GetTemplateSourcePath()); + return true; + } + else + { + return SavePrefab(templateId); + } + } + + void SliceConverter::PrintPrefab(const AzToolsFramework::Prefab::PrefabDom& prefabDom, const AZ::IO::Path& templatePath) + { + rapidjson::StringBuffer prefabBuffer; + rapidjson::PrettyWriter writer(prefabBuffer); + prefabDom.Accept(writer); + AZ_Printf("Convert-Slice", "JSON for %s:\n", templatePath.c_str()); + + // We use Output() to print out the JSON because AZ_Printf has a 4096-character limit. + AZ::Debug::Trace::Instance().Output("", prefabBuffer.GetString()); + AZ::Debug::Trace::Instance().Output("", "\n"); + } + + bool SliceConverter::SavePrefab(AzToolsFramework::Prefab::TemplateId templateId) + { + auto prefabLoaderInterface = AZ::Interface::Get(); + + if (!prefabLoaderInterface->SaveTemplate(templateId)) + { + AZ_Printf("Convert-Slice", " Could not save prefab - internal error (Json write operation failure).\n"); + return false; + } + + return true; + } + + } // namespace SerializeContextTools +} // namespace AZ diff --git a/Code/Tools/SerializeContextTools/SliceConverter.h b/Code/Tools/SerializeContextTools/SliceConverter.h new file mode 100644 index 0000000000..90dfa0d50a --- /dev/null +++ b/Code/Tools/SerializeContextTools/SliceConverter.h @@ -0,0 +1,53 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace AZ +{ + class CommandLine; + class Entity; + class ModuleEntity; + class SerializeContext; + struct Uuid; + + namespace SerializeContextTools + { + class Application; + + class SliceConverter : public Converter + { + public: + static bool ConvertSliceFiles(Application& application); + + private: + + static bool ConvertSliceFile(AzToolsFramework::Prefab::PrefabSystemComponent* prefabSystemComponent, + AZ::IO::PathView outputPath, bool isDryRun, AZ::Entity* rootEntity); + + static void PrintPrefab(const AzToolsFramework::Prefab::PrefabDom& prefabDom, const AZ::IO::Path& templatePath); + static bool SavePrefab(AzToolsFramework::Prefab::TemplateId templateId); + }; + } // namespace SerializeContextTools +} // namespace AZ diff --git a/Code/Tools/SerializeContextTools/Utilities.cpp b/Code/Tools/SerializeContextTools/Utilities.cpp index 1c50466443..cfd75a44e7 100644 --- a/Code/Tools/SerializeContextTools/Utilities.cpp +++ b/Code/Tools/SerializeContextTools/Utilities.cpp @@ -209,30 +209,42 @@ namespace AZ::SerializeContextTools return result; } - bool Utilities::InspectSerializedFile(const AZStd::string& filePath, SerializeContext* sc, const ObjectStream::ClassReadyCB& classCallback) + bool Utilities::InspectSerializedFile(const char* filePath, SerializeContext* sc, const ObjectStream::ClassReadyCB& classCallback) { - if (!AZ::IO::SystemFile::Exists(filePath.c_str())) + if (!AZ::IO::FileIOBase::GetInstance()->Exists(filePath)) { - AZ_Error("Verify", false, "Unable to open file '%s' as it doesn't exist.", filePath.c_str()); + AZ_Error("Verify", false, "Unable to open file '%s' as it doesn't exist.", filePath); return false; } - u64 fileLength = AZ::IO::SystemFile::Length(filePath.c_str()); - if (fileLength == 0) + AZ::IO::HandleType fileHandle; + auto openResult = AZ::IO::FileIOBase::GetInstance()->Open(filePath, AZ::IO::OpenMode::ModeRead, fileHandle); + if (!openResult) { - AZ_Error("Verify", false, "File '%s' doesn't have content.", filePath.c_str()); + AZ_Error("Verify", false, "File '%s' could not be opened.", filePath); + return false; + } + + u64 fileLength = 0; + auto sizeResult = AZ::IO::FileIOBase::GetInstance()->Size(fileHandle, fileLength); + if (!sizeResult || (fileLength == 0)) + { + AZ_Error("Verify", false, "File '%s' doesn't have content.", filePath); return false; } AZStd::vector data; data.resize_no_construct(fileLength); - u64 bytesRead = AZ::IO::SystemFile::Read(filePath.c_str(), data.data()); - if (bytesRead != fileLength) + u64 bytesRead = 0; + auto readResult = AZ::IO::FileIOBase::GetInstance()->Read(fileHandle, data.data(), fileLength, true, &bytesRead); + if (!readResult || (bytesRead != fileLength)) { - AZ_Error("Verify", false, "Unable to read file '%s'.", filePath.c_str()); + AZ_Error("Verify", false, "Unable to read file '%s'.", filePath); return false; } + AZ::IO::FileIOBase::GetInstance()->Close(fileHandle); + AZ::IO::MemoryStream stream(data.data(), fileLength); ObjectStream::FilterDescriptor filter; @@ -241,7 +253,7 @@ namespace AZ::SerializeContextTools filter.m_assetCB = AZ::Data::AssetFilterNoAssetLoading; if (!ObjectStream::LoadBlocking(&stream, *sc, classCallback, filter)) { - AZ_Printf("Verify", "Failed to deserialize '%s'\n", filePath.c_str()); + AZ_Printf("Verify", "Failed to deserialize '%s'\n", filePath); return false; } return true; diff --git a/Code/Tools/SerializeContextTools/Utilities.h b/Code/Tools/SerializeContextTools/Utilities.h index d04f67a304..f08bfc2f64 100644 --- a/Code/Tools/SerializeContextTools/Utilities.h +++ b/Code/Tools/SerializeContextTools/Utilities.h @@ -39,7 +39,7 @@ namespace AZ static AZStd::vector GetSystemComponents(const Application& application); - static bool InspectSerializedFile(const AZStd::string& filePath, SerializeContext* sc, const ObjectStream::ClassReadyCB& classCallback); + static bool InspectSerializedFile(const char* filePath, SerializeContext* sc, const ObjectStream::ClassReadyCB& classCallback); private: Utilities() = delete; diff --git a/Code/Tools/SerializeContextTools/main.cpp b/Code/Tools/SerializeContextTools/main.cpp index fb2dc442ed..d9f2cfbcc2 100644 --- a/Code/Tools/SerializeContextTools/main.cpp +++ b/Code/Tools/SerializeContextTools/main.cpp @@ -16,6 +16,7 @@ #include #include #include +#include void PrintHelp() @@ -74,6 +75,14 @@ void PrintHelp() AZ_Printf("Help", R"( On Windows the should be in quotes, as \"/\" is treated as command option prefix)" "\n"); AZ_Printf("Help", R"( [opt] -verbose: Report additional details during the conversion process.)" "\n"); AZ_Printf("Help", R"( example: 'convert-ini --files=AssetProcessorPlatformConfig.ini;bootstrap.cfg --ext=setreg)" "\n"); + AZ_Printf("Help", " 'convert-slice': Converts ObjectStream-based slice files or legacy levels to a JSON-based prefab.\n"); + AZ_Printf("Help", " [arg] -files=: -separated list of files to convert. Supports wildcards.\n"); + AZ_Printf("Help", " [opt] -dryrun: Processes as normal, but doesn't write files.\n"); + AZ_Printf("Help", " [opt] -keepdefaults: Fields are written if a default value was found.\n"); + AZ_Printf("Help", " [opt] -verbose: Report additional details during the conversion process.\n"); + AZ_Printf("Help", " example: 'convert-slice -files=*.slice -specializations=editor\n"); + AZ_Printf("Help", " example: 'convert-slice -files=Levels/TestLevel/TestLevel.ly -specializations=editor\n"); + AZ_Printf("Help", "\n"); } int main(int argc, char** argv) @@ -114,6 +123,10 @@ int main(int argc, char** argv) { result = Converter::ConvertConfigFile(application); } + else if (AZ::StringFunc::Equal("convert-slice", action.c_str())) + { + result = SliceConverter::ConvertSliceFiles(application); + } else { PrintHelp(); diff --git a/Code/Tools/SerializeContextTools/serializecontexttools_files.cmake b/Code/Tools/SerializeContextTools/serializecontexttools_files.cmake index db584ff385..814c55ea08 100644 --- a/Code/Tools/SerializeContextTools/serializecontexttools_files.cmake +++ b/Code/Tools/SerializeContextTools/serializecontexttools_files.cmake @@ -17,6 +17,8 @@ set(FILES Dumper.h Dumper.cpp main.cpp + SliceConverter.h + SliceConverter.cpp Utilities.h Utilities.cpp ) diff --git a/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.h b/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.h index 951877ab28..a35e39ff6b 100644 --- a/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.h +++ b/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.h @@ -12,6 +12,7 @@ #pragma once #include +#include namespace AssetMemoryAnalyzer { diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp index ccba00f15f..59c799a601 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp @@ -79,7 +79,7 @@ namespace ImageProcessingAtom builderDescriptor.m_busId = azrtti_typeid(); builderDescriptor.m_createJobFunction = AZStd::bind(&ImageBuilderWorker::CreateJobs, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); builderDescriptor.m_processJobFunction = AZStd::bind(&ImageBuilderWorker::ProcessJob, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - builderDescriptor.m_version = 22; // [ATOM-14765] + builderDescriptor.m_version = 23; // [ATOM-14022] builderDescriptor.m_analysisFingerprint = ImageProcessingAtom::BuilderSettingManager::Instance()->GetAnalysisFingerprint(); m_imageBuilder.BusConnect(builderDescriptor.m_busId); AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor); diff --git a/Code/CryEngine/CryCommon/AzDXGIFormat.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/AzDXGIFormat.h similarity index 97% rename from Code/CryEngine/CryCommon/AzDXGIFormat.h rename to Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/AzDXGIFormat.h index 6315dd3955..74a7f469fb 100644 --- a/Code/CryEngine/CryCommon/AzDXGIFormat.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/AzDXGIFormat.h @@ -17,11 +17,11 @@ #include -#if defined(AZ_PLATFORM_WINDOWS) && !defined(OPENGL) -#include +#if __has_include() +# include // For non-windows platforms need to define the formats so that the ImageExtension // class used by the editor can have access to these -#elif AZ_TRAIT_OS_PLATFORM_APPLE || defined(OPENGL) || defined(AZ_PLATFORM_LINUX) || defined(AZ_PLATFORM_ANDROID) +#else #define DXGI_FORMAT_DEFINED 1 diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/DDSHeader.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/DDSHeader.h index f280d4df48..25ee79c414 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/DDSHeader.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/DDSHeader.h @@ -15,9 +15,6 @@ #include #include -//! The following defines and constants are extracted from ImageExtensionHelper.h -//! Please make sure they are always synced with ImageExtensionHelper.h - #define IMAGE_BUIDER_MAKEFOURCC(ch0, ch1, ch2, ch3) \ ((AZ::u32)(AZ::u8)(ch0) | ((AZ::u32)(AZ::u8)(ch1) << 8) | \ ((AZ::u32)(AZ::u8)(ch2) << 16) | ((AZ::u32)(AZ::u8)(ch3) << 24)) diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageAssetProducer.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageAssetProducer.cpp index 9c02894b7c..2448f501af 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageAssetProducer.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageAssetProducer.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -238,14 +239,9 @@ namespace ImageProcessingAtom uint8_t* mipBuffer; uint32_t pitch; m_imageObject->GetImagePointer(mip, mipBuffer, pitch); - uint32_t mipBufferSize = m_imageObject->GetMipBufSize(mip); - - RHI::ImageSubresourceLayout layout; - layout.m_bytesPerImage = mipBufferSize / arraySize; - layout.m_rowCount = layout.m_bytesPerImage / pitch; - layout.m_size = RHI::Size(m_imageObject->GetWidth(mip), m_imageObject->GetHeight(mip) / arraySize, 1); - layout.m_bytesPerRow = pitch; - + RHI::Format format = Utils::PixelFormatToRHIFormat(m_imageObject->GetPixelFormat(), m_imageObject->HasImageFlags(EIF_SRGBRead)); + + RHI::ImageSubresourceLayout layout = RHI::GetImageSubresourceLayout(RHI::Size(m_imageObject->GetWidth(mip), m_imageObject->GetHeight(mip) / arraySize, 1), format); builder.BeginMip(layout); for (uint32_t arrayIndex = 0; arrayIndex < arraySize; ++arrayIndex) diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h index f8942d0b61..6cf0a0e6dc 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h @@ -12,9 +12,6 @@ #pragma once -//! The following constants are extracted from ImageExtensionHelper.h -//! Please make sure they are always synced with the same constants defined in ImageExtensionHelper.h - namespace ImageProcessingAtom { // flags to propagate from the RC to the engine through GetImageFlags() diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.h index 7dd81fb195..8a4f8df1b2 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.h @@ -164,7 +164,7 @@ namespace ImageProcessingAtom AZ::Color m_colMinARGB; // ARGB will be added the properties of the DDS file AZ::Color m_colMaxARGB; // ARGB will be added the properties of the DDS file float m_averageBrightness; // will be added to the properties of the DDS file - AZ::u32 m_imageFlags; // combined from CImageExtensionHelper::EIF_Cubemap,... + AZ::u32 m_imageFlags; // AZ::u32 m_numPersistentMips; // number of mipmaps won't be splitted public: diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.h index 7d8c6f9284..6b099468ea 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/PixelFormatInfo.h @@ -12,7 +12,7 @@ #pragma once -#include // DX10+ formats. DXGI_FORMAT +#include // DX10+ formats. DXGI_FORMAT #include diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake b/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake index dfcfdfc319..69c678877d 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/imageprocessing_files.cmake @@ -41,6 +41,7 @@ set(FILES Source/BuilderSettings/PresetSettings.h Source/BuilderSettings/TextureSettings.cpp Source/BuilderSettings/TextureSettings.h + Source/Processing/AzDXGIFormat.h Source/Processing/DDSHeader.h Source/Processing/ImageAssetProducer.cpp Source/Processing/ImageAssetProducer.h diff --git a/Gems/Atom/Asset/ImageProcessingAtom/gem.json b/Gems/Atom/Asset/ImageProcessingAtom/gem.json deleted file mode 100644 index abe759ed71..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/gem.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "gem_name": "ImageProcessingAtom", - "Dependencies": [ - { - "Uuid": "a218db9eb2114477b46600fea4441a6c", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RPI" - } - ], - "GemFormatVersion": 4, - "Uuid": "9d10b00be96045caa64c705e5772cb64", - "Name": "ImageProcessingAtom", - "DisplayName": "Atom.Asset.ImageProcessing", - "Version": "0.1.0", - "Summary": "Contains Asset Processor builder for processing image files for Atom and UI for Atom texture property editing in Asset Browser", - "Tags": [ "Atom Image Builder", "Atom Texture Property Editor" ], - "LinkType": "Dynamic", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Editor", - "Type": "EditorModule" - } - ] -} diff --git a/Gems/Atom/Asset/Shader/gem.json b/Gems/Atom/Asset/Shader/gem.json deleted file mode 100644 index 3371b10f7a..0000000000 --- a/Gems/Atom/Asset/Shader/gem.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "gem_name": "Atom_Asset_Shader", - "Dependencies": [ - { - "Uuid": "a218db9eb2114477b46600fea4441a6c", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RPI" - } - ], - "GemFormatVersion": 4, - "Uuid": "d32452026dae4b7dba2ad89dbde9c48f", - "Name": "Atom_Asset_Shader", - "DisplayName": "Atom.Asset.Shader", - "Version": "0.1.0", - "Summary": "The systems necessary to build and use AZSL Shaders", - "Tags": ["Assets", "Atom", "Shader"], - "LinkType": "Dynamic", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Builders", - "Type": "EditorModule" - } - ] -} diff --git a/Gems/Atom/Bootstrap/gem.json b/Gems/Atom/Bootstrap/gem.json deleted file mode 100644 index 21b909c249..0000000000 --- a/Gems/Atom/Bootstrap/gem.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "gem_name": "Atom_Bootstrap", - "Dependencies": [ - { - "Uuid": "a218db9eb2114477b46600fea4441a6c", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RPI.Public" - } - ], - "GemFormatVersion": 4, - "Uuid": "c7ff89ad6e8b4b45b2fadef2bcf12d6e", - "Name": "Atom_Bootstrap", - "DisplayName": "Atom.Bootstrap", - "Version": "0.1.0", - "Summary": "Bootstrap gem to setup any necessary Atom components.", - "Tags": ["Atom", "Bootstrap"], - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - } - ] -} diff --git a/Gems/Atom/Component/DebugCamera/gem.json b/Gems/Atom/Component/DebugCamera/gem.json deleted file mode 100644 index eb59669951..0000000000 --- a/Gems/Atom/Component/DebugCamera/gem.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "gem_name": "Atom_Component_DebugCamera", - "Dependencies": [ - { - "Uuid": "a218db9eb2114477b46600fea4441a6c", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RPI" - } - ], - "GemFormatVersion": 4, - "Uuid": "013d1b42ad314c929b292c143bcbf045", - "Version": "0.1.0", - "Name": "Atom_Component_DebugCamera", - "DisplayName": "Atom.Component.DebugCamera", - "Tags": ["Atom", "Camera", "Debug"], - "Summary": "Debug Camera for testing RPI/RHI", - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - } - ] -} diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h index 089f4e8c62..58fb2e0f8a 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignment.h @@ -1,21 +1,21 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once +#include #include -#include #include -#include #include +#include namespace AZ { @@ -31,39 +31,19 @@ namespace AZ MaterialAssignment() = default; - MaterialAssignment(const AZ::Data::AssetId& materialAssetId) - : m_materialInstance() - { - m_materialAsset.Create(materialAssetId); - } + MaterialAssignment(const AZ::Data::AssetId& materialAssetId); - MaterialAssignment(const Data::Asset& asset) - : m_materialAsset(asset) - , m_materialInstance() - { - } + MaterialAssignment(const Data::Asset& asset); - MaterialAssignment(const Data::Asset& asset, const Data::Instance& instance) - : m_materialAsset(asset) - , m_materialInstance(instance) - { - } + MaterialAssignment(const Data::Asset& asset, const Data::Instance& instance); - void RebuildInstance() - { - if (m_materialAsset.IsReady()) - { - m_materialInstance = m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); - AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); - } - } + //! Recreates the material instance from the asset if it has been loaded. + //! If amy property overrides have been specified then a unique instance will be created. + //! Otherwise an attempt will be made to find or create a shared instance. + void RebuildInstance(); - AZStd::string ToString() const - { - AZStd::string assetPathString; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPathString, &AZ::Data::AssetCatalogRequests::GetAssetPathById, m_materialAsset.GetId()); - return assetPathString; - } + //! Returns a string composed of the asset path. + AZStd::string ToString() const; Data::Asset m_materialAsset; Data::Instance m_materialInstance; @@ -77,64 +57,15 @@ namespace AZ static const MaterialAssignmentMap DefaultMaterialAssignmentMap; //! Utility function for retrieving a material entry from a MaterialAssignmentMap - AZ_INLINE const MaterialAssignment& GetMaterialAssignmentFromMap(const MaterialAssignmentMap& materials, const MaterialAssignmentId& id) - { - const auto& materialItr = materials.find(id); - return materialItr != materials.end() ? materialItr->second : DefaultMaterialAssignment; - } - - //! Utility function for retrieving a material entry from a MaterialAssignmentMap, falling back to defaults for a particular asset or the entire model - AZ_INLINE const MaterialAssignment& GetMaterialAssignmentFromMapWithFallback(const MaterialAssignmentMap& materials, const MaterialAssignmentId& id) - { - const MaterialAssignment& lodAssignment = GetMaterialAssignmentFromMap(materials, id); - if (lodAssignment.m_materialInstance.get()) - { - return lodAssignment; - } + const MaterialAssignment& GetMaterialAssignmentFromMap(const MaterialAssignmentMap& materials, const MaterialAssignmentId& id); - const MaterialAssignment& assetAssignment = GetMaterialAssignmentFromMap(materials, MaterialAssignmentId::CreateFromAssetOnly(id.m_materialAssetId)); - if (assetAssignment.m_materialInstance.get()) - { - return assetAssignment; - } - - const MaterialAssignment& defaultAssignment = GetMaterialAssignmentFromMap(materials, DefaultMaterialAssignmentId); - if (defaultAssignment.m_materialInstance.get()) - { - return defaultAssignment; - } - - return DefaultMaterialAssignment; - } + //! Utility function for retrieving a material entry from a MaterialAssignmentMap, falling back to defaults for a particular asset + //! or the entire model + const MaterialAssignment& GetMaterialAssignmentFromMapWithFallback( + const MaterialAssignmentMap& materials, const MaterialAssignmentId& id); //! Utility function for generating a set of available material assignments in a model - AZ_INLINE MaterialAssignmentMap GetMaterialAssignmentsFromModel(Data::Instance model) - { - MaterialAssignmentMap materials; - materials[DefaultMaterialAssignmentId] = MaterialAssignment(); - - if (model) - { - size_t lodIndex = 0; - for (const Data::Instance& lod : model->GetLods()) - { - for (const AZ::RPI::ModelLod::Mesh& mesh : lod->GetMeshes()) - { - if (mesh.m_material) - { - const MaterialAssignmentId generalId = MaterialAssignmentId::CreateFromAssetOnly(mesh.m_material->GetAssetId()); - materials[generalId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); - - const MaterialAssignmentId specificId = MaterialAssignmentId::CreateFromLodAndAsset(lodIndex, mesh.m_material->GetAssetId()); - materials[specificId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); - } - } - ++lodIndex; - } - } - - return materials; - } + MaterialAssignmentMap GetMaterialAssignmentsFromModel(Data::Instance model); } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h index 267e65743a..80de6d8041 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Material/MaterialAssignmentId.h @@ -1,20 +1,20 @@ /* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ #pragma once +#include #include #include -#include #include #include #include @@ -26,6 +26,9 @@ namespace AZ { using MaterialAssignmentLodIndex = AZ::u64; + //! MaterialAssignmentId is used to address available and overridable material slots on a model. + //! The LOD and one of the model's original material asset IDs are used as coordinates that identify + //! a specific material slot or a set of slots matching either. struct MaterialAssignmentId final { AZ_RTTI(AZ::Render::MaterialAssignmentId, "{EB603581-4654-4C17-B6DE-AE61E79EDA97}"); @@ -34,69 +37,37 @@ namespace AZ MaterialAssignmentId() = default; - MaterialAssignmentId(MaterialAssignmentLodIndex lodIndex, const AZ::Data::AssetId& materialAssetId) - : m_lodIndex(lodIndex) - , m_materialAssetId(materialAssetId) - { - } - - static MaterialAssignmentId CreateDefault() - { - return MaterialAssignmentId(NonLodIndex, AZ::Data::AssetId()); - } - - static MaterialAssignmentId CreateFromAssetOnly(AZ::Data::AssetId materialAssetId) - { - return MaterialAssignmentId(NonLodIndex, materialAssetId); - } - - static MaterialAssignmentId CreateFromLodAndAsset(MaterialAssignmentLodIndex lodIndex, AZ::Data::AssetId materialAssetId) - { - return MaterialAssignmentId(lodIndex, materialAssetId); - } - - bool IsDefault() const - { - return m_lodIndex == NonLodIndex && !m_materialAssetId.IsValid(); - } - - bool IsAssetOnly() const - { - return m_lodIndex == NonLodIndex && m_materialAssetId.IsValid(); - } - - bool IsLodAndAsset() const - { - return m_lodIndex != NonLodIndex && m_materialAssetId.IsValid(); - } - - - AZStd::string ToString() const - { - AZStd::string assetPathString; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPathString, &AZ::Data::AssetCatalogRequests::GetAssetPathById, m_materialAssetId); - AZ::StringFunc::Path::StripPath(assetPathString); - AZ::StringFunc::Path::StripExtension(assetPathString); - return AZStd::string::format("%s:%llu", assetPathString.c_str(), m_lodIndex); - } - - size_t GetHash() const - { - size_t seed = 0; - AZStd::hash_combine(seed, m_lodIndex); - AZStd::hash_combine(seed, m_materialAssetId); - return seed; - } - - bool operator==(const MaterialAssignmentId& rhs) const - { - return m_lodIndex == rhs.m_lodIndex && m_materialAssetId == rhs.m_materialAssetId; - } - - bool operator!=(const MaterialAssignmentId& rhs) const - { - return m_lodIndex != rhs.m_lodIndex || m_materialAssetId != rhs.m_materialAssetId; - } + MaterialAssignmentId(MaterialAssignmentLodIndex lodIndex, const AZ::Data::AssetId& materialAssetId); + + //! Create an ID that maps to all material slots, regardless of asset ID or LOD, effectively applying to an entire model. + static MaterialAssignmentId CreateDefault(); + + //! Create an ID that maps to all material slots with a corresponding asset ID, regardless of LOD. + static MaterialAssignmentId CreateFromAssetOnly(AZ::Data::AssetId materialAssetId); + + //! Create an ID that maps to a specific material slot with a corresponding asset ID and LOD. + static MaterialAssignmentId CreateFromLodAndAsset(MaterialAssignmentLodIndex lodIndex, AZ::Data::AssetId materialAssetId); + + //! Returns true if the asset ID and LOD are invalid + bool IsDefault() const; + + //! Returns true if the asset ID is valid and LOD is invalid + bool IsAssetOnly() const; + + //! Returns true if the asset ID and LOD are both valid + bool IsLodAndAsset() const; + + //! Creates a string composed of the asset path and LOD + AZStd::string ToString() const; + + //! Creates a hash composed of the asset ID sub ID and LOD + size_t GetHash() const; + + //! Returns true if both asset ID sub IDs and LODs match + bool operator==(const MaterialAssignmentId& rhs) const; + + //! Returns true if both asset ID sub IDs and LODs do not match + bool operator!=(const MaterialAssignmentId& rhs) const; static constexpr MaterialAssignmentLodIndex NonLodIndex = -1; MaterialAssignmentLodIndex m_lodIndex = NonLodIndex; @@ -116,4 +87,4 @@ namespace AZStd return id.GetHash(); } }; -} //namespace AZStd +} // namespace AZStd diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index be6d438a62..089a6168b1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -274,6 +274,10 @@ namespace AZ passSystem->AddPassCreator(Name("ReflectionScreenSpaceBlurPass"), &Render::ReflectionScreenSpaceBlurPass::Create); passSystem->AddPassCreator(Name("ReflectionScreenSpaceBlurChildPass"), &Render::ReflectionScreenSpaceBlurChildPass::Create); passSystem->AddPassCreator(Name("ReflectionCopyFrameBufferPass"), &Render::ReflectionCopyFrameBufferPass::Create); + + // setup handler for load pass template mappings + m_loadTemplatesHandler = RPI::PassSystemInterface::OnReadyLoadTemplatesEvent::Handler([this]() { this->LoadPassTemplateMappings(); }); + RPI::PassSystemInterface::Get()->ConnectEvent(m_loadTemplatesHandler); } void CommonSystemComponent::Deactivate() @@ -292,5 +296,12 @@ namespace AZ AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); } + + void CommonSystemComponent::LoadPassTemplateMappings() + { + const char* passTemplatesFile = "Passes/PassTemplates.azasset"; + RPI::PassSystemInterface::Get()->LoadPassTemplateMappings(passTemplatesFile); + } + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.h b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.h index 595faba523..92705f0fa6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.h +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.h @@ -14,6 +14,8 @@ #include #include +#include + #if AZ_TRAIT_LUXCORE_SUPPORTED #include "LuxCore/LuxCoreRenderer.h" #endif @@ -41,6 +43,11 @@ namespace AZ void Activate() override; void Deactivate() override; + // Load pass template mappings for this gem + void LoadPassTemplateMappings(); + + RPI::PassSystemInterface::OnReadyLoadTemplatesEvent::Handler m_loadTemplatesHandler; + #if AZ_TRAIT_LUXCORE_SUPPORTED // LuxCore LuxCoreRenderer m_luxCore; diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp index 24857f8d65..febb0b16c5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp @@ -134,7 +134,14 @@ namespace AZ { m_decalData.GetData(decal.GetIndex()) = m_decalData.GetData(sourceDecal.GetIndex()); const auto materialAsset = GetMaterialUsedByDecal(sourceDecal); - m_materialToTextureArrayLookupTable.at(materialAsset).m_useCount++; + if (materialAsset.IsValid()) + { + m_materialToTextureArrayLookupTable.at(materialAsset).m_useCount++; + } + else + { + AZ_Warning("DecalTextureArrayFeatureProcessor", false, "CloneDecal called on a decal with no material set."); + } m_deviceBufferNeedsUpdate = true; } return decal; diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index f817e8324b..ffb5469aef 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -11,8 +11,8 @@ */ #include -#include #include +#include namespace AZ { @@ -67,5 +67,101 @@ namespace AZ } } + + MaterialAssignment::MaterialAssignment(const AZ::Data::AssetId& materialAssetId) + : m_materialInstance() + { + m_materialAsset.Create(materialAssetId); + } + + MaterialAssignment::MaterialAssignment(const Data::Asset& asset) + : m_materialAsset(asset) + , m_materialInstance() + { + } + + MaterialAssignment::MaterialAssignment(const Data::Asset& asset, const Data::Instance& instance) + : m_materialAsset(asset) + , m_materialInstance(instance) + { + } + + void MaterialAssignment::RebuildInstance() + { + if (m_materialAsset.IsReady()) + { + m_materialInstance = + m_propertyOverrides.empty() ? RPI::Material::FindOrCreate(m_materialAsset) : RPI::Material::Create(m_materialAsset); + AZ_Error("MaterialAssignment", m_materialInstance, "Material instance not initialized"); + } + } + + AZStd::string MaterialAssignment::ToString() const + { + AZStd::string assetPathString; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetPathString, &AZ::Data::AssetCatalogRequests::GetAssetPathById, m_materialAsset.GetId()); + return assetPathString; + } + + const MaterialAssignment& GetMaterialAssignmentFromMap(const MaterialAssignmentMap& materials, const MaterialAssignmentId& id) + { + const auto& materialItr = materials.find(id); + return materialItr != materials.end() ? materialItr->second : DefaultMaterialAssignment; + } + + const MaterialAssignment& GetMaterialAssignmentFromMapWithFallback( + const MaterialAssignmentMap& materials, const MaterialAssignmentId& id) + { + const MaterialAssignment& lodAssignment = GetMaterialAssignmentFromMap(materials, id); + if (lodAssignment.m_materialInstance.get()) + { + return lodAssignment; + } + + const MaterialAssignment& assetAssignment = + GetMaterialAssignmentFromMap(materials, MaterialAssignmentId::CreateFromAssetOnly(id.m_materialAssetId)); + if (assetAssignment.m_materialInstance.get()) + { + return assetAssignment; + } + + const MaterialAssignment& defaultAssignment = GetMaterialAssignmentFromMap(materials, DefaultMaterialAssignmentId); + if (defaultAssignment.m_materialInstance.get()) + { + return defaultAssignment; + } + + return DefaultMaterialAssignment; + } + + MaterialAssignmentMap GetMaterialAssignmentsFromModel(Data::Instance model) + { + MaterialAssignmentMap materials; + materials[DefaultMaterialAssignmentId] = MaterialAssignment(); + + if (model) + { + size_t lodIndex = 0; + for (const Data::Instance& lod : model->GetLods()) + { + for (const AZ::RPI::ModelLod::Mesh& mesh : lod->GetMeshes()) + { + if (mesh.m_material) + { + const MaterialAssignmentId generalId = MaterialAssignmentId::CreateFromAssetOnly(mesh.m_material->GetAssetId()); + materials[generalId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); + + const MaterialAssignmentId specificId = + MaterialAssignmentId::CreateFromLodAndAsset(lodIndex, mesh.m_material->GetAssetId()); + materials[specificId] = MaterialAssignment(mesh.m_material->GetAsset(), mesh.m_material); + } + } + ++lodIndex; + } + } + + return materials; + } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp index 4813136d2e..59de229445 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentId.cpp @@ -11,8 +11,8 @@ */ #include -#include #include +#include namespace AZ { @@ -47,5 +47,70 @@ namespace AZ ; } } + + MaterialAssignmentId::MaterialAssignmentId(MaterialAssignmentLodIndex lodIndex, const AZ::Data::AssetId& materialAssetId) + : m_lodIndex(lodIndex) + , m_materialAssetId(materialAssetId) + { + } + + MaterialAssignmentId MaterialAssignmentId::CreateDefault() + { + return MaterialAssignmentId(NonLodIndex, AZ::Data::AssetId()); + } + + MaterialAssignmentId MaterialAssignmentId::CreateFromAssetOnly(AZ::Data::AssetId materialAssetId) + { + return MaterialAssignmentId(NonLodIndex, materialAssetId); + } + + MaterialAssignmentId MaterialAssignmentId::CreateFromLodAndAsset( + MaterialAssignmentLodIndex lodIndex, AZ::Data::AssetId materialAssetId) + { + return MaterialAssignmentId(lodIndex, materialAssetId); + } + + bool MaterialAssignmentId::IsDefault() const + { + return m_lodIndex == NonLodIndex && !m_materialAssetId.IsValid(); + } + + bool MaterialAssignmentId::IsAssetOnly() const + { + return m_lodIndex == NonLodIndex && m_materialAssetId.IsValid(); + } + + bool MaterialAssignmentId::IsLodAndAsset() const + { + return m_lodIndex != NonLodIndex && m_materialAssetId.IsValid(); + } + + AZStd::string MaterialAssignmentId::ToString() const + { + AZStd::string assetPathString; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetPathString, &AZ::Data::AssetCatalogRequests::GetAssetPathById, m_materialAssetId); + AZ::StringFunc::Path::StripPath(assetPathString); + AZ::StringFunc::Path::StripExtension(assetPathString); + return AZStd::string::format("%s:%llu", assetPathString.c_str(), m_lodIndex); + } + + size_t MaterialAssignmentId::GetHash() const + { + size_t seed = 0; + AZStd::hash_combine(seed, m_lodIndex); + AZStd::hash_combine(seed, m_materialAssetId.m_subId); + return seed; + } + + bool MaterialAssignmentId::operator==(const MaterialAssignmentId& rhs) const + { + return m_lodIndex == rhs.m_lodIndex && m_materialAssetId.m_subId == rhs.m_materialAssetId.m_subId; + } + + bool MaterialAssignmentId::operator!=(const MaterialAssignmentId& rhs) const + { + return !(*this == rhs); + } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index 47000d8a5c..8926b0c19f 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -27,8 +27,6 @@ set(FILES Include/Atom/Feature/ImGui/SystemBus.h Include/Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessor.h Include/Atom/Feature/LookupTable/LookupTableAsset.h - Include/Atom/Feature/Material/MaterialAssignment.h - Include/Atom/Feature/Material/MaterialAssignmentId.h Include/Atom/Feature/Mesh/MeshFeatureProcessor.h Include/Atom/Feature/PostProcessing/PostProcessingConstants.h Include/Atom/Feature/PostProcessing/SMAAFeatureProcessorInterface.h @@ -155,8 +153,6 @@ set(FILES Source/LookupTable/LookupTableAsset.cpp Source/Material/ConvertEmissiveUnitFunctor.cpp Source/Material/ConvertEmissiveUnitFunctor.h - Source/Material/MaterialAssignment.cpp - Source/Material/MaterialAssignmentId.cpp Source/Material/ShaderEnableFunctor.cpp Source/Material/ShaderEnableFunctor.h Source/Material/SubsurfaceTransmissionParameterFunctor.cpp diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_staticlibrary_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_staticlibrary_files.cmake index d33e861c02..553f307409 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_staticlibrary_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_staticlibrary_files.cmake @@ -10,8 +10,12 @@ # set(FILES + Include/Atom/Feature/Material/MaterialAssignment.h + Include/Atom/Feature/Material/MaterialAssignmentId.h Include/Atom/Feature/Utils/LightingPreset.h Include/Atom/Feature/Utils/ModelPreset.h + Source/Material/MaterialAssignment.cpp + Source/Material/MaterialAssignmentId.cpp Source/Utils/LightingPreset.cpp Source/Utils/ModelPreset.cpp ) diff --git a/Gems/Atom/Feature/Common/gem.json b/Gems/Atom/Feature/Common/gem.json deleted file mode 100644 index 689deb492e..0000000000 --- a/Gems/Atom/Feature/Common/gem.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "gem_name": "Atom_Feature_Common", - "Dependencies": [ - { - "Uuid": "a218db9eb2114477b46600fea4441a6c", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RPI" - } - ], - "GemFormatVersion": 4, - "Uuid": "b58e5eed0901428ca78544b04dbd61bd", - "Name": "Atom_Feature_Common", - "DisplayName": "Atom.Feature.Common", - "Version": "0.1.0", - "LinkType": "Dynamic", - "Summary": "Provides commonly used render features.", - "Tags": [ "Atom", "Feature", "Common" ], - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - }, - { - "Name": "Builders", - "Type": "EditorModule" - }, - { - "Name": "Public", - "Type": "StaticLib" - }, - { - "Name": "Editor", - "Type": "EditorModule", - "Extends": "GameModule" - }, - { - "Name": "StaticLibrary", - "Type": "StaticLib" - } - ] -} diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ImageSubresource.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ImageSubresource.h index b536ed5524..e75ee4d4bf 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ImageSubresource.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/ImageSubresource.h @@ -100,7 +100,9 @@ namespace AZ Size size, uint32_t rowCount, uint32_t bytesPerRow, - uint32_t bytesPerImage); + uint32_t bytesPerImage, + uint32_t numBlocksWidth, + uint32_t numBlocksHeight); /// The size of the image subresource in pixels. Certain formats have alignment requirements. /// Block compressed formats are 4 pixel aligned. Other non-standard formats may be 2 pixel aligned. @@ -114,6 +116,13 @@ namespace AZ /// The number of bytes in a single image slice. 3D textures are comprised of m_size.m_depth image slices. uint32_t m_bytesPerImage = 0; + + /// The number of blocks in width based on the texture fomat + uint32_t m_blockElementWidth = 1; + + /// The number of blocks in height based on the texture fomat + uint32_t m_blockElementHeight = 1; + }; struct ImageSubresourceLayoutPlaced : ImageSubresourceLayout diff --git a/Gems/Atom/RHI/Code/Source/RHI.Reflect/ImageSubresource.cpp b/Gems/Atom/RHI/Code/Source/RHI.Reflect/ImageSubresource.cpp index 4e34fe2b32..c76af7d5bb 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Reflect/ImageSubresource.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Reflect/ImageSubresource.cpp @@ -102,11 +102,13 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(0) + ->Version(1) ->Field("m_size", &ImageSubresourceLayout::m_size) ->Field("m_rowCount", &ImageSubresourceLayout::m_rowCount) ->Field("m_bytesPerRow", &ImageSubresourceLayout::m_bytesPerRow) ->Field("m_bytesPerImage", &ImageSubresourceLayout::m_bytesPerImage) + ->Field("m_blockElementWidth", &ImageSubresourceLayout::m_blockElementWidth) + ->Field("m_blockElementHeight", &ImageSubresourceLayout::m_blockElementHeight) ; } } @@ -115,11 +117,15 @@ namespace AZ Size size, uint32_t rowCount, uint32_t bytesPerRow, - uint32_t bytesPerImage) + uint32_t bytesPerImage, + uint32_t blockElementWidth, + uint32_t blockElementHeight) : m_size{size} , m_rowCount{rowCount} , m_bytesPerRow{bytesPerRow} , m_bytesPerImage{bytesPerImage} + , m_blockElementWidth{blockElementWidth} + , m_blockElementHeight{blockElementHeight} {} ImageSubresourceLayoutPlaced::ImageSubresourceLayoutPlaced(const ImageSubresourceLayout& subresourceLayout, size_t offset) @@ -296,8 +302,22 @@ namespace AZ numBlocks = 4; break; + case RHI::Format::EAC_R11_UNORM: + case RHI::Format::EAC_R11_SNORM: + isBlockCompressed = true; + bytesPerElement = 8; + numBlocks = 4; + break; + + case RHI::Format::EAC_RG11_UNORM: + case RHI::Format::EAC_RG11_SNORM: + isBlockCompressed = true; + bytesPerElement = 16; + numBlocks = 4; + break; + default: - AZ_Assert(false, "Unimplemented esoteric format."); + AZ_Assert(false, "Unimplemented esoteric format %i.", static_cast(imageFormat)); } if (isBlockCompressed) @@ -316,6 +336,8 @@ namespace AZ subresourceLayout.m_rowCount = numBlocksHigh; subresourceLayout.m_size.m_width = imageSize.m_width; subresourceLayout.m_size.m_height = imageSize.m_height; + subresourceLayout.m_blockElementWidth = numBlocks; + subresourceLayout.m_blockElementHeight = numBlocks; } else if (isPacked) { diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp index 22849f7236..951a405d40 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp @@ -271,7 +271,7 @@ namespace AZ // Staging sizes uint32_t stagingRowPitch = RHI::AlignUp(subresourceLayout.m_bytesPerRow, DX12_TEXTURE_DATA_PITCH_ALIGNMENT); uint32_t stagingSlicePitch = RHI::AlignUp(subresourceLayout.m_rowCount*stagingRowPitch, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); - const uint32_t compressedTexelBlockSizeHeight = subresourceLayout.m_size.m_height / subresourceLayout.m_rowCount; + const uint32_t compressedTexelBlockSizeHeight = subresourceLayout.m_blockElementHeight; // ImageHeight must be bigger than or equal to the Image's row count. Images with a RowCount that is less than the ImageHeight indicates a block compression. // Images with a RowCount which is higher than the ImageHeight indicates a planar image, which is not supported for streaming images. @@ -386,7 +386,7 @@ namespace AZ const uint32_t numRowsToCopy = endRow - startRow; // Calculate the blocksize for BC formatted images; the copy command works in texels. - const uint32_t heightToCopy = (endRow - startRow) * compressedTexelBlockSizeHeight; + uint32_t heightToCopy = (endRow - startRow) * compressedTexelBlockSizeHeight; // Copy subresource data to staging memory { @@ -402,6 +402,14 @@ namespace AZ } } + //Clamp heightToCopy to match subresourceLayout.m_size.m_height as it is possible to go over + //if subresourceLayout.m_size.m_height is not perfectly divisible by compressedTexelBlockSizeHeight + if(destHeight+heightToCopy > subresourceLayout.m_size.m_height) + { + uint32_t HeightDiff = (destHeight + heightToCopy) - subresourceLayout.m_size.m_height; + heightToCopy -= HeightDiff; + } + // Add copy command to copy image subresource from staging memory to image gpu resource // Source location diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h index c7a2a5dd64..a6fe57f6d8 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h @@ -415,7 +415,7 @@ namespace AZ // this assert typically happens when a shader needs a particular Srg (e.g., the ViewSrg) but the code did not bind it, // check the pass code in this callstack to determine why it was not bound - AZ_Assert(false, "ShaderResourceGroup in slot '%d' is null at DrawItem submit time. This is not valid and means the shader is expecting an Srg that is not currently bound in the pipeline. Current bindings: %s", + AZ_Assert(false, "ShaderResourceGroup in slot '%d' is null at DrawItem submit time. This is not valid and means the shader is expecting an Srg that isF not currently bound in the pipeline. Current bindings: %s", srgSlot, slotSrgString.c_str()); diff --git a/Gems/Atom/RHI/DX12/gem.json b/Gems/Atom/RHI/DX12/gem.json deleted file mode 100644 index 1af6988a2f..0000000000 --- a/Gems/Atom/RHI/DX12/gem.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "gem_name": "Atom_RHI_DX12", - "Dependencies": [ - { - "Uuid": "fb7f322c8bdb42228d9e155c954f98bd", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RHI" - } - ], - "GemFormatVersion": 4, - "Uuid": "e011969cf32442fdaac2443a960ab5ff", - "Name": "Atom_RHI_DX12", - "DisplayName": "Atom RHI.DX12", - "Version": "0.1.0", - "Summary": "The DirectX 12 backend for the Atom Render Hardware Interface", - "Tags": ["Atom", "RHI", "DX12"], - "LinkType": "Dynamic", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Private", - "Type": "GameModule" - }, - { - "Name": "Reflect", - "Type": "StaticLib" - }, - { - "Name": "Builders", - "Type": "EditorModule" - } - ] -} diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp index 891f9ea2f3..594a4931b9 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/AsyncUploadQueue.cpp @@ -190,8 +190,8 @@ namespace AZ const uint32_t stagingRowPitch = RHI::AlignUp(subresourceLayout.m_bytesPerRow, bufferOffsetAlign); const uint32_t stagingSlicePitch = RHI::AlignUp(subresourceLayout.m_rowCount * stagingRowPitch, bufferOffsetAlign); const uint32_t rowsPerSplit = static_cast(m_descriptor.m_stagingSizeInBytes) / stagingRowPitch; - const uint32_t compressedTexelBlockSizeHeight = subresourceLayout.m_size.m_height / subresourceLayout.m_rowCount; - + const uint32_t compressedTexelBlockSizeHeight = subresourceLayout.m_blockElementHeight; + // ImageHeight must be bigger than or equal to the Image's row count. Images with a RowCount that is less than the ImageHeight indicates a block compression. // Images with a RowCount which is higher than the ImageHeight indicates a planar image, which is not supported for streaming images. if (subresourceLayout.m_size.m_height < subresourceLayout.m_rowCount) @@ -281,7 +281,7 @@ namespace AZ const uint32_t endRow = AZStd::min(startRow + rowsPerSplit, subresourceLayout.m_rowCount); // Calculate the blocksize for BC formatted images; the copy command works in texels. - const uint32_t heightToCopy = (endRow - startRow) * compressedTexelBlockSizeHeight; + uint32_t heightToCopy = (endRow - startRow) * compressedTexelBlockSizeHeight; // Copy subresource data to staging memory. uint8_t* stagingDataStart = framePacket->m_stagingResourceData + framePacket->m_dataOffset; @@ -293,6 +293,14 @@ namespace AZ const uint32_t bytesCopied = (endRow - startRow) * stagingRowPitch; Platform::SynchronizeBufferOnCPU(framePacket->m_stagingResource, framePacket->m_dataOffset, bytesCopied); + //Clamp heightToCopy to match subresourceLayout.m_size.m_height as it is possible to go over + //if subresourceLayout.m_size.m_height is not perfectly divisible by compressedTexelBlockSizeHeight + if(destHeight+heightToCopy > subresourceLayout.m_size.m_height) + { + uint32_t HeightDiff = (destHeight + heightToCopy) - subresourceLayout.m_size.m_height; + heightToCopy -= HeightDiff; + } + const RHI::Size sourceSize = RHI::Size(subresourceLayout.m_size.m_width, heightToCopy, 1); const RHI::Origin sourceOrigin = RHI::Origin(0, destHeight, depth); CopyBufferToImage(framePacket, image, stagingRowPitch, bytesCopied, diff --git a/Gems/Atom/RHI/Metal/gem.json b/Gems/Atom/RHI/Metal/gem.json deleted file mode 100644 index 5724c6e4a4..0000000000 --- a/Gems/Atom/RHI/Metal/gem.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "gem_name": "Atom_RHI_Metal", - "Dependencies": [ - { - "Uuid": "fb7f322c8bdb42228d9e155c954f98bd", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RHI" - } - ], - "GemFormatVersion": 4, - "Uuid": "5f27cdc951e64fe0be9d823dc7acbc28", - "Name": "Atom_RHI_Metal", - "DisplayName": "Atom RHI.Metal", - "Version": "0.1.0", - "Summary": "The Metal backend for the Atom Render Hardware Interface", - "Tags": ["Atom", "RHI", "Metal"], - "LinkType": "Dynamic", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Private", - "Type": "GameModule" - }, - { - "Name": "Reflect", - "Type": "StaticLib" - }, - { - "Name": "Builders", - "Type": "EditorModule" - } - ] -} diff --git a/Gems/Atom/RHI/Null/gem.json b/Gems/Atom/RHI/Null/gem.json deleted file mode 100644 index 7327b6af77..0000000000 --- a/Gems/Atom/RHI/Null/gem.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "gem_name": "Atom_RHI_Null", - "GemFormatVersion": 4, - "Uuid": "1f64c07a7d2f4722a3969fcf3be34d30", - "Name": "Atom_RHI_Null", - "DisplayName": "Atom RHI.Null", - "Version": "0.1.0", - "Summary": "The Null backend for the Atom Render Hardware Interface", - "Tags": ["Atom", "RHI", "Null"], - "LinkType": "Dynamic", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Private", - "Type": "GameModule" - }, - { - "Name": "Reflect", - "Type": "StaticLib" - }, - { - "Name": "Builders", - "Type": "EditorModule" - } - ] -} diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/AsyncUploadQueue.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/AsyncUploadQueue.cpp index a6e7ff082f..ed578f18c5 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/AsyncUploadQueue.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/AsyncUploadQueue.cpp @@ -214,7 +214,7 @@ namespace AZ const uint32_t stagingRowPitch = RHI::AlignUp(subresourceLayout.m_bytesPerRow, bufferOffsetAlign); const uint32_t stagingSlicePitch = subresourceLayout.m_rowCount * stagingRowPitch; const uint32_t rowsPerSplit = static_cast(m_descriptor.m_stagingSizeInBytes) / stagingRowPitch; - const uint32_t compressedTexelBlockSizeHeight = subresourceLayout.m_size.m_height / subresourceLayout.m_rowCount; + const uint32_t compressedTexelBlockSizeHeight = subresourceLayout.m_blockElementHeight; // ImageHeight must be bigger than or equal to the Image's row count. Images with a RowCount that is less than the ImageHeight indicates a block compression. // Images with a RowCount which is higher than the ImageHeight indicates a planar image, which is not supported for streaming images. @@ -333,7 +333,7 @@ namespace AZ const uint32_t endRow = AZStd::min(startRow + rowsPerSplit, subresourceLayout.m_rowCount); // Calculate the blocksize for BC formatted images; the copy command works in texels. - const uint32_t heightToCopy = (endRow - startRow) * compressedTexelBlockSizeHeight; + uint32_t heightToCopy = (endRow - startRow) * compressedTexelBlockSizeHeight; // Copy subresource data to staging memory. { @@ -348,6 +348,14 @@ namespace AZ framePacket->m_stagingBuffer->GetBufferMemoryView()->Unmap(RHI::HostMemoryAccess::Write); } + //Clamp heightToCopy to match subresourceLayout.m_size.m_height as it is possible to go over + //if subresourceLayout.m_size.m_height is not perfectly divisible by compressedTexelBlockSizeHeight + if(destHeight+heightToCopy > subresourceLayout.m_size.m_height) + { + uint32_t HeightDiff = (destHeight + heightToCopy) - subresourceLayout.m_size.m_height; + heightToCopy -= HeightDiff; + } + // Add copy command to copy image subresource from staging memory to image GPU resource. copyDescriptor.m_destinationOrigin.m_top = destHeight; copyDescriptor.m_sourceSize.m_height = heightToCopy; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp index 8eee7ef726..634f5a51ac 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/DescriptorSet.cpp @@ -239,7 +239,16 @@ namespace AZ allocInfo.pSetLayouts = &nativeLayout; VkResult result = vkAllocateDescriptorSets(descriptor.m_device->GetNativeDevice(), &allocInfo, &m_nativeDescriptorSet); - AssertSuccess(result); + if (result == VK_ERROR_FRAGMENTED_POOL) + { + // fragmented pool will be re-created subsequently in DescriptorSetAllocator, so warning only + AZ_Warning("Vulkan RHI", false, "Fragmented pool, will be recreated in DescriptorSetAllocator afterward"); + } + else + { + AssertSuccess(result); + } + if (result != VK_SUCCESS) { return result; diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Vulkan.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Vulkan.cpp index 90a4c2f9c2..311d3436de 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Vulkan.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/Vulkan.cpp @@ -96,6 +96,8 @@ namespace AZ return "Validation failed"; case VK_ERROR_OUT_OF_POOL_MEMORY: return "Pool is out of memory"; + case VK_ERROR_FRAGMENTED_POOL: + return "Fragmented pool"; default: return "Unknown error"; } diff --git a/Gems/Atom/RHI/Vulkan/gem.json b/Gems/Atom/RHI/Vulkan/gem.json deleted file mode 100644 index fb89def7b5..0000000000 --- a/Gems/Atom/RHI/Vulkan/gem.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "gem_name": "Atom_RHI_Vulkan", - "Dependencies": [ - { - "Uuid": "fb7f322c8bdb42228d9e155c954f98bd", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RHI" - } - ], - "GemFormatVersion": 4, - "Uuid": "150d40d376124d98a388dfe890551c03", - "Name": "Atom_RHI_Vulkan", - "DisplayName": "Atom RHI.Vulkan", - "Version": "0.1.0", - "Summary": "The Vulkan backend for the Atom Render Hardware Interface", - "Tags": ["Atom", "RHI", "Vulkan"], - "LinkType": "Dynamic", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Private", - "Type": "GameModule" - }, - { - "Name": "Reflect", - "Type": "StaticLib" - }, - { - "Name": "Glad", - "Type": "StaticLib" - }, - { - "Name": "Builders", - "Type": "EditorModule" - } - ] -} diff --git a/Gems/Atom/RHI/gem.json b/Gems/Atom/RHI/gem.json deleted file mode 100644 index 96dabe2c91..0000000000 --- a/Gems/Atom/RHI/gem.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "gem_name": "Atom_RHI", - "GemFormatVersion": 4, - "Uuid": "fb7f322c8bdb42228d9e155c954f98bd", - "Name": "Atom_RHI", - "DisplayName": "Atom RHI", - "Version": "0.1.0", - "Summary": "The Atom Render Hardware Interface", - "Tags": ["Atom", "RHI"], - "LinkType": "Dynamic", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Private", - "Type": "GameModule" - }, - { - "Name": "Public", - "Type": "StaticLib" - }, - { - "Name": "Reflect", - "Type": "StaticLib" - }, - { - "Name": "Tests", - "Type": "Standalone" - } - ] -} diff --git a/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/ShaderResourceGroups/BindlessPrototypeSrg.azsli b/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/ShaderResourceGroups/BindlessPrototypeSrg.azsli deleted file mode 100644 index 7304af9e1e..0000000000 --- a/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/ShaderResourceGroups/BindlessPrototypeSrg.azsli +++ /dev/null @@ -1,136 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#pragma once - -// NOTE: Nest this array, so Azslc will output a size of the bindingslot to 1 -struct FloatBuffer -{ - float buffer; -}; - -// Listed on update frequency -ShaderResourceGroupSemantic FrequencyPerScene -{ - FrequencyId = 6; -}; - -ShaderResourceGroupSemantic FloatBufferSemanticId -{ - FrequencyId = 7; -}; - -ShaderResourceGroup ImageSrg : FrequencyPerScene -{ - Sampler m_sampler - { - MaxAnisotropy = 16; - AddressU = Wrap; - AddressV = Wrap; - AddressW = Wrap; - }; - - // Array of textures - Texture2D m_textureArray[]; -} - -ShaderResourceGroup FloatBufferSrg : FloatBufferSemanticId -{ - StructuredBuffer m_floatBuffer; -}; - -// Helper functions to read data from the FloatBuffer. The FloatBuffer is accessed with a descriptor and a index. -// The descriptor holds the initial offset within the FloatBuffer, and the index is a sub-index, which increments with each property that is being read. -// The data needs to be read in the same order as it is allocated on the host. - -// All float setters -void SetFloat(out float outFloat, in uint desc, inout uint index) -{ - outFloat = FloatBufferSrg::m_floatBuffer[desc + index + 0].buffer; - index += 1; -} - -void SetFloat2(out float2 outFloat, in uint desc, inout uint index) -{ - outFloat.x = FloatBufferSrg::m_floatBuffer[desc + index + 0].buffer; - outFloat.y = FloatBufferSrg::m_floatBuffer[desc + index + 1].buffer; - index += 2; -} - -void SetFloat3(out float3 outFloat, in uint desc, inout uint index) -{ - outFloat.x = FloatBufferSrg::m_floatBuffer[desc + index + 0].buffer; - outFloat.y = FloatBufferSrg::m_floatBuffer[desc + index + 1].buffer; - outFloat.z = FloatBufferSrg::m_floatBuffer[desc + index + 2].buffer; - index += 3; -} - -void SetFloat4(out float4 outFloat, in uint desc, inout uint index) -{ - outFloat.x = FloatBufferSrg::m_floatBuffer[desc + index + 0].buffer; - outFloat.y = FloatBufferSrg::m_floatBuffer[desc + index + 1].buffer; - outFloat.z = FloatBufferSrg::m_floatBuffer[desc + index + 2].buffer; - outFloat.w = FloatBufferSrg::m_floatBuffer[desc + index + 3].buffer; - index += 4; -} - -// All matrix setters -void SetFloat4x4(out float4x4 outFloat, in uint desc, inout uint index) -{ - [unroll(4)] - for(uint i = 0; i < 4; i++) - { - SetFloat4(outFloat[i], desc, index); - } -} - -// All uint setters -void SetUint(out uint outUInt, in uint desc, inout uint index) -{ - outUInt = asuint(FloatBufferSrg::m_floatBuffer[desc + index + 0].buffer); - index += 1; -} - -void SetUint2(out uint2 outUInt, in uint desc, inout uint index) -{ - outUInt.x = asuint(FloatBufferSrg::m_floatBuffer[desc + index + 0].buffer); - outUInt.y = asuint(FloatBufferSrg::m_floatBuffer[desc + index + 1].buffer); - index += 2; -} - -void SetUint3(out uint3 outUInt, in uint desc, inout uint index) -{ - outUInt.x = asuint(FloatBufferSrg::m_floatBuffer[desc + index + 0].buffer); - outUInt.y = asuint(FloatBufferSrg::m_floatBuffer[desc + index + 1].buffer); - outUInt.z = asuint(FloatBufferSrg::m_floatBuffer[desc + index + 2].buffer); - index += 3; -} - -void SetUint4(out uint4 outUInt, in uint desc, inout uint index) -{ - outUInt.x = asuint(FloatBufferSrg::m_floatBuffer[desc + index + 0].buffer); - outUInt.y = asuint(FloatBufferSrg::m_floatBuffer[desc + index + 1].buffer); - outUInt.z = asuint(FloatBufferSrg::m_floatBuffer[desc + index + 2].buffer); - outUInt.w = asuint(FloatBufferSrg::m_floatBuffer[desc + index + 3].buffer); - index += 4; -} - -// All double setters -void SetDouble(out double outDouble, in uint desc, inout uint index) -{ - uint lowBits; - uint highBits; - SetUint(highBits, desc, index); - SetUint(lowBits, desc, index); - - outDouble = asdouble(lowBits, highBits); -} diff --git a/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake b/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake index 47bece22c9..b7dd571002 100644 --- a/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake +++ b/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake @@ -21,7 +21,6 @@ set(FILES Shader/ImagePreview.shader ShaderLib/Atom/RPI/Math.azsli ShaderLib/Atom/RPI/TangentSpace.azsli - ShaderLib/Atom/RPI/ShaderResourceGroups/BindlessPrototypeSrg.azsli ShaderLib/Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli ShaderLib/Atom/RPI/ShaderResourceGroups/DefaultObjectSrg.azsli ) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFactory.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFactory.h index dc39687a97..2252838541 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFactory.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFactory.h @@ -89,7 +89,7 @@ namespace AZ // --- Members --- // Cached pointer to the pass library to simplify code - PassLibrary* m_passLibary = nullptr; + PassLibrary* m_passLibrary = nullptr; // ClassNames are used to look up PassCreators. This list is 1-to-1 with the PassCreator list AZStd::vector m_passClassNames; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h index 283cea7c0a..d26f15096b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h @@ -56,6 +56,9 @@ namespace AZ // The list of passes created from this template AZStd::vector m_passes; + + // The pass templates mapping asset id which this template is coming from. + Data::AssetId m_mappingAssetId; }; typedef AZStd::unordered_map TemplateEntriesByName; @@ -105,7 +108,7 @@ namespace AZ bool LoadPassAsset(const Name& name, const Data::Asset& passAsset, bool hotReloading = false); // Find asset with specified pass template asset id and load pass template from the asset. - void LoadPassAsset(const Name& name, const Data::AssetId& passAssetId); + bool LoadPassAsset(const Name& name, const Data::AssetId& passAssetId); // Data::AssetBus::Handler overrides... void OnAssetReloaded(Data::Asset asset) override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h index d37868025c..fd30f4f406 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h @@ -55,6 +55,10 @@ namespace AZ //! Initializes the PassSystem and the Root Pass and creates the Pass InstanceDatabase void Init(); + //! Initialize and load pass templates + //! This function need to be called after Init() + void InitPassTemplates(); + //! Deletes the Root Pass and shuts down the PassSystem void Shutdown(); @@ -74,6 +78,7 @@ namespace AZ void SetHotReloading(bool hotReloading) override; void SetTargetedPassDebuggingName(const AZ::Name& targetPassName) override; const AZ::Name& GetTargetedPassDebuggingName() const override; + void ConnectEvent(OnReadyLoadTemplatesEvent::Handler& handler) override; // PassSystemInterface factory related functions... void AddPassCreator(Name className, PassCreator createFunction) override; @@ -139,6 +144,9 @@ namespace AZ // Counts the number of passes int32_t m_passCounter = 0; + + // Events + OnReadyLoadTemplatesEvent m_loadTemplatesEvent; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h index 82d52ab5a2..1224bf9545 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h @@ -64,7 +64,10 @@ namespace AZ //! initializing a scene; virtual void ProcessQueuedChanges() = 0; - //! Load pass templates listed in a name-assetid mapping asset + //! Load pass templates listed in a name-assetid mapping asset + //! This function should be called before the render pipelines which use templates from this mappings are created. + //! To load pass template mapping before any render pipelines are created, use OnReadyLoadTemplatesEvent::Handler to + //! load desired pass template mappings virtual bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath) = 0; //! Writes a pass template to a .pass file which can then be used as a pass asset. Useful for @@ -148,6 +151,12 @@ namespace AZ //! Find the SwapChainPass associated with window Handle virtual SwapChainPass* FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const = 0; + using OnReadyLoadTemplatesEvent = AZ::Event<>; + //! Connect a handler to listen to the event that the pass system is ready to load pass templates + //! The event is triggered when pass system is initialized and asset system is ready. + //! The handler can add new pass templates or load pass template mappings from assets + virtual void ConnectEvent(OnReadyLoadTemplatesEvent::Handler& handler) = 0; + private: // These functions are only meant to be used by the Pass class @@ -164,17 +173,10 @@ namespace AZ virtual void UnregisterPass(Pass* pass) = 0; }; - - //! Notifications of the pass system such attachments were rebuilt, pass tree changes - class PassSystemNotificiations - : public AZ::EBusTraits + + namespace PassSystemEvents { - public: - - //! Notify when any pass's attachment was rebuilt - virtual void OnPassAttachmentsBuilt() = 0; - }; + } - using PassSystemNotificiationBus = AZ::EBus; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h index d6146d3760..aad099dc23 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/View.h @@ -91,6 +91,8 @@ namespace AZ const AZ::Matrix4x4& GetViewToWorldMatrix() const; const AZ::Matrix4x4& GetViewToClipMatrix() const; const AZ::Matrix4x4& GetWorldToClipMatrix() const; + //! Get the camera's world transform, converted from the viewToWorld matrix's native y-up to z-up + AZ::Transform GetCameraTransform() const; //! Finalize draw lists in this view. This function should only be called when all //! draw packets for current frame are added. diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h index bc7e5a4b1d..377c1d5c4e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/ViewportContextBus.h @@ -92,6 +92,8 @@ namespace AZ virtual ViewPtr GetCurrentView(const Name& contextName) const = 0; }; + using ViewportContextRequests = AZ::Interface; + class ViewportContextManagerNotifications : public AZ::EBusTraits { diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Asset/AssetUtils.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Asset/AssetUtils.h index 5a169a9e61..1a8ddb5d97 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Asset/AssetUtils.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Asset/AssetUtils.h @@ -137,13 +137,19 @@ namespace AZ template Data::Asset LoadCriticalAsset(const AZStd::string& assetFilePath, TraceLevel reporting) { - AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown; - AzFramework::AssetSystemRequestBus::BroadcastResult(status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, assetFilePath); - - if (status != AzFramework::AssetSystem::AssetStatus_Compiled) + bool apConnected = false; + AzFramework::AssetSystemRequestBus::BroadcastResult( + apConnected, &AzFramework::AssetSystemRequestBus::Events::ConnectedWithAssetProcessor); + if (apConnected) { - AssetUtilsInternal::ReportIssue(reporting, AZStd::string::format("Could not compile asset '%s'", assetFilePath.c_str()).c_str()); - return {}; + AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown; + AzFramework::AssetSystemRequestBus::BroadcastResult( + status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, assetFilePath); + if (status != AzFramework::AssetSystem::AssetStatus_Compiled) + { + AssetUtilsInternal::ReportIssue(reporting, AZStd::string::format("Could not compile asset '%s'", assetFilePath.c_str()).c_str()); + return {}; + } } return LoadAssetByProductPath(assetFilePath.c_str(), reporting); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/RPISystemDescriptor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/RPISystemDescriptor.h index 1223f984fd..3d0b9f4f63 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/RPISystemDescriptor.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/RPISystemDescriptor.h @@ -44,9 +44,6 @@ namespace AZ //! The path of the only one view srg asset for the RPI system. This is used to create any RPI::View. AZStd::string m_viewSrgAssetPath = "shaderlib/viewsrg_viewsrg.azsrg"; - //! Path of pass templates' name-assetid mapping file. - AZStd::string m_passTemplatesMappingPath = "Passes/PassTemplates.azasset"; - ImageSystemDescriptor m_imageSystemDescriptor; GpuQuerySystemDescriptor m_gpuQuerySystemDescriptor; DynamicDrawSystemDescriptor m_dynamicDrawSystemDescriptor; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFactory.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFactory.cpp index 6a2e756403..90df206a3d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFactory.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFactory.cpp @@ -36,7 +36,7 @@ namespace AZ { void PassFactory::Init(PassLibrary* passLibrary) { - m_passLibary = passLibrary; + m_passLibrary = passLibrary; AddCorePasses(); } @@ -125,7 +125,7 @@ namespace AZ Ptr PassFactory::CreatePassFromTemplate(Name templateName, Name passName) { - const AZStd::shared_ptr& passTemplate = m_passLibary->GetPassTemplate(templateName); + const AZStd::shared_ptr& passTemplate = m_passLibrary->GetPassTemplate(templateName); if (passTemplate == nullptr) { AZ_Error("PassFactory", false, "FAILED TO CREATE PASS [%s]. Could not find pass template [%s]", passName.GetCStr(), templateName.GetCStr()); @@ -143,7 +143,7 @@ namespace AZ return nullptr; } - const AZStd::shared_ptr& passTemplate = m_passLibary->GetPassTemplate(passRequest->m_templateName); + const AZStd::shared_ptr& passTemplate = m_passLibrary->GetPassTemplate(passRequest->m_templateName); if (passTemplate == nullptr) { AZ_Error("PassFactory", false, "FAILED TO CREATE PASS [%s]. Could not find pass template [%s]", passRequest->m_passName.GetCStr(), passRequest->m_templateName.GetCStr()); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp index 6c1f96e414..346ccc7d76 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp @@ -262,6 +262,7 @@ namespace AZ } // Handle template mapping reload + // Note: it's a known issue that when mapping asset got reloaded, we only handle the new entries Data::Asset templateMappings = { asset.GetAs(), AZ::Data::AssetLoadBehavior::PreLoad }; if (templateMappings) { @@ -310,7 +311,7 @@ namespace AZ return success; } - void PassLibrary::LoadPassAsset(const Name& name, const Data::AssetId& passAssetId) + bool PassLibrary::LoadPassAsset(const Name& name, const Data::AssetId& passAssetId) { Data::Asset passAsset; if (passAssetId.IsValid()) @@ -325,11 +326,20 @@ namespace AZ { Data::AssetBus::MultiHandler::BusConnect(passAssetId); } + + return loadSuccess; } bool PassLibrary::LoadPassTemplateMappings(const AZStd::string& templateMappingPath) { Data::Asset mappingAsset = AssetUtils::LoadCriticalAsset(templateMappingPath.c_str(), AssetUtils::TraceLevel::Error); + + if (m_templateMappingAssets.find(mappingAsset.GetId()) != m_templateMappingAssets.end()) + { + AZ_Warning("PassLibrary", false, "Pass template mapping [%s] was already loaded", mappingAsset.GetHint().c_str()); + return true; + } + bool success = LoadPassTemplateMappings(mappingAsset); if (success) { @@ -350,13 +360,29 @@ namespace AZ } const AZStd::unordered_map& assetMapping = mappings->GetAssetMapping(); + Data::AssetId mappingAssetId = mappingAsset.GetId(); m_templateEntries.reserve(m_templateEntries.size() + assetMapping.size()); for (const auto& assetInfo : assetMapping) { Name templateName = AZ::Name(assetInfo.first); if (!HasTemplate(templateName)) { - LoadPassAsset(templateName, assetInfo.second); + bool loaded = LoadPassAsset(templateName, assetInfo.second); + if (loaded) + { + auto& entry = m_templateEntries[templateName]; + entry.m_mappingAssetId = mappingAssetId; + } + } + else + { + // Report a warning if the template was setup in another mappping asset. + // We won't report a warning if the template was loaded from same asset. This only happens when the asset got reloaded. + if (m_templateEntries[templateName].m_mappingAssetId != mappingAssetId) + { + AZ_Warning("PassLibrary", false, "Template [%s] was aleady added to the library. Duplicated template from [%s]", + templateName.GetCStr(), mappingAsset.ToString().c_str()); + } } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index 706d759231..448c28f202 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -100,6 +100,12 @@ namespace AZ m_rootPass->m_flags.m_partOfHierarchy = true; } + void PassSystem::InitPassTemplates() + { + AZ_Assert(m_rootPass, "PassSystem::Init() need to be called"); + m_loadTemplatesEvent.Signal(); + } + bool PassSystem::LoadPassTemplateMappings(const AZStd::string& templateMappingPath) { return m_passLibrary.LoadPassTemplateMappings(templateMappingPath); @@ -213,7 +219,6 @@ namespace AZ DebugPrintPassHierarchy(); } #endif - PassSystemNotificiationBus::Broadcast(&PassSystemNotificiationBus::Events::OnPassAttachmentsBuilt); } m_isBuilding = false; @@ -323,6 +328,11 @@ namespace AZ return m_targetedPassDebugName; } + void PassSystem::ConnectEvent(OnReadyLoadTemplatesEvent::Handler& handler) + { + handler.Connect(m_loadTemplatesEvent); + } + // --- Pass Factory Functions --- void PassSystem::AddPassCreator(Name className, PassCreator createFunction) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index 5cd6f93715..44be2dabeb 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -369,12 +369,7 @@ namespace AZ m_bufferSystem.Init(); m_dynamicDraw.Init(m_descriptor.m_dynamicDrawSystemDescriptor); - // Have pass system load default pass template mapping - bool passSystemReady = m_passSystem.LoadPassTemplateMappings(m_descriptor.m_passTemplatesMappingPath); - if (!passSystemReady) - { - return; - } + m_passSystem.InitPassTemplates(); m_systemAssetsInitialized = true; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index a66471e038..7e33750eb5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -99,7 +99,6 @@ namespace AZ { WaitAndCleanCompletionJob(m_simulationCompletion); SceneRequestBus::Handler::BusDisconnect(); - DisableAllFeatureProcessors(); // Remove all the render pipelines. Need to process queued changes with pass system before and after remove render pipelines AZ::RPI::PassSystemInterface::Get()->ProcessQueuedChanges(); @@ -111,6 +110,8 @@ namespace AZ m_pipelines.clear(); AZ::RPI::PassSystemInterface::Get()->ProcessQueuedChanges(); + Deactivate(); + delete m_cullingScene; } @@ -138,8 +139,11 @@ namespace AZ void Scene::Deactivate() { - AZ_Assert(m_activated, "Not activated"); - + if (!m_activated) + { + return; + } + for (auto& fp : m_featureProcessors) { fp->Deactivate(); @@ -240,7 +244,6 @@ namespace AZ fp->Deactivate(); } m_featureProcessors.clear(); - m_pipelineStatesLookup.clear(); } FeatureProcessor* Scene::GetFeatureProcessor(const FeatureProcessorId& featureProcessorId) const diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp index e3f41cbda9..21a46693d5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/View.cpp @@ -110,6 +110,15 @@ namespace AZ InvalidateSrg(); } + AZ::Transform View::GetCameraTransform() const + { + static const Quaternion yUpToZUp = Quaternion::CreateRotationX(-AZ::Constants::HalfPi); + return AZ::Transform::CreateFromQuaternionAndTranslation( + Quaternion::CreateFromMatrix4x4(m_viewToWorldMatrix) * yUpToZUp, + m_viewToWorldMatrix.GetTranslation() + ).GetOrthogonalized(); + } + void View::SetCameraTransform(const AZ::Matrix3x4& cameraTransform) { m_position = cameraTransform.GetTranslation(); @@ -118,7 +127,7 @@ namespace AZ // is in a Z-up world and an identity matrix means that it faces along the positive-Y axis and Z is up. // An identity view matrix on the other hand looks along the negative Z-axis. // So we adjust for this by rotating the camera world matrix by 90 degrees around the X axis. - AZ::Matrix3x4 zUpToYUp = AZ::Matrix3x4::CreateRotationX(AZ::Constants::HalfPi); + static AZ::Matrix3x4 zUpToYUp = AZ::Matrix3x4::CreateRotationX(AZ::Constants::HalfPi); AZ::Matrix3x4 yUpWorld = cameraTransform * zUpToYUp; float viewToWorldMatrixRaw[16] = { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp index 0dae5ac2d0..22287238e9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/ViewportContext.cpp @@ -194,12 +194,7 @@ namespace AZ AZ::Transform ViewportContext::GetCameraTransform() const { - const Matrix4x4& worldToViewMatrix = GetDefaultView()->GetViewToWorldMatrix(); - const Quaternion zUpToYUp = Quaternion::CreateRotationX(-AZ::Constants::HalfPi); - return AZ::Transform::CreateFromQuaternionAndTranslation( - Quaternion::CreateFromMatrix4x4(worldToViewMatrix) * zUpToYUp, - worldToViewMatrix.GetTranslation() - ).GetOrthogonalized(); + return GetDefaultView()->GetCameraTransform(); } void ViewportContext::SetCameraTransform(const AZ::Transform& transform) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantTreeAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantTreeAsset.cpp index 25ba5aa837..f550a6f2ca 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantTreeAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantTreeAsset.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -40,15 +41,12 @@ namespace AZ Data::AssetId ShaderVariantTreeAsset::GetShaderVariantTreeAssetIdFromShaderAssetId(const Data::AssetId& shaderAssetId) { //From the shaderAssetId We can deduce the path of the shader asset, and from the path of the shader asset we can deduce the path of the ShaderVariantTreeAsset. - AZStd::string shaderAssetPath; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(shaderAssetPath - , &AZ::Data::AssetCatalogRequests::GetAssetPathById - , shaderAssetId); - - AZStd::string shaderAssetPathRoot; - AZStd::string shaderAssetPathName; - AzFramework::StringFunc::Path::Split(shaderAssetPath.c_str(), nullptr /*drive*/, &shaderAssetPathRoot, &shaderAssetPathName, nullptr /*extension*/); - + AZ::IO::FixedMaxPath shaderAssetPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult(shaderAssetPath.Native(), &AZ::Data::AssetCatalogRequests::GetAssetPathById + , shaderAssetId); + AZ::IO::FixedMaxPath shaderAssetPathRoot = shaderAssetPath.ParentPath(); + AZ::IO::FixedMaxPath shaderAssetPathName = shaderAssetPath.Stem(); + AZStd::string shaderVariantTreeAssetDir; AzFramework::StringFunc::Path::Join(ShaderVariantTreeAsset::CommonSubFolderLowerCase, shaderAssetPathRoot.c_str(), shaderVariantTreeAssetDir); AZStd::string shaderVariantTreeAssetFilename = AZStd::string::format("%s.%s", shaderAssetPathName.c_str(), ShaderVariantTreeAsset::Extension); @@ -63,8 +61,7 @@ namespace AZ { // If the game project did not customize the shadervariantlist, let's see if the original author of the .shader file // provided a shadervariantlist. - shaderVariantTreeAssetDir = shaderAssetPathRoot; - AzFramework::StringFunc::Path::Join(shaderVariantTreeAssetDir.c_str(), shaderVariantTreeAssetFilename.c_str(), shaderVariantTreeAssetPath); + AzFramework::StringFunc::Path::Join(shaderAssetPathRoot.c_str(), shaderVariantTreeAssetFilename.c_str(), shaderVariantTreeAssetPath); AZ::Data::AssetCatalogRequestBus::BroadcastResult(shaderVariantTreeAssetId, &AZ::Data::AssetCatalogRequests::GetAssetIdByPath , shaderVariantTreeAssetPath.c_str(), AZ::Data::s_invalidAssetType, false); } diff --git a/Gems/Atom/RPI/gem.json b/Gems/Atom/RPI/gem.json deleted file mode 100644 index 4a144fe53f..0000000000 --- a/Gems/Atom/RPI/gem.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "gem_name": "Atom_RPI", - "Dependencies": [ - { - "Uuid": "fb7f322c8bdb42228d9e155c954f98bd", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RHI" - } - ], - "GemFormatVersion": 4, - "Uuid": "a218db9eb2114477b46600fea4441a6c", - "Name": "Atom_RPI", - "DisplayName": "Atom RPI", - "Version": "0.1.0", - "Summary": "The Atom Render Pipeline Interface", - "Tags": ["Atom", "RPI"], - "LinkType": "Dynamic", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Builders", - "Type": "EditorModule" - }, - { - "Name": "Private", - "Type": "GameModule" - }, - { - "Name": "Public", - "Type": "StaticLib" - }, - { - "Name": "Reflect", - "Type": "StaticLib" - }, - { - "Name": "Editor", - "Type": "EditorModule", - "Extends": "Private" - }, - { - "Name": "Tests", - "Type": "Standalone" - } - ] -} diff --git a/Gems/Atom/Tools/AtomToolsFramework/gem.json b/Gems/Atom/Tools/AtomToolsFramework/gem.json deleted file mode 100644 index e3caecf339..0000000000 --- a/Gems/Atom/Tools/AtomToolsFramework/gem.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "gem_name": "AtomToolsFramework", - "GemFormatVersion": 4, - "Uuid": "3e0ee0c27f204f5188146baac822d020", - "Name": "AtomToolsFramework", - "DisplayName": "AtomToolsFramework", - "Version": "0.1.0", - "Summary": "AtomToolsFramework", - "Tags": [ "Untagged" ], - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Editor", - "Type": "EditorModule" - } - ] -} diff --git a/Gems/Atom/Tools/MaterialEditor/gem.json b/Gems/Atom/Tools/MaterialEditor/gem.json deleted file mode 100644 index ce913e552c..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/gem.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "gem_name": "MaterialEditor", - "Dependencies": [ - { - "Uuid": "a218db9eb2114477b46600fea4441a6c", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RPI" - }, - { - "Uuid": "b58e5eed0901428ca78544b04dbd61bd", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom Feature Common" - }, - { - "Uuid": "b658359393884c4381c2fe2952b1472a", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "EditorPythonBindings" - }, - { - "Uuid": "3e0ee0c27f204f5188146baac822d020", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "AtomToolsFramework" - }, - { - "Uuid": "9d10b00be96045caa64c705e5772cb64", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "ImageProcessingAtom" - }, - { - "Uuid": "4e981f3b17394f5d84d674fff0f54f4f", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "AtomLyIntegration.CommonFeatures" - } - ], - "GemFormatVersion": 4, - "Uuid": "36f854c260b84d438dde4bc5789d8123", - "Name": "MaterialEditor", - "DisplayName": "Material Editor", - "Version": "0.1.0", - "LinkType": "Dynamic", - "Summary": "Tools for editing Atom materials", - "Tags": ["Untagged"], - "IconPath": "preview.svg", - "Modules": [ - ] -} diff --git a/Gems/Atom/Tools/ShaderManagementConsole/gem.json b/Gems/Atom/Tools/ShaderManagementConsole/gem.json deleted file mode 100644 index 8cf05dc725..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/gem.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "gem_name": "ShaderManagementConsole", - "Dependencies": [ - { - "Uuid": "a218db9eb2114477b46600fea4441a6c", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RPI" - }, - { - "Uuid": "b658359393884c4381c2fe2952b1472a", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "EditorPythonBindings" - }, - { - "Uuid": "3e0ee0c27f204f5188146baac822d020", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "AtomToolsFramework" - }, - { - "Uuid": "9d10b00be96045caa64c705e5772cb64", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "ImageProcessingAtom" - }, - { - "Uuid": "4e981f3b17394f5d84d674fff0f54f4f", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "AtomLyIntegration.CommonFeatures" - } - ], - "GemFormatVersion": 4, - "Uuid": "77967ca0a6264a8e95b138a31bf78fe0", - "Name": "ShaderManagementConsole", - "DisplayName": "Shader Management Console", - "Version": "0.1.0", - "LinkType": "Dynamic", - "Summary": "Shader Management Console", - "IconPath": "preview.svg", - "Modules": [ - ] -} diff --git a/Gems/Atom/Utils/gem.json b/Gems/Atom/Utils/gem.json deleted file mode 100644 index 7f9ae3041a..0000000000 --- a/Gems/Atom/Utils/gem.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "gem_name": "Atom_Utils", - "Dependencies": [ - { - "Uuid": "fb7f322c8bdb42228d9e155c954f98bd", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RHI" - } - ], - "GemFormatVersion": 4, - "Uuid": "5c850809e890497c82cd9999ecb33250", - "Name": "Atom_Utils", - "DisplayName": "Atom.Utils", - "Version": "0.1.0", - "Summary": "Various utility classes used by Atom.", - "Tags": ["Atom", "Utils"], - "LinkType": "Dynamic", - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Utils", - "Type": "StaticLib" - }, - { - "Name": "Tests", - "Type": "Standalone" - } - ] -} diff --git a/Gems/Atom/gem.json b/Gems/Atom/gem.json new file mode 100644 index 0000000000..c74a9013f3 --- /dev/null +++ b/Gems/Atom/gem.json @@ -0,0 +1,3 @@ +{ + "gem_name": "Atom" +} diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt index 33873e0dfa..c431746b40 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt @@ -63,6 +63,7 @@ ly_add_target( Gem::EMotionFX_Atom Gem::ImguiAtom Gem::AtomFont + Gem::AtomViewportDisplayInfo ) if(PAL_TRAIT_BUILD_HOST_TOOLS) @@ -104,5 +105,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::ImguiAtom Gem::AtomFont Gem::AtomToolsFramework.Editor + Gem::AtomViewportDisplayInfo ) endif() diff --git a/Gems/AtomLyIntegration/AtomBridge/gem.json b/Gems/AtomLyIntegration/AtomBridge/gem.json deleted file mode 100644 index 17cb022932..0000000000 --- a/Gems/AtomLyIntegration/AtomBridge/gem.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "gem_name": "Atom_AtomBridge", - "Dependencies": [ - { - "Uuid": "a218db9eb2114477b46600fea4441a6c", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom RPI" - }, - { - "Uuid": "c7ff89ad6e8b4b45b2fadef2bcf12d6e", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom_Bootstrap" - } - ], - "GemFormatVersion": 4, - "Uuid": "b55b2738aa4a46c8b034fe98e6e5158b", - "Name": "Atom_AtomBridge", - "DisplayName": "Atom.AtomBridge", - "Version": "0.1.0", - "Summary": "A short description of my Gem.", - "Tags": ["Untagged"], - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - }, - { - "Name": "Editor", - "Type": "EditorModule", - "Extends": "GameModule" - } - ] -} diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h index fd66534197..1e224d6090 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h @@ -207,11 +207,15 @@ namespace AZ // AzFramework::FontDrawInterface implementation void DrawScreenAlignedText2d( const AzFramework::TextDrawParameters& params, - const AZStd::string_view& string) override; + AZStd::string_view text) override; void DrawScreenAlignedText3d( const AzFramework::TextDrawParameters& params, - const AZStd::string_view& string) override; + AZStd::string_view text) override; + + AZ::Vector2 GetTextSize( + const AzFramework::TextDrawParameters& params, + AZStd::string_view text) override; public: FFont(AtomFont* atomFont, const char* fontName); @@ -233,7 +237,7 @@ namespace AZ void Prepare(const char* str, bool updateTexture, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize); void DrawStringUInternal( const RHI::Viewport& viewport, - RPI::ViewportContext* viewportContext, + RPI::ViewportContextPtr viewportContext, float x, float y, float z, @@ -282,6 +286,16 @@ namespace AZ RPI::WindowContextSharedPtr GetDefaultWindowContext() const; RPI::ViewportContextPtr GetDefaultViewportContext() const; + struct DrawParameters + { + TextDrawContext m_ctx; + AZ::Vector2 m_position; + AZ::Vector2 m_size; + AZ::RPI::ViewportContextPtr m_viewportContext; + const AZ::RHI::Viewport* m_viewport; + }; + DrawParameters ExtractDrawParameters(const AzFramework::TextDrawParameters& params, AZStd::string_view text, bool forceCalculateSize); + private: static constexpr uint32_t NumBuffers = 2; static constexpr float WindowScaleWidth = 800.0f; diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp b/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp index 75b0e22e4a..21b57e0908 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp +++ b/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp @@ -280,7 +280,7 @@ void AZ::FFont::DrawString(float x, float y, const char* str, const bool asciiMu return; } - DrawStringUInternal(GetDefaultWindowContext()->GetViewport(), GetDefaultViewportContext().get(), x, y, 1.0f, str, asciiMultiLine, ctx); + DrawStringUInternal(GetDefaultWindowContext()->GetViewport(), GetDefaultViewportContext(), x, y, 1.0f, str, asciiMultiLine, ctx); } void AZ::FFont::DrawString(float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) @@ -290,12 +290,12 @@ void AZ::FFont::DrawString(float x, float y, float z, const char* str, const boo return; } - DrawStringUInternal(GetDefaultWindowContext()->GetViewport(), GetDefaultViewportContext().get(), x, y, z, str, asciiMultiLine, ctx); + DrawStringUInternal(GetDefaultWindowContext()->GetViewport(), GetDefaultViewportContext(), x, y, z, str, asciiMultiLine, ctx); } void AZ::FFont::DrawStringUInternal( const RHI::Viewport& viewport, - RPI::ViewportContext* viewportContext, + RPI::ViewportContextPtr viewportContext, float x, float y, float z, @@ -505,7 +505,7 @@ Vec2 AZ::FFont::GetTextSizeUInternal( } charX = offset.x; - charY += size.y; + charY += size.y * (1.f + ctx.GetLineSpacing()); if (charY > maxH) { @@ -944,7 +944,7 @@ int AZ::FFont::CreateQuadsForText(const RHI::Viewport& viewport, float x, float case '\n': { charX = baseXY.x + offset.x; - charY += size.y; + charY += size.y * (1.f + ctx.GetLineSpacing()); continue; } break; @@ -1675,47 +1675,46 @@ static void SetCommonContextFlags(AZ::TextDrawContext& ctx, const AzFramework::T } } -void AZ::FFont::DrawScreenAlignedText2d( - const AzFramework::TextDrawParameters& params, - const AZStd::string_view& string) +AZ::FFont::DrawParameters AZ::FFont::ExtractDrawParameters(const AzFramework::TextDrawParameters& params, AZStd::string_view text, bool forceCalculateSize) { + DrawParameters internalParams; if (params.m_drawViewportId == AzFramework::InvalidViewportId || - string.empty()) + text.empty()) { - return; + return internalParams; } - //Code mostly duplicated from CRenderer::Draw2dTextWithDepth float posX = params.m_position.GetX(); float posY = params.m_position.GetY(); - AZ::RPI::ViewportContext* viewportContext = AZ::Interface::Get()->GetViewportContextById(params.m_drawViewportId).get(); - const AZ::RHI::Viewport& viewport = viewportContext->GetWindowContext()->GetViewport(); + internalParams.m_viewportContext = AZ::Interface::Get()->GetViewportContextById(params.m_drawViewportId); + const AZ::RHI::Viewport& viewport = internalParams.m_viewportContext->GetWindowContext()->GetViewport(); + internalParams.m_viewport = &viewport; if (params.m_virtual800x600ScreenSize) { posX *= WindowScaleWidth / (viewport.m_maxX - viewport.m_minX); posY *= WindowScaleHeight / (viewport.m_maxY - viewport.m_minY); } - TextDrawContext ctx; - ctx.SetBaseState(GS_NODEPTHTEST); - ctx.SetColor(AZColorToLYColorF(params.m_color)); - ctx.SetCharWidthScale((params.m_monospace || params.m_scaleWithWindow) ? 0.5f : 1.0f); - ctx.EnableFrame(false); - ctx.SetProportional(!params.m_monospace && params.m_scaleWithWindow); - ctx.SetSizeIn800x600(params.m_scaleWithWindow && params.m_virtual800x600ScreenSize); - ctx.SetSize(AZVec2ToLYVec2(UiDraw_TextSizeFactor * params.m_scale)); + internalParams.m_ctx.SetBaseState(GS_NODEPTHTEST); + internalParams.m_ctx.SetColor(AZColorToLYColorF(params.m_color)); + internalParams.m_ctx.SetCharWidthScale((params.m_monospace || params.m_scaleWithWindow) ? 0.5f : 1.0f); + internalParams.m_ctx.EnableFrame(false); + internalParams.m_ctx.SetProportional(!params.m_monospace && params.m_scaleWithWindow); + internalParams.m_ctx.SetSizeIn800x600(params.m_scaleWithWindow && params.m_virtual800x600ScreenSize); + internalParams.m_ctx.SetSize(AZVec2ToLYVec2(UiDraw_TextSizeFactor * params.m_scale)); + internalParams.m_ctx.SetLineSpacing(params.m_lineSpacing); if (params.m_monospace || !params.m_scaleWithWindow) { ScaleCoord(viewport, posX, posY); } if (params.m_hAlign != AzFramework::TextHorizontalAlignment::Left || - params.m_vAlign != AzFramework::TextVerticalAlignment::Top) + params.m_vAlign != AzFramework::TextVerticalAlignment::Top || + forceCalculateSize) { - Vec2 textSize = GetTextSizeUInternal(viewport, string.data(), params.m_multiline, ctx); - + Vec2 textSize = GetTextSizeUInternal(viewport, text.data(), params.m_multiline, internalParams.m_ctx); // If we're using virtual 800x600 coordinates, convert the text size from // pixels to that before using it as an offset. - if (ctx.m_sizeIn800x600) + if (internalParams.m_ctx.m_sizeIn800x600) { float width = 1.0f; float height = 1.0f; @@ -1741,33 +1740,46 @@ void AZ::FFont::DrawScreenAlignedText2d( { posY -= textSize.y; } + internalParams.m_size = AZ::Vector2{textSize.x, textSize.y}; + } + SetCommonContextFlags(internalParams.m_ctx, params); + internalParams.m_ctx.m_drawTextFlags |= eDrawText_2D; + internalParams.m_position = AZ::Vector2{posX, posY}; + return internalParams; +} + +void AZ::FFont::DrawScreenAlignedText2d( + const AzFramework::TextDrawParameters& params, + AZStd::string_view text) +{ + DrawParameters internalParams = ExtractDrawParameters(params, text, false); + if (!internalParams.m_viewportContext) + { + return; } - SetCommonContextFlags(ctx, params); - ctx.m_drawTextFlags |= eDrawText_2D; DrawStringUInternal( - viewport, - viewportContext, - posX, - posY, + *internalParams.m_viewport, + internalParams.m_viewportContext, + internalParams.m_position.GetX(), + internalParams.m_position.GetY(), params.m_position.GetZ(), // Z - string.data(), + text.data(), params.m_multiline, - ctx + internalParams.m_ctx ); } void AZ::FFont::DrawScreenAlignedText3d( const AzFramework::TextDrawParameters& params, - const AZStd::string_view& string) + AZStd::string_view text) { - if (params.m_drawViewportId == AzFramework::InvalidViewportId || - string.empty()) + DrawParameters internalParams = ExtractDrawParameters(params, text, false); + if (!internalParams.m_viewportContext) { return; } - AZ::RPI::ViewportContext* viewportContext = AZ::Interface::Get()->GetViewportContextById(params.m_drawViewportId).get(); - AZ::RPI::ViewPtr currentView = viewportContext->GetDefaultView(); + AZ::RPI::ViewPtr currentView = internalParams.m_viewportContext->GetDefaultView(); if (!currentView) { return; @@ -1779,7 +1791,23 @@ void AZ::FFont::DrawScreenAlignedText3d( ); AzFramework::TextDrawParameters param2d = params; param2d.m_position = positionNDC; - DrawScreenAlignedText2d(param2d, string); + + DrawStringUInternal( + *internalParams.m_viewport, + internalParams.m_viewportContext, + internalParams.m_position.GetX(), + internalParams.m_position.GetY(), + params.m_position.GetZ(), // Z + text.data(), + params.m_multiline, + internalParams.m_ctx + ); +} + +AZ::Vector2 AZ::FFont::GetTextSize(const AzFramework::TextDrawParameters& params, AZStd::string_view text) +{ + DrawParameters sizeParams = ExtractDrawParameters(params, text, true); + return sizeParams.m_size; } #endif //USE_NULLFONT_ALWAYS diff --git a/Gems/AtomLyIntegration/AtomFont/gem.json b/Gems/AtomLyIntegration/AtomFont/gem.json deleted file mode 100644 index d5ca7834fd..0000000000 --- a/Gems/AtomLyIntegration/AtomFont/gem.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "gem_name": "AtomFont", - "Dependencies": [ - ], - "GemFormatVersion": 4, - "Uuid": "{16ef36f2e3fc4e6ca15fcc484ec895fc}", - "Name": "AtomLyIntegration_AtomFont", - "DisplayName": "AtomLyIntegration.AtomFont", - "Version": "0.1.0", - "LinkType": "Dynamic", - "Summary": "Implement ICryFont & IFFont interfaces on Atom. Uses duplicated CryFont code", - "Tags": [ "Atom", "Font" ], - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - } - ] -} diff --git a/Gems/AtomLyIntegration/AtomImGuiTools/gem.json b/Gems/AtomLyIntegration/AtomImGuiTools/gem.json deleted file mode 100644 index 4d399e56e2..0000000000 --- a/Gems/AtomLyIntegration/AtomImGuiTools/gem.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "gem_name": "AtomImGuiTools", - "GemFormatVersion": 4, - "Uuid": "1a9d10de1b8a45fab2fe04517f613962", - "Name": "AtomImGuiTools", - "DisplayName": "Atom ImGui Tools", - "Version": "0.1.0", - "Summary": "ImGui tools for Atom renderer.", - "Tags": [ "Atom", "ImGui" ], - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - } - ], - "Dependencies": [ - { - "Uuid": "9986e22e14184f2fb6bb1e7dd185b2f9", - "VersionConstraints": [ - "~>0.1" - ], - "_comment": "ImGui.Atom" - } - ] -} diff --git a/Code/CryEngine/CrySystem/Platform/Linux/platform_linux_files.cmake b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/CMakeLists.txt similarity index 95% rename from Code/CryEngine/CrySystem/Platform/Linux/platform_linux_files.cmake rename to Gems/AtomLyIntegration/AtomViewportDisplayInfo/CMakeLists.txt index 5714be5dfb..20a680bce9 100644 --- a/Code/CryEngine/CrySystem/Platform/Linux/platform_linux_files.cmake +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/CMakeLists.txt @@ -9,5 +9,4 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -set(FILES -) +add_subdirectory(Code) diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt new file mode 100644 index 0000000000..de4ee9b4b5 --- /dev/null +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt @@ -0,0 +1,52 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +ly_add_target( + NAME AtomViewportDisplayInfo GEM_MODULE + NAMESPACE Gem + FILES_CMAKE + atomviewportdisplayinfo_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PRIVATE + AZ::AzCore + AZ::AtomCore + Legacy::CryCommon + Gem::Atom_RHI.Reflect + Gem::Atom_RPI.Public +) + +################################################################################ +# Tests +################################################################################ +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + ly_add_target( + NAME AtomViewportDisplayInfo.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + atomviewportdisplayinfo_test_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Include + Tests + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + ) + ly_add_googletest( + NAME Gem::AtomViewportDisplayInfo.Tests + ) +endif() + diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Include/AtomLyIntegration/AtomViewportDisplayInfo/AtomViewportInfoDisplayBus.h b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Include/AtomLyIntegration/AtomViewportDisplayInfo/AtomViewportInfoDisplayBus.h new file mode 100644 index 0000000000..ae9359d9d3 --- /dev/null +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Include/AtomLyIntegration/AtomViewportDisplayInfo/AtomViewportInfoDisplayBus.h @@ -0,0 +1,61 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once +#include +#include + +namespace AZ +{ + namespace AtomBridge + { + //! The level of information to display in the viewport info display overlay. + enum class ViewportInfoDisplayState : int + { + NoInfo = 0, + NormalInfo = 1, + FullInfo = 2, + CompactInfo = 3, + Invalid + }; + + //! This bus is used to request changes to the viewport info display overlay. + class AtomViewportInfoDisplayRequests + : public AZ::EBusTraits + { + public: + static const AZ::EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single; + + //! Gets the current viewport info overlay state. + virtual ViewportInfoDisplayState GetDisplayState() const = 0; + //! Sets the current viewport info overlay state. + //! The overlay will be drawn to the default viewport context every frame, if enabled. + virtual void SetDisplayState(ViewportInfoDisplayState state) = 0; + }; + + using AtomViewportInfoDisplayRequestBus = AZ::EBus; + + //! This bus is used to listen for state changes in the viewport info display overlay. + class AtomViewportInfoDisplayNotifications + : public AZ::EBusTraits + { + public: + static const AZ::EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single; + + //! Called when the ViewportInfoDisplayState (via the r_displayInfo CVar) has changed. + virtual void OnViewportInfoDisplayStateChanged([[maybe_unused]]ViewportInfoDisplayState state){} + }; + + using AtomViewportInfoDisplayNotificationBus = AZ::EBus; + } +} diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp new file mode 100644 index 0000000000..672c26a9ab --- /dev/null +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp @@ -0,0 +1,316 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include "AtomViewportDisplayInfoSystemComponent.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace AZ::Render +{ + AZ_CVAR(int, r_displayInfo, 1, [](const int& newDisplayInfoVal)->void + { + // Forward this event to the system component so it can update accordingly. + // This callback only gets triggered by console commands, so this will not recurse. + AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast( + &AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState, + aznumeric_cast(newDisplayInfoVal) + ); + }, AZ::ConsoleFunctorFlags::DontReplicate, + "Toggles debugging information display.\n" + "Usage: r_displayInfo [0=off/1=show/2=enhanced/3=compact]" + ); + AZ_CVAR(float, r_fpsCalcInterval, 1.0f, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "The time period over which to calculate the framerate for r_displayInfo." + ); + + void AtomViewportDisplayInfoSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serialize = azrtti_cast(context)) + { + serialize->Class() + ->Version(0) + ; + + if (AZ::EditContext* ec = serialize->GetEditContext()) + { + ec->Class("Viewport Display Info", "Manages debug viewport information through r_displayInfo") + ->ClassElement(Edit::ClassElements::EditorData, "") + ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) + ->Attribute(Edit::Attributes::AutoExpand, true) + ; + } + } + } + + void AtomViewportDisplayInfoSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC("ViewportDisplayInfoService")); + } + + void AtomViewportDisplayInfoSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC("ViewportDisplayInfoService")); + } + + void AtomViewportDisplayInfoSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) + { + required.push_back(AZ_CRC("RPISystem", 0xf2add773)); + } + + void AtomViewportDisplayInfoSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + } + + void AtomViewportDisplayInfoSystemComponent::Activate() + { + AZ::Name apiName = AZ::RHI::Factory::Get().GetName(); + if (!apiName.IsEmpty()) + { + m_rendererDescription = AZStd::string::format("Atom using %s RHI", apiName.GetCStr()); + } + + AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect( + AZ::RPI::ViewportContextRequests::Get()->GetDefaultViewportContextName()); + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler::BusConnect(); + } + + void AtomViewportDisplayInfoSystemComponent::Deactivate() + { + AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler::BusDisconnect(); + AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect(); + } + + AZ::RPI::ViewportContextPtr AtomViewportDisplayInfoSystemComponent::GetViewportContext() const + { + return AZ::RPI::ViewportContextRequests::Get()->GetDefaultViewportContext(); + } + + void AtomViewportDisplayInfoSystemComponent::DrawLine(AZStd::string_view line, AZ::Color color) + { + m_drawParams.m_color = color; + AZ::Vector2 textSize = m_fontDrawInterface->GetTextSize(m_drawParams, line); + m_fontDrawInterface->DrawScreenAlignedText2d(m_drawParams, line); + m_drawParams.m_position.SetY(m_drawParams.m_position.GetY() + textSize.GetY() + m_lineSpacing); + } + + void AtomViewportDisplayInfoSystemComponent::OnRenderTick() + { + if (!m_fontDrawInterface) + { + auto fontQueryInterface = AZ::Interface::Get(); + if (!fontQueryInterface) + { + return; + } + m_fontDrawInterface = + fontQueryInterface->GetDefaultFontDrawInterface(); + } + AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); + + if (!m_fontDrawInterface || !viewportContext || !viewportContext->GetRenderScene()) + { + return; + } + + m_fpsInterval = AZStd::chrono::seconds(r_fpsCalcInterval); + + UpdateFramerate(); + + const AtomBridge::ViewportInfoDisplayState displayLevel = GetDisplayState(); + if (displayLevel == AtomBridge::ViewportInfoDisplayState::NoInfo) + { + return; + } + + if (m_updateRootPassQuery) + { + if (auto rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass()) + { + rootPass->SetPipelineStatisticsQueryEnabled(displayLevel != AtomBridge::ViewportInfoDisplayState::CompactInfo); + m_updateRootPassQuery = false; + } + } + + m_drawParams.m_drawViewportId = viewportContext->GetId(); + auto viewportSize = viewportContext->GetViewportSize(); + m_drawParams.m_position = AZ::Vector3(viewportSize.m_width, 0.f, 1.f); + m_drawParams.m_color = AZ::Colors::White; + m_drawParams.m_scale = AZ::Vector2(0.7f); + m_drawParams.m_hAlign = AzFramework::TextHorizontalAlignment::Right; + m_drawParams.m_monospace = false; + m_drawParams.m_depthTest = false; + m_drawParams.m_virtual800x600ScreenSize = true; + m_drawParams.m_scaleWithWindow = false; + m_drawParams.m_multiline = true; + m_drawParams.m_lineSpacing = 0.5f; + + // Calculate line spacing based on the font's actual line height + const float lineHeight = m_fontDrawInterface->GetTextSize(m_drawParams, " ").GetY(); + m_lineSpacing = lineHeight * m_drawParams.m_lineSpacing; + + DrawRendererInfo(); + if (displayLevel == AtomBridge::ViewportInfoDisplayState::FullInfo) + { + DrawCameraInfo(); + } + if (displayLevel != AtomBridge::ViewportInfoDisplayState::CompactInfo) + { + DrawPassInfo(); + } + DrawFramerate(); + } + + AtomBridge::ViewportInfoDisplayState AtomViewportDisplayInfoSystemComponent::GetDisplayState() const + { + return aznumeric_cast(r_displayInfo.operator int()); + } + + void AtomViewportDisplayInfoSystemComponent::SetDisplayState(AtomBridge::ViewportInfoDisplayState state) + { + r_displayInfo = aznumeric_cast(state); + AtomBridge::AtomViewportInfoDisplayNotificationBus::Broadcast( + &AtomBridge::AtomViewportInfoDisplayNotificationBus::Events::OnViewportInfoDisplayStateChanged, + state); + m_updateRootPassQuery = true; + } + + void AtomViewportDisplayInfoSystemComponent::DrawRendererInfo() + { + DrawLine(m_rendererDescription, AZ::Colors::Yellow); + } + + void AtomViewportDisplayInfoSystemComponent::DrawCameraInfo() + { + AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); + AZ::RPI::ViewPtr currentView = viewportContext->GetDefaultView(); + if (currentView == nullptr) + { + return; + } + + auto viewportSize = viewportContext->GetViewportSize(); + AzFramework::CameraState cameraState; + AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, currentView->GetViewToClipMatrix()); + const AZ::Transform transform = currentView->GetCameraTransform(); + const AZ::Vector3 translation = transform.GetTranslation(); + const AZ::Vector3 rotation = transform.GetEulerDegrees(); + DrawLine(AZStd::string::format( + "CamPos=%.2f %.2f %.2f Angl=%3.0f %3.0f %4.0f ZN=%.2f ZF=%.0f", + translation.GetX(), translation.GetY(), translation.GetZ(), + rotation.GetX(), rotation.GetY(), rotation.GetZ(), + cameraState.m_nearClip, cameraState.m_farClip + )); + } + + void AtomViewportDisplayInfoSystemComponent::DrawPassInfo() + { + auto rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass(); + const RPI::PipelineStatisticsResult stats = rootPass->GetLatestPipelineStatisticsResult(); + AZStd::function)> containingPassCount = [&containingPassCount](const AZ::RPI::Ptr pass) + { + int count = 1; + if (auto passAsParent = pass->AsParent()) + { + for (const auto& child : passAsParent->GetChildren()) + { + count += containingPassCount(child); + } + } + return count; + }; + const int numPasses = containingPassCount(rootPass); + DrawLine(AZStd::string::format( + "Total Passes: %d Vertex Count: %lld Primitive Count: %lld", + numPasses, + aznumeric_cast(stats.m_vertexCount), + aznumeric_cast(stats.m_primitiveCount) + )); + } + + void AtomViewportDisplayInfoSystemComponent::UpdateFramerate() + { + if (!m_tickRequests) + { + m_tickRequests = AZ::TickRequestBus::FindFirstHandler(); + if (!m_tickRequests) + { + return; + } + } + + AZ::ScriptTimePoint currentTime = m_tickRequests->GetTimeAtCurrentTick(); + // Only keep as much sampling data as is required by our FPS history. + while (!m_fpsHistory.empty() && (currentTime.Get() - m_fpsHistory.front().Get()) > m_fpsInterval) + { + m_fpsHistory.pop_front(); + } + + // Discard entries with a zero time-delta (can happen when we don't have window focus). + if (m_fpsHistory.empty() || (currentTime.Get() - m_fpsHistory.back().Get()) != AZStd::chrono::seconds(0)) + { + m_fpsHistory.push_back(currentTime); + } + } + + void AtomViewportDisplayInfoSystemComponent::DrawFramerate() + { + AZStd::chrono::duration actualInterval = AZStd::chrono::seconds(0); + AZStd::optional lastTime; + AZStd::optional minFPS; + AZStd::optional maxFPS; + for (const AZ::ScriptTimePoint& time : m_fpsHistory) + { + if (lastTime.has_value()) + { + AZStd::chrono::duration deltaTime = time.Get() - lastTime.value().Get(); + double fps = AZStd::chrono::seconds(1) / deltaTime; + if (!minFPS.has_value()) + { + minFPS = fps; + maxFPS = fps; + } + else + { + minFPS = AZStd::min(minFPS.value(), fps); + maxFPS = AZStd::max(maxFPS.value(), fps); + } + actualInterval += deltaTime; + } + lastTime = time; + } + + const double averageFPS = aznumeric_cast(m_fpsHistory.size()) / actualInterval.count(); + const double frameIntervalSeconds = m_fpsInterval.count(); + + DrawLine( + AZStd::string::format( + "FPS %.1f [%.0f..%.0f], frame avg over %.1fs", + averageFPS, + minFPS.value_or(0.0), + maxFPS.value_or(0.0), + frameIntervalSeconds), + AZ::Colors::Yellow); + } +} // namespace AZ::Render diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h new file mode 100644 index 0000000000..135082fd8c --- /dev/null +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.h @@ -0,0 +1,79 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace AZ +{ + class TickRequests; + + namespace Render + { + class AtomViewportDisplayInfoSystemComponent + : public AZ::Component + , public AZ::RPI::ViewportContextNotificationBus::Handler + , public AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler + { + public: + AZ_COMPONENT(AtomViewportDisplayInfoSystemComponent, "{AC32F173-E7E2-4943-8E6C-7C3091978221}"); + + static void Reflect(AZ::ReflectContext* context); + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + protected: + // AZ::Component overrides... + void Activate() override; + void Deactivate() override; + + // AZ::RPI::ViewportContextNotificationBus::Handler overrides... + void OnRenderTick() override; + + // AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler overrides... + AtomBridge::ViewportInfoDisplayState GetDisplayState() const override; + void SetDisplayState(AtomBridge::ViewportInfoDisplayState state) override; + + private: + AZ::RPI::ViewportContextPtr GetViewportContext() const; + void DrawLine(AZStd::string_view line, AZ::Color color = AZ::Colors::White); + + void UpdateFramerate(); + + void DrawRendererInfo(); + void DrawCameraInfo(); + void DrawPassInfo(); + void DrawFramerate(); + + AZStd::string m_rendererDescription; + AzFramework::TextDrawParameters m_drawParams; + AzFramework::FontDrawInterface* m_fontDrawInterface = nullptr; + float m_lineSpacing; + AZStd::chrono::duration m_fpsInterval = AZStd::chrono::seconds(1); + AZStd::deque m_fpsHistory; + AZStd::optional m_lastMemoryUpdate; + AZ::TickRequests* m_tickRequests = nullptr; + bool m_updateRootPassQuery = true; + }; + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/Module.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/Module.cpp new file mode 100644 index 0000000000..f67e1bd1f5 --- /dev/null +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/Module.cpp @@ -0,0 +1,51 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include + +#include "AtomViewportDisplayInfoSystemComponent.h" + +namespace AZ +{ + namespace Render + { + class AtomViewportDisplayInfoModule + : public AZ::Module + { + public: + AZ_RTTI(AtomViewportDisplayInfoModule, "{B10C0E55-03A1-4A46-AE3E-D3615AEAA659}", AZ::Module); + AZ_CLASS_ALLOCATOR(AtomViewportDisplayInfoModule, AZ::SystemAllocator, 0); + + AtomViewportDisplayInfoModule() + : AZ::Module() + { + m_descriptors.insert(m_descriptors.end(), { + AtomViewportDisplayInfoSystemComponent::CreateDescriptor(), + }); + } + + AZ::ComponentTypeList GetRequiredSystemComponents() const override + { + return AZ::ComponentTypeList{ + azrtti_typeid(), + }; + } + }; + } // namespace Render +} // namespace AZ + +// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM +// The first parameter should be GemName_GemIdLower +// The second should be the fully qualified name of the class above +AZ_DECLARE_MODULE_CLASS(Gem_AtomViewportDisplayInfo, AZ::Render::AtomViewportDisplayInfoModule) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/INetworkPlayerSpawner.h b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/Tests/test_Main.cpp similarity index 79% rename from Gems/Multiplayer/Code/Include/Multiplayer/INetworkPlayerSpawner.h rename to Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/Tests/test_Main.cpp index f50d60e82d..b533221bbe 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/INetworkPlayerSpawner.h +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/Tests/test_Main.cpp @@ -10,9 +10,11 @@ * */ -#pragma once +#include -namespace Multiplayer -{ +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); +TEST(AtomViewportDisplayInfoSanityTest, Sanity) +{ + EXPECT_EQ(1, 1); } diff --git a/Code/CryEngine/CrySystem/Platform/Windows/platform_windows_files.cmake b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/atomviewportdisplayinfo_files.cmake similarity index 80% rename from Code/CryEngine/CrySystem/Platform/Windows/platform_windows_files.cmake rename to Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/atomviewportdisplayinfo_files.cmake index 5714be5dfb..561971453b 100644 --- a/Code/CryEngine/CrySystem/Platform/Windows/platform_windows_files.cmake +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/atomviewportdisplayinfo_files.cmake @@ -10,4 +10,7 @@ # set(FILES + Source/AtomViewportDisplayInfoSystemComponent.cpp + Source/AtomViewportDisplayInfoSystemComponent.h + Source/Module.cpp ) diff --git a/Code/CryEngine/CrySystem/crysystem_dlmalloc_files.cmake b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/atomviewportdisplayinfo_test_files.cmake similarity index 94% rename from Code/CryEngine/CrySystem/crysystem_dlmalloc_files.cmake rename to Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/atomviewportdisplayinfo_test_files.cmake index 9f94bf6cff..0bc1ee3a50 100644 --- a/Code/CryEngine/CrySystem/crysystem_dlmalloc_files.cmake +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/atomviewportdisplayinfo_test_files.cmake @@ -10,5 +10,5 @@ # set(FILES - CryDLMalloc.c + Source/Tests/test_Main.cpp ) diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json new file mode 100644 index 0000000000..dd92a99ea9 --- /dev/null +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json @@ -0,0 +1,12 @@ +{ + "gem_name": "AtomLyIntegration_AtomViewportDisplayInfo", + "display_name": "Atom Viewport Display Info Overlay", + "summary": "Provides a diagnostic viewport overlay for the default O3DE Atom viewport.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "AtomLyIntegration", + "AtomViewportDisplayInfo" + ] +} \ No newline at end of file diff --git a/Gems/AtomLyIntegration/CMakeLists.txt b/Gems/AtomLyIntegration/CMakeLists.txt index 57bb860a9e..35022e643b 100644 --- a/Gems/AtomLyIntegration/CMakeLists.txt +++ b/Gems/AtomLyIntegration/CMakeLists.txt @@ -16,3 +16,4 @@ add_subdirectory(EMotionFXAtom) add_subdirectory(AtomFont) add_subdirectory(TechnicalArt) add_subdirectory(AtomBridge) +add_subdirectory(AtomViewportDisplayInfo) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp index 9d63f4a4a9..7ebf25454d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSlot.cpp @@ -269,7 +269,8 @@ namespace AZ QAction* action = nullptr; - menu.addAction("Open Material Editor", [this]() { EditorMaterialSystemComponentRequestBus::Broadcast(&EditorMaterialSystemComponentRequestBus::Events::OpenInMaterialEditor, ""); }); + action = menu.addAction("Open Material Editor...", [this]() { EditorMaterialSystemComponentRequestBus::Broadcast(&EditorMaterialSystemComponentRequestBus::Events::OpenInMaterialEditor, ""); }); + action->setVisible(!m_materialAsset.GetId().IsValid()); action = menu.addAction("Clear", [this]() { Clear(); }); action->setEnabled(m_materialAsset.GetId().IsValid() || !m_propertyOverrides.empty() || !m_matModUvOverrides.empty()); diff --git a/Gems/AtomLyIntegration/CommonFeatures/gem.json b/Gems/AtomLyIntegration/CommonFeatures/gem.json deleted file mode 100644 index 6c5d21c7f1..0000000000 --- a/Gems/AtomLyIntegration/CommonFeatures/gem.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "gem_name": "AtomLyIntegration_CommonFeatures", - "Dependencies": [ - { - "Uuid": "3e0ee0c27f204f5188146baac822d020", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "AtomToolsFramework" - }, - { - "Uuid": "ff06785f7145416b9d46fde39098cb0c", - "VersionConstraints": [ - "~>0.1" - ], - "_comment": "LmbrCentral" - }, - { - "Uuid": "b58e5eed0901428ca78544b04dbd61bd", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom Common Features" - } - ], - "GemFormatVersion": 4, - "Uuid": "4e981f3b17394f5d84d674fff0f54f4f", - "Name": "AtomLyIntegration_CommonFeatures", - "DisplayName": "AtomLyIntegration.CommonFeatures", - "Version": "0.1.0", - "LinkType": "Dynamic", - "Summary": "Lumberyard integration for common Atom features.", - "Tags": [ "Atom", "Feature", "Common" ], - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - }, - { - "Name": "Editor", - "Type": "EditorModule", - "Extends": "GameModule" - } - ] -} diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt index dc969d61d3..6492f4f13a 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt @@ -25,6 +25,7 @@ ly_add_target( Gem::Atom_Utils.Static Gem::Atom_Feature_Common Gem::Atom_Feature_Common.Public + Gem::Atom_Feature_Common.Static Gem::Atom_RPI.Public Gem::Atom_RHI.Reflect Gem::AtomLyIntegration_CommonFeatures.Public diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/gem.json b/Gems/AtomLyIntegration/EMotionFXAtom/gem.json deleted file mode 100644 index bdc959cc69..0000000000 --- a/Gems/AtomLyIntegration/EMotionFXAtom/gem.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "gem_name": "EMotionFX_Atom", - "Dependencies": [ - { - "Uuid": "b58e5eed0901428ca78544b04dbd61bd", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "Atom Common Features" - }, - { - "Uuid": "4e981f3b17394f5d84d674fff0f54f4f", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "AtomLyIntegration.CommonFeatures" - }, - { - "Uuid": "044a63ea67d04479aa5daf62ded9d9ca", - "VersionConstraints": [ - "~>0.1.0" - ], - "_comment": "EMotionFX" - } - ], - "GemFormatVersion": 3, - "Uuid": "{4f8a4d073ba34b43be45705f18705f1e}", - "Name": "EMotionFX_Atom", - "DisplayName": "EMotionFX.Atom", - "Version": "0.1.0", - "LinkType": "Dynamic", - "Summary": "EMotionFX support for Atom. Since some Atom projects will not include EMotionFX, and some projects using EMotionFX will not include Atom, this gem exists to prevent creating a hard dependency in either direction.", - "Tags": ["Atom", "EMotionFX", "Actor", "Skinned", "Mesh"], - "IconPath": "preview.png", - "EditorModule": true -} diff --git a/Gems/AtomLyIntegration/ImguiAtom/gem.json b/Gems/AtomLyIntegration/ImguiAtom/gem.json deleted file mode 100644 index dffef8fcc0..0000000000 --- a/Gems/AtomLyIntegration/ImguiAtom/gem.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "gem_name": "ImguiAtom", - "GemFormatVersion": 4, - "Uuid": "9986e22e14184f2fb6bb1e7dd185b2f9", - "Name": "ImguiAtom", - "DisplayName": "ImGui.Atom", - "Version": "0.1.0", - "Summary": "Provides ImGui implementation for Atom renderer", - "Tags": ["Atom", "ImGui"], - "IconPath": "preview.png", - "Modules": [ - { - "Type": "GameModule" - } - ], - "Dependencies": [ - { - "Uuid": "bab8807a1bc646b3909f3cc200ffeedf", - "VersionConstraints": [ - "~>0.1" - ], - "_comment": "ImGui" - }, - { - "Uuid": "a218db9eb2114477b46600fea4441a6c", - "VersionConstraints": [ - "~>0.1" - ], - "_comment": "Atom RPI" - } - ] -} diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json deleted file mode 100644 index ca80c62dd0..0000000000 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "gem_name": "Atom_DccScriptingInterface", - "GemFormatVersion": 4, - "Uuid": "7bf5a77dacd8438bb4966a66b5a678d8", - "Name": "Atom_DccScriptingInterface", - "DisplayName": "Atom DccScriptingInterface (DCCsi)", - "Version": "0.1.0", - "Summary": "A python framework for working with various DCC tools and workflows.", - "Tags": ["DCC","Digital","Content","Creation"], - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Editor", - "Type": "EditorModule" - } - ] -} diff --git a/Gems/AtomLyIntegration/gem.json b/Gems/AtomLyIntegration/gem.json new file mode 100644 index 0000000000..0971ad53c2 --- /dev/null +++ b/Gems/AtomLyIntegration/gem.json @@ -0,0 +1,3 @@ +{ + "gem_name": "AtomLyIntegration" +} diff --git a/Gems/AudioSystem/Code/Platform/Android/AudioSystem_Traits_Android.h b/Gems/AudioSystem/Code/Platform/Android/AudioSystem_Traits_Android.h index eaecb67e94..954ab9365f 100644 --- a/Gems/AudioSystem/Code/Platform/Android/AudioSystem_Traits_Android.h +++ b/Gems/AudioSystem/Code/Platform/Android/AudioSystem_Traits_Android.h @@ -18,6 +18,5 @@ #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE 256 #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE_DEFAULT_TEXT "256" #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_THREAD_AFFINITY AFFINITY_MASK_ALL -#define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_ALLOCATION_POLICY IMemoryManager::eapCustomAlignment #define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE 72 << 10 /* 72 MiB (re-evaluate this size!) */ #define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE_DEFAULT_TEXT "2048 (2 MiB)" diff --git a/Gems/AudioSystem/Code/Platform/Linux/AudioSystem_Traits_Linux.h b/Gems/AudioSystem/Code/Platform/Linux/AudioSystem_Traits_Linux.h index 951eec5d54..472afd51e5 100644 --- a/Gems/AudioSystem/Code/Platform/Linux/AudioSystem_Traits_Linux.h +++ b/Gems/AudioSystem/Code/Platform/Linux/AudioSystem_Traits_Linux.h @@ -18,6 +18,5 @@ #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE 512 #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE_DEFAULT_TEXT "512" #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_THREAD_AFFINITY AFFINITY_MASK_ALL -#define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_ALLOCATION_POLICY IMemoryManager::eapCustomAlignment #define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE 384 << 10 /* 384 MiB */ #define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE_DEFAULT_TEXT "393216 (384 MiB)" diff --git a/Gems/AudioSystem/Code/Platform/Mac/AudioSystem_Traits_Mac.h b/Gems/AudioSystem/Code/Platform/Mac/AudioSystem_Traits_Mac.h index 951eec5d54..472afd51e5 100644 --- a/Gems/AudioSystem/Code/Platform/Mac/AudioSystem_Traits_Mac.h +++ b/Gems/AudioSystem/Code/Platform/Mac/AudioSystem_Traits_Mac.h @@ -18,6 +18,5 @@ #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE 512 #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE_DEFAULT_TEXT "512" #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_THREAD_AFFINITY AFFINITY_MASK_ALL -#define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_ALLOCATION_POLICY IMemoryManager::eapCustomAlignment #define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE 384 << 10 /* 384 MiB */ #define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE_DEFAULT_TEXT "393216 (384 MiB)" diff --git a/Gems/AudioSystem/Code/Platform/Windows/AudioSystem_Traits_Windows.h b/Gems/AudioSystem/Code/Platform/Windows/AudioSystem_Traits_Windows.h index 11fb0ee66d..fa37cf1e89 100644 --- a/Gems/AudioSystem/Code/Platform/Windows/AudioSystem_Traits_Windows.h +++ b/Gems/AudioSystem/Code/Platform/Windows/AudioSystem_Traits_Windows.h @@ -18,6 +18,5 @@ #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE 1024 #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE_DEFAULT_TEXT "1024" #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_THREAD_AFFINITY AFFINITY_MASK_ALL -#define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_ALLOCATION_POLICY IMemoryManager::eapCustomAlignment #define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE 384 << 10 /* 384 MiB */ #define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE_DEFAULT_TEXT "393216 (384 MiB)" diff --git a/Gems/AudioSystem/Code/Platform/iOS/AudioSystem_Traits_iOS.h b/Gems/AudioSystem/Code/Platform/iOS/AudioSystem_Traits_iOS.h index 3ffcf4a345..7a008237e2 100644 --- a/Gems/AudioSystem/Code/Platform/iOS/AudioSystem_Traits_iOS.h +++ b/Gems/AudioSystem/Code/Platform/iOS/AudioSystem_Traits_iOS.h @@ -18,6 +18,5 @@ #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE 128 #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_OBJECT_POOL_SIZE_DEFAULT_TEXT "128" #define AZ_TRAIT_AUDIOSYSTEM_AUDIO_THREAD_AFFINITY AFFINITY_MASK_ALL -#define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_ALLOCATION_POLICY IMemoryManager::eapCustomAlignment #define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE 2 << 10 /* 2 MiB (re-evaluate this size!) */ #define AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_SIZE_DEFAULT_TEXT "2048 (2 MiB)" diff --git a/Gems/AudioSystem/Code/Source/Engine/ATLEntities.h b/Gems/AudioSystem/Code/Source/Engine/ATLEntities.h index fa72a78db9..c6624a125b 100644 --- a/Gems/AudioSystem/Code/Source/Engine/ATLEntities.h +++ b/Gems/AudioSystem/Code/Source/Engine/ATLEntities.h @@ -29,9 +29,6 @@ #include #include -#include - - namespace Audio { @@ -393,7 +390,7 @@ namespace Audio , m_memoryBlockAlignment(AUDIO_MEMORY_ALIGNMENT) , m_flags(eAFF_NOTFOUND) , m_dataScope(eADS_ALL) - , m_memoryBlock(nullptr) + // , m_memoryBlock(nullptr) // ToDo: Update to use non-legacy memory: LYN-3792 , m_implData(implData) { } @@ -406,7 +403,7 @@ namespace Audio size_t m_memoryBlockAlignment; Flags m_flags; EATLDataScope m_dataScope; - AZStd::unique_ptr m_memoryBlock; + // AZStd::unique_ptr m_memoryBlock; // ToDo: Update to use non-legacy memory: LYN-3792 AZ::IO::FileRequestPtr m_asyncStreamRequest; diff --git a/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.cpp b/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.cpp index 7be14244d0..0e84679261 100644 --- a/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.cpp @@ -25,7 +25,6 @@ #include #include -#include #include namespace Audio @@ -76,12 +75,13 @@ namespace Audio { if (size > 0) { - m_memoryHeap.reset(static_cast(gEnv->pSystem->GetIMemoryManager()->CreateCustomMemoryHeapInstance(AZ_TRAIT_AUDIOSYSTEM_FILE_CACHE_MANAGER_ALLOCATION_POLICY))); + // ToDo: Update to use non-legacy memory: LYN-3792 + /*m_memoryHeap.reset(???); if (m_memoryHeap.get()) { m_maxByteTotal = size << 10; - } + }*/ } } @@ -541,7 +541,7 @@ namespace Audio CATLAudioFileEntry* audioFileEntry = fileEntryIter->second; AZ_Assert(audioFileEntry, "FileCacheManager - Audio file entry is null!"); - AZ_Assert(buffer == audioFileEntry->m_memoryBlock->GetData(), "FileCacheManager - The memory buffer doesn't match the file entry memory block!"); + // AZ_Assert(buffer == audioFileEntry->m_memoryBlock->GetData(), "FileCacheManager - The memory buffer doesn't match the file entry memory block!"); // ToDo: Update to use non-legacy memory: LYN-3792 FinishCachingFileInternal(audioFileEntry, numBytesRead, streamer->GetRequestStatus(request)); } } @@ -574,7 +574,7 @@ namespace Audio SATLAudioFileEntryInfo fileEntryInfo; fileEntryInfo.nMemoryBlockAlignment = audioFileEntry->m_memoryBlockAlignment; - fileEntryInfo.pFileData = audioFileEntry->m_memoryBlock->GetData(); + // fileEntryInfo.pFileData = audioFileEntry->m_memoryBlock->GetData(); // ToDo: Update to use non-legacy memory: LYN-3792 fileEntryInfo.nSize = audioFileEntry->m_fileSize; fileEntryInfo.pImplData = audioFileEntry->m_implData; fileEntryInfo.sFileName = PathUtil::GetFile(audioFileEntry->m_filePath.c_str()); @@ -649,9 +649,12 @@ namespace Audio } /////////////////////////////////////////////////////////////////////////////////////////////// - bool CFileCacheManager::AllocateMemoryBlockInternal(CATLAudioFileEntry* const audioFileEntry) + bool CFileCacheManager::AllocateMemoryBlockInternal([[maybe_unused]]CATLAudioFileEntry* const audioFileEntry) { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Audio); + // ToDo: Update to use non-legacy memory: LYN-3792 + return false; + + /*AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Audio); // Must not have valid memory yet. AZ_Assert(!audioFileEntry->m_memoryBlock, "FileCacheManager AllocateMemoryBlockInternal - Memory appears to be set already!"); @@ -673,7 +676,7 @@ namespace Audio } } - return (audioFileEntry->m_memoryBlock != nullptr); + return (audioFileEntry->m_memoryBlock != nullptr);*/ } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -700,7 +703,8 @@ namespace Audio audioFileEntry->m_asyncStreamRequest.reset(); } - if (audioFileEntry->m_memoryBlock && audioFileEntry->m_memoryBlock->GetData()) + // ToDo: Update to use non-legacy memory heap: LYN-3792 + /*if (audioFileEntry->m_memoryBlock && audioFileEntry->m_memoryBlock->GetData()) { SATLAudioFileEntryInfo fileEntryInfo; fileEntryInfo.nMemoryBlockAlignment = audioFileEntry->m_memoryBlockAlignment; @@ -713,7 +717,7 @@ namespace Audio g_audioLogger.Log(eALT_COMMENT, "FileCacheManager - File Uncached: '%s'\n", fileEntryInfo.sFileName); } - audioFileEntry->m_memoryBlock.reset(); + audioFileEntry->m_memoryBlock.reset();*/ audioFileEntry->m_flags.ClearFlags(eAFF_CACHED | eAFF_REMOVABLE); AZ_Warning("FileCacheManager", audioFileEntry->m_useCount == 0, "Use-count of file '%s' is non-zero while uncaching it! Use Count: %d", audioFileEntry->m_filePath.c_str(), audioFileEntry->m_useCount); audioFileEntry->m_useCount = 0; @@ -765,7 +769,7 @@ namespace Audio bool CFileCacheManager::TryCacheFileCacheEntryInternal( CATLAudioFileEntry* const audioFileEntry, [[maybe_unused]] const TAudioFileEntryID fileEntryId, - const bool loadSynchronously, + [[maybe_unused]] const bool loadSynchronously, const bool overrideUseCount /* = false */, const size_t useCount /* = 0 */) { @@ -775,7 +779,8 @@ namespace Audio if (!audioFileEntry->m_filePath.empty() && !audioFileEntry->m_flags.AreAnyFlagsActive(eAFF_CACHED | eAFF_LOADING)) { - if (DoesRequestFitInternal(audioFileEntry->m_fileSize) && AllocateMemoryBlockInternal(audioFileEntry)) + // ToDo: Update to use non-legacy memory heap: LYN-3792 + /*if (DoesRequestFitInternal(audioFileEntry->m_fileSize) && AllocateMemoryBlockInternal(audioFileEntry)) { auto streamer = AZ::Interface::Get(); AZ_Assert(streamer, "FileCacheManager - Streamer should be ready!"); @@ -849,7 +854,7 @@ namespace Audio // The user should be made aware of it. g_audioLogger.Log(eALT_ERROR, "FileCacheManager: Could not cache '%s' - out of memory or fragmented memory!", audioFileEntry->m_filePath.c_str()); - } + }*/ } else if (audioFileEntry->m_flags.AreAnyFlagsActive(eAFF_CACHED | eAFF_LOADING)) { diff --git a/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.h b/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.h index 0e780bd467..b06a810e49 100644 --- a/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.h +++ b/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.h @@ -23,7 +23,6 @@ #include // Forward declarations -class CCustomMemoryHeap; struct IRenderAuxGeom; namespace Audio @@ -103,7 +102,7 @@ namespace Audio TATLPreloadRequestLookup& m_preloadRequests; TAudioFileEntries m_audioFileEntries; - AZStd::unique_ptr m_memoryHeap; + // AZStd::unique_ptr m_memoryHeap; // ToDo: Update to use non-legacy memory: LYN-3792 size_t m_currentByteTotal; size_t m_maxByteTotal; }; diff --git a/Gems/Camera/Code/Source/CameraComponentController.cpp b/Gems/Camera/Code/Source/CameraComponentController.cpp index 2799d897d6..3dcee68169 100644 --- a/Gems/Camera/Code/Source/CameraComponentController.cpp +++ b/Gems/Camera/Code/Source/CameraComponentController.cpp @@ -160,6 +160,17 @@ namespace Camera incompatible.push_back(AZ_CRC("CameraService", 0x1dd1caa4)); } + void CameraComponentController::Init() + { + m_onViewMatrixChanged = AZ::Event::Handler([this](const AZ::Matrix4x4&) + { + if (!m_updatingTransformFromEntity) + { + AZ::TransformBus::Event(m_entityId, &AZ::TransformInterface::SetWorldTM, m_atomCamera->GetCameraTransform()); + } + }); + } + void CameraComponentController::Activate(AZ::EntityId entityId) { m_entityId = entityId; @@ -218,6 +229,8 @@ namespace Camera } } AZ::RPI::ViewProviderBus::Handler::BusConnect(m_entityId); + + m_atomCamera->ConnectWorldToViewMatrixChangedHandler(m_onViewMatrixChanged); } UpdateCamera(); @@ -258,6 +271,7 @@ namespace Camera if (atomViewportRequests) { AZ::RPI::ViewProviderBus::Handler::BusDisconnect(m_entityId); + m_onViewMatrixChanged.Disconnect(); } DeactivateAtomView(); @@ -376,7 +390,9 @@ namespace Camera if (m_atomCamera) { + m_updatingTransformFromEntity = true; m_atomCamera->SetCameraTransform(AZ::Matrix3x4::CreateFromTransform(world.GetOrthogonalized())); + m_updatingTransformFromEntity = false; } } @@ -425,7 +441,9 @@ namespace Camera m_config.m_nearClipDistance, m_config.m_farClipDistance, true); + m_updatingTransformFromEntity = true; m_atomCamera->SetViewToClipMatrix(viewToClipMatrix); + m_updatingTransformFromEntity = false; } } diff --git a/Gems/Camera/Code/Source/CameraComponentController.h b/Gems/Camera/Code/Source/CameraComponentController.h index 92e1354f17..cae6ad4663 100644 --- a/Gems/Camera/Code/Source/CameraComponentController.h +++ b/Gems/Camera/Code/Source/CameraComponentController.h @@ -77,6 +77,7 @@ namespace Camera static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + void Init(); void Activate(AZ::EntityId entityId); void Deactivate(); void SetConfiguration(const CameraComponentConfig& config); @@ -121,6 +122,8 @@ namespace Camera // Atom integration AZ::RPI::ViewPtr m_atomCamera; AZ::RPI::AuxGeomDrawPtr m_atomAuxGeom; + AZ::Event::Handler m_onViewMatrixChanged; + bool m_updatingTransformFromEntity = false; // Cry view integration IView* m_view = nullptr; diff --git a/Gems/LmbrCentral/Code/Source/Shape/PolygonPrismShape.cpp b/Gems/LmbrCentral/Code/Source/Shape/PolygonPrismShape.cpp index 95d4366a13..3ea8f2a3d0 100644 --- a/Gems/LmbrCentral/Code/Source/Shape/PolygonPrismShape.cpp +++ b/Gems/LmbrCentral/Code/Source/Shape/PolygonPrismShape.cpp @@ -215,10 +215,6 @@ namespace LmbrCentral m_entityId = entityId; m_currentTransform = AZ::Transform::CreateIdentity(); AZ::TransformBus::EventResult(m_currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM); - m_currentNonUniformScale = AZ::Vector3::CreateOne(); - AZ::NonUniformScaleRequestBus::EventResult(m_currentNonUniformScale, m_entityId, &AZ::NonUniformScaleRequests::GetScale); - m_polygonPrism->SetNonUniformScale(m_currentNonUniformScale); - m_intersectionDataCache.InvalidateCache(InvalidateShapeCacheReason::ShapeChange); AZ::TransformNotificationBus::Handler::BusConnect(entityId); ShapeComponentRequestsBus::Handler::BusConnect(entityId); @@ -226,6 +222,11 @@ namespace LmbrCentral AZ::VariableVerticesRequestBus::Handler::BusConnect(entityId); AZ::FixedVerticesRequestBus::Handler::BusConnect(entityId); + m_currentNonUniformScale = AZ::Vector3::CreateOne(); + AZ::NonUniformScaleRequestBus::EventResult(m_currentNonUniformScale, m_entityId, &AZ::NonUniformScaleRequests::GetScale); + m_polygonPrism->SetNonUniformScale(m_currentNonUniformScale); + m_intersectionDataCache.InvalidateCache(InvalidateShapeCacheReason::ShapeChange); + AZ::NonUniformScaleRequestBus::Event(m_entityId, &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent, m_nonUniformScaleChangedHandler); diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Anchor_Left.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Anchor_Left.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Anchor_Left.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Anchor_Left.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Anchor_TopLeft.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Anchor_TopLeft.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Anchor_TopLeft.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Anchor_TopLeft.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Anchor_Whole.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Anchor_Whole.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Anchor_Whole.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Anchor_Whole.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Border_Selected.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Border_Selected.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Border_Selected.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Border_Selected.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Border_Unselected.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Border_Unselected.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Border_Unselected.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Border_Unselected.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Canvas_Background.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Canvas_Background.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Canvas_Background.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Canvas_Background.tif diff --git a/Gems/LyShine/Assets/Editor/Icons/Viewport/Canvas_Background.tif.assetinfo b/Gems/LyShine/Assets/Editor/Icons/Viewport/Canvas_Background.tif.assetinfo new file mode 100644 index 0000000000..61b2832ff3 --- /dev/null +++ b/Gems/LyShine/Assets/Editor/Icons/Viewport/Canvas_Background.tif.assetinfo @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/DottedLine.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/DottedLine.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/DottedLine.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/DottedLine.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Pivot.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Pivot.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Pivot.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Pivot.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Center_Square.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Center_Square.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Center_Square.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Center_Square.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Circle.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Circle.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Circle.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Circle.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Square_X.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Line_Square_X.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Square_X.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Line_Square_X.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Square_Y.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Line_Square_Y.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Square_Y.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Line_Square_Y.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Triangle_X.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Line_Triangle_X.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Triangle_X.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Line_Triangle_X.tif diff --git a/Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Triangle_Y.tif b/Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Line_Triangle_Y.tif similarity index 100% rename from Assets/Editor/Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Triangle_Y.tif rename to Gems/LyShine/Assets/Editor/Icons/Viewport/Transform_Gizmo_Line_Triangle_Y.tif diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index 9c46a61236..732bd1cfd4 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -93,6 +93,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC Gem::Atom_RPI.Public Gem::Atom_Utils.Static + Gem::Atom_Bootstrap.Headers ) ly_add_target( diff --git a/Gems/LyShine/Code/Editor/Animation/UiAnimViewDopeSheetBase.cpp b/Gems/LyShine/Code/Editor/Animation/UiAnimViewDopeSheetBase.cpp index bb15996223..57c52671df 100644 --- a/Gems/LyShine/Code/Editor/Animation/UiAnimViewDopeSheetBase.cpp +++ b/Gems/LyShine/Code/Editor/Animation/UiAnimViewDopeSheetBase.cpp @@ -2308,20 +2308,12 @@ void CUiAnimViewDopeSheetBase::DrawKeys(CUiAnimViewTrack* pTrack, QPainter* pain const int kDefaultWidthForDescription = 200; const int kSmallMargin = 10; - FixedDynArray drawnKeyTimes; - drawnKeyTimes.set(ArrayT((float*)alloca(numKeys * sizeof(float)), numKeys)); - // Draw keys. for (int i = 0; i < numKeys; ++i) { CUiAnimViewKeyHandle keyHandle = pTrack->GetKey(i); const float time = keyHandle.GetTime(); - if (!stl::push_back_unique(drawnKeyTimes, time)) - { - continue; - } - int x = TimeToClient(time); if (x - kSmallMargin > rect.right()) { diff --git a/Gems/LyShine/Code/Editor/Animation/Util/UiEditorUtils.cpp b/Gems/LyShine/Code/Editor/Animation/Util/UiEditorUtils.cpp index 24b8841059..29e63f62c3 100644 --- a/Gems/LyShine/Code/Editor/Animation/Util/UiEditorUtils.cpp +++ b/Gems/LyShine/Code/Editor/Animation/Util/UiEditorUtils.cpp @@ -21,34 +21,6 @@ ////////////////////////////////////////////////////////////////////////// void HeapCheck::Check([[maybe_unused]] const char* file, [[maybe_unused]] int line) { -#ifdef _DEBUG - AZ_Assert(CryMemory::IsHeapValid(), "Invalid heap"); -#endif - - /* - int heapstatus = _heapchk(); - switch( heapstatus ) - { - case _HEAPOK: - break; - case _HEAPEMPTY: - break; - case _HEAPBADBEGIN: - { - CString str; - str.Format( "Bad Start of Heap, at file %s line:%d",file,line ); - MessageBox( NULL,str,"Heap Check",MB_OK ); - } - break; - case _HEAPBADNODE: - { - CString str; - str.Format( "Bad Node in Heap, at file %s line:%d",file,line ); - MessageBox( NULL,str,"Heap Check",MB_OK ); - } - break; - } - */ } #include diff --git a/Gems/LyShine/Code/Editor/EditorWindow.cpp b/Gems/LyShine/Code/Editor/EditorWindow.cpp index 4641b02a13..e3810dcbee 100644 --- a/Gems/LyShine/Code/Editor/EditorWindow.cpp +++ b/Gems/LyShine/Code/Editor/EditorWindow.cpp @@ -1451,7 +1451,6 @@ void EditorWindow::OnEditorNotifyEvent(EEditorNotifyEvent ev) { // change skin RefreshEditorMenu(); - m_viewport->UpdateViewportBackground(); break; } case eNotify_OnUpdateViewports: diff --git a/Gems/LyShine/Code/Editor/PropertyHandlerSprite.cpp b/Gems/LyShine/Code/Editor/PropertyHandlerSprite.cpp index 5123d120d5..6a9de9093e 100644 --- a/Gems/LyShine/Code/Editor/PropertyHandlerSprite.cpp +++ b/Gems/LyShine/Code/Editor/PropertyHandlerSprite.cpp @@ -11,6 +11,7 @@ */ #include "UiCanvasEditor_precompiled.h" #include "EditorCommon.h" +#include "Sprite.h" #include "PropertyHandlerSprite.h" @@ -29,6 +30,8 @@ #include +#include + #include #include @@ -42,6 +45,7 @@ PropertySpriteCtrl::PropertySpriteCtrl(QWidget* parent) [ this ]([[maybe_unused]] AZ::Data::AssetId newAssetID) { EBUS_EVENT(AzToolsFramework::PropertyEditorGUIMessages::Bus, RequestWrite, this); + AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::Bus::Handler::OnEditingFinished, m_propertyAssetCtrl); }); setAcceptDrops(true); @@ -148,7 +152,9 @@ void PropertyHandlerSprite::WriteGUIValuesIntoProperty(size_t index, PropertySpr AZStd::string assetPath; EBUS_EVENT_RESULT(assetPath, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, GUI->GetPropertyAssetCtrl()->GetCurrentAssetID()); - instance.SetAssetPath(assetPath.c_str()); + // Convert streaming image's product path to relative source path to assign to the SimpleAssetReference + AZStd::string sourcePath = CSprite::GetImageSourcePathFromProductPath(assetPath); + instance.SetAssetPath(sourcePath.c_str()); } bool PropertyHandlerSprite::ReadValuesIntoGUI(size_t index, PropertySpriteCtrl* GUI, const property_t& instance, AzToolsFramework::InstanceDataNode* node) @@ -160,12 +166,26 @@ bool PropertyHandlerSprite::ReadValuesIntoGUI(size_t index, PropertySpriteCtrl* ctrl->blockSignals(true); { - ctrl->SetCurrentAssetType(instance.GetAssetType()); + // Set the asset type for the PropertyAssetCtrl. + // Use the hardcoded streaming image asset type instead of the passed in instance's asset type + // since the passed in type is the legacy SimpleAssetReference, and the asset picker + // does not associate this type with streaming images + AZ::Data::AssetType assetType = AZ::AzTypeInfo::Uuid(); + ctrl->SetCurrentAssetType(assetType); AZ::Data::AssetId assetId; if (!instance.GetAssetPath().empty()) { - EBUS_EVENT_RESULT(assetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, instance.GetAssetPath().c_str(), instance.GetAssetType(), false); + // Get the image path from the SimpleAssetReference and fix it up since CSprite still + // allows user specified paths that have the .sprite extension or the deprecated .dds extension + AZStd::string sourcePath = CSprite::GetImageSourcePathFromProductPath(instance.GetAssetPath()); + AZStd::string fixedUpSourcePath; + CSprite::FixUpSourceImagePathFromUserDefinedPath(sourcePath, fixedUpSourcePath); + + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetId, &AZ::Data::AssetCatalogRequestBus::Events::GenerateAssetIdTEMP, + fixedUpSourcePath.c_str()); + assetId.m_subId = AZ::RPI::StreamingImageAsset::GetImageAssetSubId(); } ctrl->SetSelectedAssetID(assetId); } diff --git a/Gems/LyShine/Code/Editor/QtHelpers.cpp b/Gems/LyShine/Code/Editor/QtHelpers.cpp index 9691c2a618..16a5d42327 100644 --- a/Gems/LyShine/Code/Editor/QtHelpers.cpp +++ b/Gems/LyShine/Code/Editor/QtHelpers.cpp @@ -13,6 +13,8 @@ #include "EditorCommon.h" +#include + namespace QtHelpers { AZ::Vector2 QPointFToVector2(const QPointF& point) @@ -34,4 +36,18 @@ namespace QtHelpers return inWidget; } + float GetHighDpiScaleFactor(const QWidget& widget) + { + float dpiScale = QHighDpiScaling::factor(widget.windowHandle()->screen()); + return dpiScale; + } + + QSize GetDpiScaledViewportSize(const QWidget& widget) + { + float dpiScale = GetHighDpiScaleFactor(widget); + float width = ceilf(widget.size().width() * dpiScale); + float height = ceilf(widget.size().height() * dpiScale); + return QSize(width, height); + } + } // namespace QtHelpers diff --git a/Gems/LyShine/Code/Editor/QtHelpers.h b/Gems/LyShine/Code/Editor/QtHelpers.h index f55ffc767e..7af68432d3 100644 --- a/Gems/LyShine/Code/Editor/QtHelpers.h +++ b/Gems/LyShine/Code/Editor/QtHelpers.h @@ -21,4 +21,8 @@ namespace QtHelpers bool IsGlobalPosInWidget(const QWidget* widget, const QPoint& pos); + float GetHighDpiScaleFactor(const QWidget& widget); + + QSize GetDpiScaledViewportSize(const QWidget& widget); + } // namespace QtHelpers diff --git a/Gems/LyShine/Code/Editor/ViewportAnchor.cpp b/Gems/LyShine/Code/Editor/ViewportAnchor.cpp index d61066f4d9..f46a62586d 100644 --- a/Gems/LyShine/Code/Editor/ViewportAnchor.cpp +++ b/Gems/LyShine/Code/Editor/ViewportAnchor.cpp @@ -14,10 +14,10 @@ #include "EditorCommon.h" ViewportAnchor::ViewportAnchor() - : m_anchorWhole(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Anchor_Whole.tif")) - , m_anchorLeft(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Anchor_Left.tif")) - , m_anchorLeftTop(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Anchor_TopLeft.tif")) - , m_dottedLine(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/DottedLine.tif")) + : m_anchorWhole(new ViewportIcon("Editor/Icons/Viewport/Anchor_Whole.tif")) + , m_anchorLeft(new ViewportIcon("Editor/Icons/Viewport/Anchor_Left.tif")) + , m_anchorLeftTop(new ViewportIcon("Editor/Icons/Viewport/Anchor_TopLeft.tif")) + , m_dottedLine(new ViewportIcon("Editor/Icons/Viewport/DottedLine.tif")) { } diff --git a/Gems/LyShine/Code/Editor/ViewportCanvasBackground.cpp b/Gems/LyShine/Code/Editor/ViewportCanvasBackground.cpp index ccc35de305..344e3af9cb 100644 --- a/Gems/LyShine/Code/Editor/ViewportCanvasBackground.cpp +++ b/Gems/LyShine/Code/Editor/ViewportCanvasBackground.cpp @@ -15,7 +15,7 @@ #include "EditorCommon.h" ViewportCanvasBackground::ViewportCanvasBackground() - : m_canvasBackground(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Canvas_Background.tif")) + : m_canvasBackground(new ViewportIcon("Editor/Icons/Viewport/Canvas_Background.tif")) { } diff --git a/Gems/LyShine/Code/Editor/ViewportHelpers.h b/Gems/LyShine/Code/Editor/ViewportHelpers.h index 9a1aadead5..7cb64d01c7 100644 --- a/Gems/LyShine/Code/Editor/ViewportHelpers.h +++ b/Gems/LyShine/Code/Editor/ViewportHelpers.h @@ -17,7 +17,6 @@ namespace ViewportHelpers { //------------------------------------------------------------------------------- - const AZ::Color backgroundColorLight(0.85f, 0.85f, 0.85f, 1.0f); const AZ::Color backgroundColorDark(0.133f, 0.137f, 0.149f, 1.0f); // #222236, RGBA: 34, 35, 38, 255 const AZ::Color selectedColor(1.000f, 1.000f, 1.000f, 1.0f); // #FFFFFF, RGBA: 255, 255, 255, 255 const AZ::Color unselectedColor(0.800f, 0.800f, 0.800f, 0.500f); // #CCCCCC, RGBA: 204, 204, 204, 128 diff --git a/Gems/LyShine/Code/Editor/ViewportHighlight.cpp b/Gems/LyShine/Code/Editor/ViewportHighlight.cpp index c050d55049..e6699615c6 100644 --- a/Gems/LyShine/Code/Editor/ViewportHighlight.cpp +++ b/Gems/LyShine/Code/Editor/ViewportHighlight.cpp @@ -14,8 +14,8 @@ #include "EditorCommon.h" ViewportHighlight::ViewportHighlight() - : m_highlightIconSelected(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Border_Selected.tif")) - , m_highlightIconUnselected(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Border_Unselected.tif")) + : m_highlightIconSelected(new ViewportIcon("Editor/Icons/Viewport/Border_Selected.tif")) + , m_highlightIconUnselected(new ViewportIcon("Editor/Icons/Viewport/Border_Unselected.tif")) { } diff --git a/Gems/LyShine/Code/Editor/ViewportIcon.cpp b/Gems/LyShine/Code/Editor/ViewportIcon.cpp index 81ed5dbcb5..b1866efb00 100644 --- a/Gems/LyShine/Code/Editor/ViewportIcon.cpp +++ b/Gems/LyShine/Code/Editor/ViewportIcon.cpp @@ -17,6 +17,8 @@ #include #include +float ViewportIcon::m_dpiScaleFactor = 1.0f; + ViewportIcon::ViewportIcon(const char* textureFilename) { m_image = CDraw2d::LoadTexture(textureFilename); @@ -31,7 +33,12 @@ AZ::Vector2 ViewportIcon::GetTextureSize() const if (m_image) { AZ::RHI::Size size = m_image->GetDescriptor().m_size; - return AZ::Vector2(size.m_width, size.m_height); + AZ::Vector2 scaledSize(size.m_width, size.m_height); + if (m_applyDpiScaleFactorToSize) + { + scaledSize *= m_dpiScaleFactor; + } + return scaledSize; } return AZ::Vector2(0.0f, 0.0f); @@ -380,5 +387,6 @@ void ViewportIcon::DrawElementRectOutline(Draw2dHelper& draw2d, AZ::EntityId ent rightVec.NormalizeSafe(); downVec.NormalizeSafe(); - draw2d.DrawRectOutlineTextured(m_image, points, rightVec, downVec, color); + uint32_t lineThickness = aznumeric_cast(GetTextureSize().GetY()); + draw2d.DrawRectOutlineTextured(m_image, points, rightVec, downVec, color, lineThickness); } diff --git a/Gems/LyShine/Code/Editor/ViewportIcon.h b/Gems/LyShine/Code/Editor/ViewportIcon.h index 85fd2fe068..b61d0715b6 100644 --- a/Gems/LyShine/Code/Editor/ViewportIcon.h +++ b/Gems/LyShine/Code/Editor/ViewportIcon.h @@ -49,6 +49,21 @@ public: // width of the border (but the texture can have alpha at edges to make it thinner). void DrawElementRectOutline(Draw2dHelper& draw2d, AZ::EntityId entityId, AZ::Color color); + // Set whether to apply high resolution dpi scaling to the icon size + void SetApplyDpiScaleFactorToSize(bool apply) { m_applyDpiScaleFactorToSize = apply; } + + // Get whether to apply high resolution dpi scaling to the icon size + bool GetApplyDpiScaleFactorToSize() { return m_applyDpiScaleFactorToSize; } + + // Set scale factor + static void SetDpiScaleFactor(float scale) { m_dpiScaleFactor = scale; } + + // Get scale factor + static float GetDpiScaleFactor() { return m_dpiScaleFactor; } + private: AZ::Data::Instance m_image; + bool m_applyDpiScaleFactorToSize = true; + + static float m_dpiScaleFactor; }; diff --git a/Gems/LyShine/Code/Editor/ViewportInteraction.cpp b/Gems/LyShine/Code/Editor/ViewportInteraction.cpp index 60b7f4f35b..c846bbb8c3 100644 --- a/Gems/LyShine/Code/Editor/ViewportInteraction.cpp +++ b/Gems/LyShine/Code/Editor/ViewportInteraction.cpp @@ -167,8 +167,8 @@ ViewportInteraction::ViewportInteraction(EditorWindow* editorWindow) : QObject() , m_editorWindow(editorWindow) , m_activeElementId() - , m_anchorWhole(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Anchor_Whole.tif")) - , m_pivotIcon(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Pivot.tif")) + , m_anchorWhole(new ViewportIcon("Editor/Icons/Viewport/Anchor_Whole.tif")) + , m_pivotIcon(new ViewportIcon("Editor/Icons/Viewport/Pivot.tif")) , m_interactionMode(PersistentGetInteractionMode()) , m_interactionType(InteractionType::NONE) , m_coordinateSystem(PersistentGetCoordinateSystem()) @@ -186,13 +186,13 @@ ViewportInteraction::ViewportInteraction(EditorWindow* editorWindow) , m_startAnchors(UiTransform2dInterface::Anchors()) , m_grabbedAnchors(ViewportHelpers::SelectedAnchors()) , m_grabbedGizmoParts(ViewportHelpers::GizmoParts()) - , m_lineTriangleX(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Triangle_X.tif")) - , m_lineTriangleY(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Triangle_Y.tif")) - , m_circle(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Circle.tif")) - , m_lineSquareX(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Square_X.tif")) - , m_lineSquareY(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Line_Square_Y.tif")) - , m_centerSquare(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Transform_Gizmo_Center_Square.tif")) - , m_dottedLine(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/DottedLine.tif")) + , m_lineTriangleX(new ViewportIcon("Editor/Icons/Viewport/Transform_Gizmo_Line_Triangle_X.tif")) + , m_lineTriangleY(new ViewportIcon("Editor/Icons/Viewport/Transform_Gizmo_Line_Triangle_Y.tif")) + , m_circle(new ViewportIcon("Editor/Icons/Viewport/Transform_Gizmo_Circle.tif")) + , m_lineSquareX(new ViewportIcon("Editor/Icons/Viewport/Transform_Gizmo_Line_Square_X.tif")) + , m_lineSquareY(new ViewportIcon("Editor/Icons/Viewport/Transform_Gizmo_Line_Square_Y.tif")) + , m_centerSquare(new ViewportIcon("Editor/Icons/Viewport/Transform_Gizmo_Center_Square.tif")) + , m_dottedLine(new ViewportIcon("Editor/Icons/Viewport/DottedLine.tif")) , m_dragInteraction(nullptr) , m_expanderWatcher(new ViewportInteractionExpanderWatcher(this)) { @@ -908,8 +908,9 @@ void ViewportInteraction::GetScaleToFitTransformProps(const AZ::Vector2* newCanv EBUS_EVENT_ID_RESULT(canvasSize, m_editorWindow->GetCanvas(), UiCanvasBus, GetCanvasSize); } - const int viewportWidth = m_editorWindow->GetViewport()->size().width(); - const int viewportHeight = m_editorWindow->GetViewport()->size().height(); + QSize viewportSize = QtHelpers::GetDpiScaledViewportSize(*m_editorWindow->GetViewport()); + const int viewportWidth = viewportSize.width(); + const int viewportHeight = viewportSize.height(); // We pad the edges of the viewport to allow the user to easily see the borders of // the canvas edges, which is especially helpful if there are anchors sitting on diff --git a/Gems/LyShine/Code/Editor/ViewportPivot.cpp b/Gems/LyShine/Code/Editor/ViewportPivot.cpp index 694cf91515..c264f7093d 100644 --- a/Gems/LyShine/Code/Editor/ViewportPivot.cpp +++ b/Gems/LyShine/Code/Editor/ViewportPivot.cpp @@ -15,7 +15,7 @@ #include "ViewportPivot.h" ViewportPivot::ViewportPivot() - : m_pivot(new ViewportIcon("Plugins/UiCanvasEditor/CanvasIcons/Pivot.tif")) + : m_pivot(new ViewportIcon("Editor/Icons/Viewport/Pivot.tif")) { } diff --git a/Gems/LyShine/Code/Editor/ViewportWidget.cpp b/Gems/LyShine/Code/Editor/ViewportWidget.cpp index 89c5a0bb50..f9464f17c7 100644 --- a/Gems/LyShine/Code/Editor/ViewportWidget.cpp +++ b/Gems/LyShine/Code/Editor/ViewportWidget.cpp @@ -38,6 +38,7 @@ #include #include +#include #define UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_ELEMENT_BORDERS_KEY "ViewportWidget::m_drawElementBordersFlags" #define UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_ELEMENT_BORDERS_DEFAULT ( ViewportWidget::DrawElementBorders_Unselected ) @@ -220,8 +221,6 @@ ViewportWidget::ViewportWidget(EditorWindow* parent) { setAcceptDrops(true); - UpdateViewportBackground(); - InitUiRenderer(); SetupShortcuts(); @@ -299,19 +298,6 @@ void ViewportWidget::ToggleDrawElementBorders(uint32 flags) SetDrawElementBordersFlags(m_drawElementBordersFlags); } -void ViewportWidget::UpdateViewportBackground() -{ - const QColor backgroundColor(ViewportHelpers::backgroundColorDark.GetR8(), - ViewportHelpers::backgroundColorDark.GetG8(), - ViewportHelpers::backgroundColorDark.GetB8(), - ViewportHelpers::backgroundColorDark.GetA8()); - - QPalette pal(palette()); - pal.setColor(QPalette::Window, backgroundColor); - setPalette(pal); - setAutoFillBackground(true); -} - void ViewportWidget::ActiveCanvasChanged() { bool canvasLoaded = m_editorWindow->GetCanvas().IsValid(); @@ -519,6 +505,9 @@ void ViewportWidget::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoin gEnv->pRenderer->SetSrgbWrite(true); #endif + const float dpiScale = QtHelpers::GetHighDpiScaleFactor(*this); + ViewportIcon::SetDpiScaleFactor(dpiScale); + // Set up to render a frame to this viewport's window GetViewportContext()->RenderTick(); @@ -554,7 +543,9 @@ void ViewportWidget::RefreshTick() void ViewportWidget::mousePressEvent(QMouseEvent* ev) { UiEditorMode editorMode = m_editorWindow->GetEditorMode(); - QMouseEvent scaledEvent(ev->type(), WidgetToViewport(ev->localPos()), ev->button(), ev->buttons(), ev->modifiers()); + + QPointF scaledPosition = WidgetToViewport(ev->localPos()); + QMouseEvent scaledEvent(ev->type(), scaledPosition, ev->button(), ev->buttons(), ev->modifiers()); if (editorMode == UiEditorMode::Edit) { // in Edit mode just send input to ViewportInteraction @@ -569,8 +560,7 @@ void ViewportWidget::mousePressEvent(QMouseEvent* ev) if (ev->button() == Qt::LeftButton) { // Send event to this canvas - QPointF scaledPos = WidgetToViewport(ev->localPos()); - const AZ::Vector2 viewportPosition(aznumeric_cast(scaledPos.x()), aznumeric_cast(scaledPos.y())); + const AZ::Vector2 viewportPosition(aznumeric_cast(scaledPosition.x()), aznumeric_cast(scaledPosition.y())); const AzFramework::InputChannel::Snapshot inputSnapshot(AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputDeviceMouse::Id, AzFramework::InputChannel::State::Began); @@ -588,7 +578,9 @@ void ViewportWidget::mousePressEvent(QMouseEvent* ev) void ViewportWidget::mouseMoveEvent(QMouseEvent* ev) { UiEditorMode editorMode = m_editorWindow->GetEditorMode(); - QMouseEvent scaledEvent(ev->type(), WidgetToViewport(ev->localPos()), ev->button(), ev->buttons(), ev->modifiers()); + + QPointF scaledPosition = WidgetToViewport(ev->localPos()); + QMouseEvent scaledEvent(ev->type(), scaledPosition, ev->button(), ev->buttons(), ev->modifiers()); if (editorMode == UiEditorMode::Edit) { @@ -596,7 +588,8 @@ void ViewportWidget::mouseMoveEvent(QMouseEvent* ev) m_viewportInteraction->MouseMoveEvent(&scaledEvent, m_editorWindow->GetHierarchy()->selectedItems()); - SetRulerCursorPositions(ev->globalPos()); + QPointF screenPosition = WidgetToViewport(ev->screenPos()); + SetRulerCursorPositions(screenPosition.toPoint()); } else // if (editorMode == UiEditorMode::Preview) { @@ -604,8 +597,7 @@ void ViewportWidget::mouseMoveEvent(QMouseEvent* ev) AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas(); if (canvasEntityId.IsValid()) { - QPointF scaledPos = WidgetToViewport(ev->localPos()); - const AZ::Vector2 viewportPosition(aznumeric_cast(scaledPos.x()), aznumeric_cast(scaledPos.y())); + const AZ::Vector2 viewportPosition(aznumeric_cast(scaledPosition.x()), aznumeric_cast(scaledPosition.y())); const AzFramework::InputChannelId& channelId = (ev->buttons() & Qt::LeftButton) ? AzFramework::InputDeviceMouse::Button::Left : AzFramework::InputDeviceMouse::SystemCursorPosition; @@ -625,7 +617,9 @@ void ViewportWidget::mouseMoveEvent(QMouseEvent* ev) void ViewportWidget::mouseReleaseEvent(QMouseEvent* ev) { UiEditorMode editorMode = m_editorWindow->GetEditorMode(); - QMouseEvent scaledEvent(ev->type(), WidgetToViewport(ev->localPos()), ev->button(), ev->buttons(), ev->modifiers()); + + QPointF scaledPosition = WidgetToViewport(ev->localPos()); + QMouseEvent scaledEvent(ev->type(), scaledPosition, ev->button(), ev->buttons(), ev->modifiers()); if (editorMode == UiEditorMode::Edit) { // in Edit mode just send input to ViewportInteraction @@ -641,8 +635,7 @@ void ViewportWidget::mouseReleaseEvent(QMouseEvent* ev) if (ev->button() == Qt::LeftButton) { // Send event to this canvas - QPointF scaledPos = WidgetToViewport(ev->localPos()); - const AZ::Vector2 viewportPosition(aznumeric_cast(scaledPos.x()), aznumeric_cast(scaledPos.y())); + const AZ::Vector2 viewportPosition(aznumeric_cast(scaledPosition.x()), aznumeric_cast(scaledPosition.y())); const AzFramework::InputChannel::Snapshot inputSnapshot(AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputDeviceMouse::Id, AzFramework::InputChannel::State::Ended); @@ -726,7 +719,7 @@ bool ViewportWidget::event(QEvent* ev) } } - bool result = QWidget::event(ev); + bool result = RenderViewportWidget::event(ev); return result; } @@ -931,14 +924,16 @@ void ViewportWidget::RenderEditMode(float deltaTime) EBUS_EVENT_ID_RESULT(canvasSize, canvasEntityId, UiCanvasBus, GetCanvasSize); m_draw2d->SetSortKey(backgroundKey); + + // Render a rectangle covering the entire editor viewport area + RenderViewportBackground(); + + // Render a checkerboard background covering the canvas area which represents transparency m_viewportBackground->Draw(draw2d, canvasSize, m_viewportInteraction->GetCanvasToViewportScale(), m_viewportInteraction->GetCanvasToViewportTranslation()); - AZ::Vector2 viewportSize(aznumeric_cast(size().width()), aznumeric_cast(size().height())); - viewportSize *= QHighDpiScaling::factor(windowHandle()->screen()); - #ifdef LYSHINE_ATOM_TODO // clear the stencil buffer before rendering each canvas - required for masking // NOTE: the FRT_CLEAR_IMMEDIATE is required since we will not be setting the render target @@ -953,6 +948,8 @@ void ViewportWidget::RenderEditMode(float deltaTime) EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, false); // Render this canvas + QSize scaledViewportSize = QtHelpers::GetDpiScaledViewportSize(*this); + AZ::Vector2 viewportSize(scaledViewportSize.width(), scaledViewportSize.height()); EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, RenderCanvasInEditorViewport, false, viewportSize); m_draw2d->SetSortKey(topLayerKey); @@ -1050,6 +1047,9 @@ void ViewportWidget::RenderEditMode(float deltaTime) void ViewportWidget::RenderPreviewMode(float deltaTime) { + // sort keys for different layers + static const int64_t backgroundKey = -0x1000; + AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas(); if (m_fontTextureHasChanged) @@ -1072,10 +1072,10 @@ void ViewportWidget::RenderPreviewMode(float deltaTime) if (canvasEntityId.IsValid()) { - // Get the canvas size - AZ::Vector2 viewportSize(aznumeric_cast(size().width()), aznumeric_cast(size().height())); - viewportSize *= QHighDpiScaling::factor(windowHandle()->screen()); + QSize scaledViewportSize = QtHelpers::GetDpiScaledViewportSize(*this); + AZ::Vector2 viewportSize(scaledViewportSize.width(), scaledViewportSize.height()); + // Get the canvas size AZ::Vector2 canvasSize = m_editorWindow->GetPreviewCanvasSize(); if (canvasSize.GetX() == 0.0f && canvasSize.GetY() == 0.0f) { @@ -1139,7 +1139,7 @@ void ViewportWidget::RenderPreviewMode(float deltaTime) canvasToViewportMatrix.SetTranslation(translation); EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetCanvasToViewportMatrix, canvasToViewportMatrix); -#ifdef LYSHINE_ATOM_TODO +#ifdef LYSHINE_ATOM_TODO // mask support with Atom // clear the stencil buffer before rendering each canvas - required for masking // NOTE: the FRT_CLEAR_IMMEDIATE is required since we will not be setting the render target // We also clear the color to a mid grey so that we can see the bounds of the canvas @@ -1147,16 +1147,18 @@ void ViewportWidget::RenderPreviewMode(float deltaTime) gEnv->pRenderer->ClearTargetsImmediately(FRT_CLEAR, viewportBackgroundColor); #endif -#ifdef LYSHINE_ATOM_TODO + m_draw2d->SetSortKey(backgroundKey); + + RenderViewportBackground(); + // Render a black rectangle covering the canvas area. This allows the canvas bounds to be visible when the canvas size is // not exactly the same as the viewport size AZ::Vector2 topLeftInViewportSpace = CanvasHelpers::GetViewportPoint(canvasEntityId, AZ::Vector2(0.0f, 0.0f)); AZ::Vector2 bottomRightInViewportSpace = CanvasHelpers::GetViewportPoint(canvasEntityId, canvasSize); AZ::Vector2 sizeInViewportSpace = bottomRightInViewportSpace - topLeftInViewportSpace; - Draw2dHelper draw2d(m_draw2d.get()) - int texId = gEnv->pRenderer->GetBlackTextureId(); - draw2d.DrawImage(texId, topLeftInViewportSpace, sizeInViewportSpace); -#endif + Draw2dHelper draw2d(m_draw2d.get()); + auto image = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::Black); + draw2d.DrawImage(image, topLeftInViewportSpace, sizeInViewportSpace); // Render this canvas // NOTE: the displayBounds param is always false. If we wanted a debug option to display the bounds @@ -1166,6 +1168,17 @@ void ViewportWidget::RenderPreviewMode(float deltaTime) } } +void ViewportWidget::RenderViewportBackground() +{ + QSize viewportSize = QtHelpers::GetDpiScaledViewportSize(*this); + AZ::Color backgroundColor = ViewportHelpers::backgroundColorDark; + const AZ::Data::Instance& image = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White); + + Draw2dHelper draw2d(m_draw2d.get()); + draw2d.SetImageColor(backgroundColor.GetAsVector3()); + draw2d.DrawImage(image, AZ::Vector2(0.0f, 0.0f), AZ::Vector2(viewportSize.width(), viewportSize.height())); +} + void ViewportWidget::SetupShortcuts() { // Actions with shortcuts are created instead of direct shortcuts because the shortcut dispatcher only looks for matching actions diff --git a/Gems/LyShine/Code/Editor/ViewportWidget.h b/Gems/LyShine/Code/Editor/ViewportWidget.h index 4d15f3dea4..77f07d7f6e 100644 --- a/Gems/LyShine/Code/Editor/ViewportWidget.h +++ b/Gems/LyShine/Code/Editor/ViewportWidget.h @@ -54,8 +54,6 @@ public: // member functions bool IsDrawingElementBorders(uint32 flags) const; void ToggleDrawElementBorders(uint32 flags); - void UpdateViewportBackground(); - void ActiveCanvasChanged(); void EntityContextChanged(); @@ -154,6 +152,9 @@ private: // member functions //! Render the viewport when in preview mode void RenderPreviewMode(float deltaTime); + //! Fill the entire viewport area with a background color + void RenderViewportBackground(); + //! Create shortcuts for manipulating the viewport void SetupShortcuts(); diff --git a/Gems/LyShine/Code/Include/LyShine/Draw2d.h b/Gems/LyShine/Code/Include/LyShine/Draw2d.h index df61542e25..8270461e73 100644 --- a/Gems/LyShine/Code/Include/LyShine/Draw2d.h +++ b/Gems/LyShine/Code/Include/LyShine/Draw2d.h @@ -131,16 +131,18 @@ public: // member functions //! Draw a rectangular outline with a texture // - //! \param image The texture to be used for drawing the outline - //! \param points The rect's vertices (top left, top right, bottom right, bottom left) - //! \param rightVec Right vector. Specified because the rect's width/height could be 0 - //! \param downVec Down vector. Specified because the rect's width/height could be 0 - //! \param color The color of the outline + //! \param image The texture to be used for drawing the outline + //! \param points The rect's vertices (top left, top right, bottom right, bottom left) + //! \param rightVec Right vector. Specified because the rect's width/height could be 0 + //! \param downVec Down vector. Specified because the rect's width/height could be 0 + //! \param color The color of the outline + //! \param lineThickness The thickness in pixels of the outline. If 0, it will be based on image height void DrawRectOutlineTextured(AZ::Data::Instance image, UiTransformInterface::RectPoints points, AZ::Vector2 rightVec, AZ::Vector2 downVec, - AZ::Color color); + AZ::Color color, + uint32_t lineThickness = 0); //! Get the width and height (in pixels) that would be used to draw the given text string. // @@ -439,11 +441,12 @@ public: // member functions UiTransformInterface::RectPoints points, AZ::Vector2 rightVec, AZ::Vector2 downVec, - AZ::Color color) + AZ::Color color, + uint32_t lineThickness = 0) { if (m_draw2d) { - m_draw2d->DrawRectOutlineTextured(image, points, rightVec, downVec, color); + m_draw2d->DrawRectOutlineTextured(image, points, rightVec, downVec, color, lineThickness); } } diff --git a/Gems/LyShine/Code/Source/Draw2d.cpp b/Gems/LyShine/Code/Source/Draw2d.cpp index 308761ff4e..1a639ea299 100644 --- a/Gems/LyShine/Code/Source/Draw2d.cpp +++ b/Gems/LyShine/Code/Source/Draw2d.cpp @@ -309,7 +309,8 @@ void CDraw2d::DrawRectOutlineTextured(AZ::Data::Instance image, UiTransformInterface::RectPoints points, AZ::Vector2 rightVec, AZ::Vector2 downVec, - AZ::Color color) + AZ::Color color, + uint32_t lineThickness) { // since the rect can be transformed we have to add the offsets by multiplying them // by unit vectors parallel with the edges of the rect. However, the rect could be @@ -325,18 +326,22 @@ void CDraw2d::DrawRectOutlineTextured(AZ::Data::Instance image, float rectWidth = widthVec.GetLength(); float rectHeight = heightVec.GetLength(); - // the outline thickness will be based on the texture height - float textureHeight = image ? aznumeric_cast(image->GetDescriptor().m_size.m_height) : 0.0f; - if (textureHeight <= 0.0f) + if (lineThickness == 0 && image) { - AZ_Assert(false, "Attempting to draw a textured rect outline with an image of zero height."); - return; // avoiding possible divide by zero later + lineThickness = image->GetDescriptor().m_size.m_height; + } + + if (lineThickness == 0) + { + AZ_Assert(false, "Attempting to draw a rect outline with of zero thickness."); + return; } // the outline is centered on the element rect so half the outline is outside // the rect and half is inside the rect - float outerOffset = -textureHeight * 0.5f; - float innerOffset = textureHeight * 0.5f; + float offset = aznumeric_cast(lineThickness); + float outerOffset = -offset * 0.5f; + float innerOffset = offset * 0.5f; float outerV = 0.0f; float innerV = 1.0f; @@ -348,7 +353,7 @@ void CDraw2d::DrawRectOutlineTextured(AZ::Data::Instance image, { float oldInnerOffset = innerOffset; innerOffset = minDimension * 0.5f; - // note oldInnerOffset can't be zero because of early return if textureHeight is zero + // note oldInnerOffset can't be zero because of early return if lineThickness is zero innerV = 0.5f + 0.5f * innerOffset / oldInnerOffset; } diff --git a/Gems/LyShine/Code/Source/LyShine.cpp b/Gems/LyShine/Code/Source/LyShine.cpp index bc6a27dac4..679cae3421 100644 --- a/Gems/LyShine/Code/Source/LyShine.cpp +++ b/Gems/LyShine/Code/Source/LyShine.cpp @@ -137,7 +137,6 @@ CLyShine::CLyShine(ISystem* system) , m_draw2d(new CDraw2d) , m_uiRenderer(new UiRenderer) , m_uiCanvasManager(new UiCanvasManager) - , m_uiCursorTexture(nullptr) , m_uiCursorVisibleCounter(0) { // Reflect the Deprecated Lua buses using the behavior context. @@ -170,6 +169,7 @@ CLyShine::CLyShine(ISystem* system) AzFramework::InputTextEventListener::Connect(); UiCursorBus::Handler::BusConnect(); AZ::TickBus::Handler::BusConnect(); + AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect(); // These are internal Amazon components, so register them so that we can send back their names to our metrics collection // IF YOU ARE A THIRDPARTY WRITING A GEM, DO NOT REGISTER YOUR COMPONENTS WITH EditorMetricsComponentRegistrationBus @@ -248,17 +248,12 @@ CLyShine::~CLyShine() AZ::TickBus::Handler::BusDisconnect(); AzFramework::InputTextEventListener::Disconnect(); AzFramework::InputChannelEventListener::Disconnect(); + AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect(); UiCanvasComponent::Shutdown(); // must be done after UiCanvasComponent::Shutdown CSprite::Shutdown(); - - if (m_uiCursorTexture) - { - m_uiCursorTexture->Release(); - m_uiCursorTexture = nullptr; - } } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -443,6 +438,9 @@ void CLyShine::Render() // Render all the canvases loaded in game m_uiCanvasManager->RenderLoadedCanvases(); + // Set sort key for draw2d layer to ensure it renders in front of the canvases + static const int64_t topLayerKey = 0x1000000; + m_draw2d->SetSortKey(topLayerKey); m_draw2d->RenderDeferredPrimitives(); // Don't render the UI cursor when in edit mode. For example during UI Preview mode a script could turn on the @@ -558,18 +556,20 @@ bool CLyShine::IsUiCursorVisible() //////////////////////////////////////////////////////////////////////////////////////////////////// void CLyShine::SetUiCursor(const char* cursorImagePath) { - if (m_uiCursorTexture) - { - m_uiCursorTexture->Release(); - m_uiCursorTexture = nullptr; - } + m_uiCursorTexture.reset(); + m_cursorImagePathToLoad.clear(); - if (cursorImagePath && *cursorImagePath && gEnv && gEnv->pRenderer) + if (cursorImagePath && *cursorImagePath) { - m_uiCursorTexture = gEnv->pRenderer->EF_LoadTexture(cursorImagePath, FT_DONT_RELEASE | FT_DONT_STREAM); - if (m_uiCursorTexture) + m_cursorImagePathToLoad = cursorImagePath; + // The cursor image can only be loaded after the RPI has been initialized. + // Note: this check could be avoided if LyShineSystemComponent included the RPISystem + // as a required service. However, LyShineSystempComponent is currently activated for + // tools as well as game and RPIService is not available with all tools such as AP. An + // enhancement would be to break LyShineSystemComponent into a game only component + if (m_uiRenderer->IsReady()) { - m_uiCursorTexture->SetClamp(true); + LoadUiCursor(); } } } @@ -581,8 +581,11 @@ AZ::Vector2 CLyShine::GetUiCursorPosition() AzFramework::InputSystemCursorRequestBus::EventResult(systemCursorPositionNormalized, AzFramework::InputDeviceMouse::Id, &AzFramework::InputSystemCursorRequests::GetSystemCursorPositionNormalized); - return AZ::Vector2(systemCursorPositionNormalized.GetX() * static_cast(gEnv->pRenderer->GetOverlayWidth()), - systemCursorPositionNormalized.GetY() * static_cast(gEnv->pRenderer->GetOverlayHeight())); + + AZ::Vector2 viewportSize = m_uiRenderer->GetViewportSize(); + + return AZ::Vector2(systemCursorPositionNormalized.GetX() * viewportSize.GetX(), + systemCursorPositionNormalized.GetY() * viewportSize.GetY()); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -642,6 +645,7 @@ bool CLyShine::OnInputTextEventFiltered(const AZStd::string& textUTF8) return result; } +//////////////////////////////////////////////////////////////////////////////////////////////////// void CLyShine::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { // Update the loaded UI canvases @@ -651,15 +655,33 @@ void CLyShine::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time Render(); } +//////////////////////////////////////////////////////////////////////////////////////////////////// int CLyShine::GetTickOrder() { return AZ::TICK_UI; } +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CLyShine::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +{ + // Load cursor if its path was set before RPI was initialized + LoadUiCursor(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void CLyShine::LoadUiCursor() +{ + if (!m_cursorImagePathToLoad.empty()) + { + m_uiCursorTexture = CDraw2d::LoadTexture(m_cursorImagePathToLoad); // LYSHINE_ATOM_TODO - add clamp option to draw2d and set cursor to clamp + m_cursorImagePathToLoad.clear(); + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////// void CLyShine::RenderUiCursor() { - if (!gEnv || !gEnv->pRenderer || !m_uiCursorTexture || !IsUiCursorVisible()) + if (!m_uiCursorTexture || !IsUiCursorVisible()) { return; } @@ -671,13 +693,10 @@ void CLyShine::RenderUiCursor() } const AZ::Vector2 position = GetUiCursorPosition(); - const AZ::Vector2 dimensions(static_cast(m_uiCursorTexture->GetWidth()), static_cast(m_uiCursorTexture->GetHeight())); + AZ::RHI::Size cursorSize = m_uiCursorTexture->GetDescriptor().m_size; + const AZ::Vector2 dimensions(aznumeric_cast(cursorSize.m_width), aznumeric_cast(cursorSize.m_height)); -#ifdef LYSHINE_ATOM_TODO // Convert cursor to Atom image - m_draw2d->BeginDraw2d(); - m_draw2d->DrawImage(m_uiCursorTexture->GetTextureID(), position, dimensions); - m_draw2d->EndDraw2d(); -#endif + m_draw2d->DrawImage(m_uiCursorTexture, position, dimensions); } #ifndef _RELEASE diff --git a/Gems/LyShine/Code/Source/LyShine.h b/Gems/LyShine/Code/Source/LyShine.h index 943f5fa537..4c46b0db19 100644 --- a/Gems/LyShine/Code/Source/LyShine.h +++ b/Gems/LyShine/Code/Source/LyShine.h @@ -19,6 +19,9 @@ #include #include +#include +#include + #if !defined(_RELEASE) #define LYSHINE_INTERNAL_UNIT_TEST #endif @@ -41,6 +44,7 @@ class CLyShine , public AzFramework::InputChannelEventListener , public AzFramework::InputTextEventListener , public AZ::TickBus::Handler + , protected AZ::Render::Bootstrap::NotificationBus::Handler { public: @@ -111,6 +115,10 @@ public: int GetTickOrder() override; // ~TickEvents + // AZ::Render::Bootstrap::NotificationBus + void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) override; + // ~AZ::Render::Bootstrap::NotificationBus + // Get the UIRenderer for the game (which is owned by CLyShine). This is not exposed outside the gem. UiRenderer* GetUiRenderer(); @@ -128,6 +136,7 @@ private: // member functions AZ_DISABLE_COPY_MOVE(CLyShine); + void LoadUiCursor(); void RenderUiCursor(); private: // static member functions @@ -146,7 +155,8 @@ private: // data std::unique_ptr m_uiCanvasManager; - ITexture* m_uiCursorTexture; + AZStd::string m_cursorImagePathToLoad; + AZ::Data::Instance m_uiCursorTexture; int m_uiCursorVisibleCounter; bool m_updatingLoadedCanvases = false; // guard against nested updates diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp index 8e8079e18e..f55c8c5957 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp @@ -56,26 +56,6 @@ #include "UiDynamicScrollBoxComponent.h" #include "UiNavigationSettings.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -struct CSystemEventListener_UI - : public ISystemEventListener -{ -public: - virtual void OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam) - { - switch (event) - { - case ESYSTEM_EVENT_LEVEL_POST_UNLOAD: - { - STLALLOCATOR_CLEANUP; - break; - } - } - } -}; -static CSystemEventListener_UI g_system_event_listener_ui; - - namespace LyShine { const AZStd::list* LyShineSystemComponent::m_componentDescriptors = nullptr; @@ -228,9 +208,6 @@ namespace LyShine //////////////////////////////////////////////////////////////////////////////////////////////////// void LyShineSystemComponent::InitializeSystem() { - // Not sure if this is still required - gEnv->pSystem->GetISystemEventDispatcher()->RegisterListener(&g_system_event_listener_ui); - m_pLyShine = new CLyShine(gEnv->pSystem); gEnv->pLyShine = m_pLyShine; BroadcastCursorImagePathname(); diff --git a/Gems/LyShine/Code/Source/Sprite.cpp b/Gems/LyShine/Code/Source/Sprite.cpp index c574a16c0c..7abbba4ea2 100644 --- a/Gems/LyShine/Code/Source/Sprite.cpp +++ b/Gems/LyShine/Code/Source/Sprite.cpp @@ -11,7 +11,6 @@ */ #include "LyShine_precompiled.h" #include "Sprite.h" -#include #include #include #include @@ -26,6 +25,7 @@ namespace { const char* const spriteExtension = "sprite"; + const char* const streamingImageExtension = "streamingimage"; // Increment this when the Sprite Serialize(TSerialize) function // changes to be incompatible with previous data @@ -37,7 +37,7 @@ namespace }; const int numAllowedSpriteTextureExtensions = AZ_ARRAY_SIZE(allowedSpriteTextureExtensions); - bool IsValidSpriteTextureExtension(const AZStd::string& extension) + bool IsValidImageExtension(const AZStd::string& extension) { for (int i = 0; i < numAllowedSpriteTextureExtensions; ++i) { @@ -50,6 +50,13 @@ namespace return false; } + bool IsImageProductPath(const AZStd::string& pathname) + { + AZStd::string extension; + AzFramework::StringFunc::Path::GetExtension(pathname.c_str(), extension, false); + return (extension.compare(streamingImageExtension) == 0); + } + // Check if a file exists. This does not go through the AssetCatalog so that it can identify files that exist but aren't processed yet, // and so that it will work before the AssetCatalog has loaded bool CheckIfFileExists(const AZStd::string& sourceRelativePath, const AZStd::string& cacheRelativePath) @@ -88,61 +95,49 @@ namespace return fileExists; } - bool ReplaceSpriteExtensionWithTextureExtension(const AZStd::string& spritePath, AZStd::string& texturePath) + bool GetSourceAssetPaths(const AZStd::string& pathname, AZStd::string& spritePath, AZStd::string& texturePath) { - for (int i = 0; i < numAllowedSpriteTextureExtensions; ++i) + // Remove product extension from the texture path if it exists + AZStd::string sourcePathname(pathname); + if (IsImageProductPath(pathname)) { - AZStd::string sourceRelativePath(spritePath); - AzFramework::StringFunc::Path::ReplaceExtension(sourceRelativePath, allowedSpriteTextureExtensions[i]); - AZStd::string cacheRelativePath = sourceRelativePath + ".streamingimage"; - - bool textureExists = CheckIfFileExists(sourceRelativePath, cacheRelativePath); - if (textureExists) - { - texturePath = sourceRelativePath; - return true; - } + sourcePathname = CSprite::GetImageSourcePathFromProductPath(pathname); } - return false; - } - - bool GetAssetPaths(const AZStd::string& pathname, AZStd::string& spritePath, AZStd::string& texturePath) - { - // the input string could be in any form. So make it normalized + // the input string could be in any form. So make it normalized (forward slashes and lower case) // NOTE: it should not be a full path at this point. If called from the UI editor it will // have been transformed to a game path. If being called with a hard coded path it should be a // game path already - it is not good for code to be using full paths. - AZStd::string assetPath(pathname); - EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, assetPath); + EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, sourcePathname); // check the extension and work out the pathname of the sprite file and the texture file // currently it works if the input path is either a sprite file or a texture file AZStd::string extension; - AzFramework::StringFunc::Path::GetExtension(assetPath.c_str(), extension, false); + AzFramework::StringFunc::Path::GetExtension(sourcePathname.c_str(), extension, false); if (extension.compare(spriteExtension) == 0) { - spritePath = assetPath; + // The .sprite file has been specified + spritePath = sourcePathname; // look for a texture file with the same name - if (!ReplaceSpriteExtensionWithTextureExtension(spritePath, texturePath)) + if (!CSprite::FixUpSourceImagePathFromUserDefinedPath(spritePath, texturePath)) { gEnv->pSystem->Warning(VALIDATOR_MODULE_SHINE, VALIDATOR_WARNING, VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE, - assetPath.c_str(), "No texture file found for sprite: %s, no sprite will be used", assetPath.c_str()); + spritePath.c_str(), "No texture file found for sprite: %s, no sprite will be used", spritePath.c_str()); return false; } } - else if (IsValidSpriteTextureExtension(extension)) + else if (IsValidImageExtension(extension)) { - texturePath = assetPath; - spritePath = assetPath; + texturePath = sourcePathname; + spritePath = sourcePathname; AzFramework::StringFunc::Path::ReplaceExtension(spritePath, spriteExtension); } else { gEnv->pSystem->Warning(VALIDATOR_MODULE_SHINE, VALIDATOR_WARNING, VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE, - assetPath.c_str(), "Invalid file extension for sprite: %s, no sprite will be used", assetPath.c_str()); + pathname.c_str(), "Invalid file extension for sprite: %s, no sprite will be used", pathname.c_str()); return false; } @@ -197,8 +192,7 @@ AZStd::string CSprite::s_emptyString; //////////////////////////////////////////////////////////////////////////////////////////////////// CSprite::CSprite() - : m_texture(nullptr) - , m_numSpriteSheetCellTags(0) + : m_numSpriteSheetCellTags(0) , m_atlas(nullptr) { AddRef(); @@ -208,8 +202,6 @@ CSprite::CSprite() //////////////////////////////////////////////////////////////////////////////////////////////////// CSprite::~CSprite() { - ReleaseTexture(m_texture); - s_loadedSprites->erase(m_pathname); TextureAtlasNamespace::TextureAtlasNotificationBus::Handler::BusDisconnect(); } @@ -254,26 +246,17 @@ void CSprite::SetCellBorders(int cellIndex, Borders borders) } //////////////////////////////////////////////////////////////////////////////////////////////////// -ITexture* CSprite::GetTexture() +AZ::Data::Instance CSprite::GetImage() { // Prioritize usage of an atlas +#ifdef LYSHINE_ATOM_TODO // texture atlas conversion to use Atom if (m_atlas) { return m_atlas->GetTexture(); } +#endif - if (!m_texture && !m_pathname.empty()) - { - // the render target texture may not have existed when the sprite was created - m_texture = gEnv->pRenderer->EF_GetTextureByName(m_pathname.c_str()); - if (m_texture) - { - // increase the reference count to this texture so it doesn't get removed while - // we are using it - m_texture->AddRef(); - } - } - return m_texture; + return m_image; } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -381,31 +364,21 @@ bool CSprite::AreCellBordersZeroWidth(int cellIndex) const //////////////////////////////////////////////////////////////////////////////////////////////////// AZ::Vector2 CSprite::GetSize() { -#ifdef LYSHINE_ATOM_TODO // Convert texture atlases to use Atom - ITexture* texture = GetTexture(); - if (texture) + AZ::Data::Instance image = GetImage(); + if (image) { if (m_atlas) { return AZ::Vector2(static_cast(m_atlasCoordinates.GetWidth()), static_cast(m_atlasCoordinates.GetHeight())); } - return AZ::Vector2(static_cast(texture->GetWidth()), static_cast(texture->GetHeight())); - } - else - { - return AZ::Vector2(0.0f, 0.0f); - } -#else - if (m_image) - { - AZ::RHI::Size size = m_image->GetRHIImage()->GetDescriptor().m_size; + + AZ::RHI::Size size = image->GetRHIImage()->GetDescriptor().m_size; return AZ::Vector2(size.m_width, size.m_height); } else { return AZ::Vector2(0.0f, 0.0f); } -#endif } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -665,7 +638,7 @@ CSprite* CSprite::LoadSprite(const string& pathname) { AZStd::string spritePath; AZStd::string texturePath; - bool validAssetPaths = GetAssetPaths(pathname.c_str(), spritePath, texturePath); + bool validAssetPaths = GetSourceAssetPaths(pathname.c_str(), spritePath, texturePath); if (!validAssetPaths) { @@ -738,6 +711,7 @@ CSprite* CSprite::CreateSprite(const string& renderTargetName) // create Sprite object CSprite* sprite = new CSprite; +#ifdef LYSHINE_ATOM_TODO // render target converstion to use ATom // the render target texture may not exist yet in which case we will need to load it later sprite->m_texture = gEnv->pRenderer->EF_GetTextureByName(renderTargetName.c_str()); if (sprite->m_texture) @@ -746,6 +720,7 @@ CSprite* CSprite::CreateSprite(const string& renderTargetName) // while we are using it sprite->m_texture->AddRef(); } +#endif sprite->m_pathname = renderTargetName; sprite->m_texturePathname.clear(); @@ -760,7 +735,7 @@ bool CSprite::DoesSpriteTextureAssetExist(const AZStd::string& pathname) { AZStd::string spritePath; AZStd::string texturePath; - bool validAssetPaths = GetAssetPaths(pathname, spritePath, texturePath); + bool validAssetPaths = GetSourceAssetPaths(pathname.c_str(), spritePath, texturePath); if (!validAssetPaths) { @@ -785,8 +760,7 @@ bool CSprite::DoesSpriteTextureAssetExist(const AZStd::string& pathname) } // Check if the texture asset exists - AZStd::string cacheRelativePath = texturePath + ".streamingimage"; - bool textureExists = CheckIfFileExists(texturePath, cacheRelativePath); + bool textureExists = CheckIfFileExists(spritePath, texturePath); return textureExists; } @@ -807,50 +781,53 @@ void CSprite::ReplaceSprite(ISprite** baseSprite, ISprite* newSprite) } //////////////////////////////////////////////////////////////////////////////////////////////////// -bool CSprite::LoadTexture(const string& texturePathname, const string& pathname, ITexture*& texture) +bool CSprite::FixUpSourceImagePathFromUserDefinedPath(const AZStd::string& userDefinedPath, AZStd::string& sourceImagePath) { - uint32 loadTextureFlags = (FT_USAGE_ALLOWREADSRGB | FT_DONT_STREAM); - texture = gEnv->pRenderer->EF_LoadTexture(texturePathname.c_str(), loadTextureFlags); + static const char* textureExtensions[] = { "png", "tif", "tiff", "tga", "jpg", "jpeg", "bmp", "gif" }; - if (!texture || !texture->IsTextureLoaded()) + AZStd::string sourceRelativePath(userDefinedPath); + AZStd::string cacheRelativePath = AZStd::string::format("%s.%s", sourceRelativePath.c_str(), streamingImageExtension); + bool textureExists = CheckIfFileExists(sourceRelativePath, cacheRelativePath); + + if (textureExists) { - gEnv->pSystem->Warning( - VALIDATOR_MODULE_SHINE, - VALIDATOR_WARNING, - VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE, - texturePathname.c_str(), - "No texture file found for sprite: %s, no sprite will be used. " - "NOTE: File must be in current project or a gem.", - pathname.c_str()); - texture = nullptr; - return false; + sourceImagePath = userDefinedPath; + return true; } - texture->SetFilter(FILTER_LINEAR); - return true; -} + AZStd::string curSourceImagePath(userDefinedPath); + for (const char* extensionReplacement : textureExtensions) + { + AzFramework::StringFunc::Path::ReplaceExtension(curSourceImagePath, extensionReplacement); + cacheRelativePath = AZStd::string::format("%s.%s", curSourceImagePath.c_str(), streamingImageExtension); + textureExists = CheckIfFileExists(curSourceImagePath, cacheRelativePath); + + if (textureExists) + { + sourceImagePath = curSourceImagePath; + return true; + } + } + + return false; +} //////////////////////////////////////////////////////////////////////////////////////////////////// -void CSprite::ReleaseTexture(ITexture*& texture) +AZStd::string CSprite::GetImageSourcePathFromProductPath(const AZStd::string& productPathname) { - if (texture) + AZStd::string sourcePathname(productPathname); + if (IsImageProductPath(sourcePathname)) { - // In order to avoid the texture being deleted while there are still commands on the render - // thread command queue that use it, we queue a command to delete the texture onto the - // command queue. - auto pInfo = AZStd::make_unique(); - pInfo->eClassName = eRCN_Texture; - pInfo->pResource = texture; - gEnv->pRenderer->ReleaseResourceAsync(AZStd::move(pInfo)); - texture = nullptr; + AzFramework::StringFunc::Path::StripExtension(sourcePathname); } + return sourcePathname; } //////////////////////////////////////////////////////////////////////////////////////////////////// bool CSprite::LoadImage(const AZStd::string& nameTex, AZ::Data::Instance& image) { AZStd::string sourceRelativePath(nameTex); - AZStd::string cacheRelativePath = sourceRelativePath + ".streamingimage"; + AZStd::string cacheRelativePath = AZStd::string::format("%s.%s", sourceRelativePath.c_str(), streamingImageExtension); bool textureExists = CheckIfFileExists(sourceRelativePath, cacheRelativePath); if (!textureExists) @@ -859,27 +836,13 @@ bool CSprite::LoadImage(const AZStd::string& nameTex, AZ::Data::Instance GetImage() { return m_image; } + AZ::Data::Instance GetImage(); public: // static member functions @@ -84,10 +83,15 @@ public: // static member functions //! Replaces baseSprite with newSprite with proper ref-count handling and null-checks. static void ReplaceSprite(ISprite** baseSprite, ISprite* newSprite); -private: - static bool LoadTexture(const string& texturePathname, const string& pathname, ITexture*& texture); - static void ReleaseTexture(ITexture*& texture); + //! Pathname allows any of the following: + //! 1. image source/product path (will use pathname to look for an existing .sprite sidecar file) + //! 2. .sprite source/product path (will use pathname to look for an existing image file with a supported extension) + //! 3. legacy .dds product path (will use pathname to look for an existing texture file with a supported extension) + static bool FixUpSourceImagePathFromUserDefinedPath(const AZStd::string& userDefinedPath, AZStd::string& sourceImagePath); + + static AZStd::string GetImageSourcePathFromProductPath(const AZStd::string& productPathname); +private: static bool LoadImage(const AZStd::string& nameTex, AZ::Data::Instance& image); static void ReleaseImage(AZ::Data::Instance& image); @@ -112,7 +116,6 @@ private: // data string m_pathname; string m_texturePathname; Borders m_borders; - ITexture* m_texture; AZ::Data::Instance m_image; int m_numSpriteSheetCellTags; //!< Number of Cell child-tags in sprite XML; unfortunately needed to help with serialization. diff --git a/Gems/LyShine/Code/Source/UiImageComponent.cpp b/Gems/LyShine/Code/Source/UiImageComponent.cpp index 02ea1467dc..9cf923a460 100644 --- a/Gems/LyShine/Code/Source/UiImageComponent.cpp +++ b/Gems/LyShine/Code/Source/UiImageComponent.cpp @@ -34,9 +34,8 @@ #include #include "UiSerialize.h" -#include "Sprite.h" #include "UiLayoutHelpers.h" - +#include "Sprite.h" #include "RenderGraph.h" namespace @@ -281,6 +280,20 @@ namespace 14, 15, 21, 21, 20, 14, // center quad }; + AZ::Data::Instance GetSpriteImage(ISprite* sprite) + { + AZ::Data::Instance image; + if (sprite) + { + CSprite* cSprite = dynamic_cast(sprite); // LYSHINE_ATOM_TODO - find a different solution from downcasting + if (cSprite) + { + image = cSprite->GetImage(); + } + } + + return image; + } } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -471,20 +484,12 @@ void UiImageComponent::Render(LyShine::IRenderGraph* renderGraph) renderGraph->AddPrimitive(&m_cachedPrimitive, texture, isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, m_blendMode); #else - AZ::Data::Instance image; - if (sprite) - { - CSprite* cSprite = static_cast(sprite); // LYSHINE_ATOM_TODO - find a different solution from downcasting - if (cSprite) - { - image = cSprite->GetImage(); - } - } + AZ::Data::Instance image = GetSpriteImage(sprite); bool isClampTextureMode = m_imageType == ImageType::Tiled ? false : true; bool isTextureSRGB = IsSpriteTypeRenderTarget() && m_isRenderTargetSRGB; bool isTexturePremultipliedAlpha = false; // we are not rendering from a render target with alpha in it - LyShine::RenderGraph* lyRenderGraph = static_cast(renderGraph); // LYSHINE_ATOM_TODO - find a different solution from downcasting + LyShine::RenderGraph* lyRenderGraph = dynamic_cast(renderGraph); // LYSHINE_ATOM_TODO - find a different solution from downcasting if (lyRenderGraph) { lyRenderGraph->AddPrimitiveAtom(&m_cachedPrimitive, image, isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, m_blendMode); @@ -880,8 +885,7 @@ float UiImageComponent::GetTargetWidth(float /*maxWidth*/) { float targetWidth = 0.0f; - ITexture* texture = (m_sprite) ? m_sprite->GetTexture() : nullptr; - if (texture) + if (m_sprite) { switch (m_imageType) { @@ -915,8 +919,7 @@ float UiImageComponent::GetTargetHeight(float /*maxHeight*/) { float targetHeight = 0.0f; - ITexture* texture = (m_sprite) ? m_sprite->GetTexture() : nullptr; - if (texture) + if (m_sprite) { switch (m_imageType) { @@ -1037,8 +1040,7 @@ void UiImageComponent::Reflect(AZ::ReflectContext* context) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ_CRC("RefreshEntireTree", 0xefbc823c)); editInfo->DataElement("Sprite", &UiImageComponent::m_spritePathname, "Sprite path", "The sprite path. Can be overridden by another component such as an interactable.") ->Attribute(AZ::Edit::Attributes::Visibility, &UiImageComponent::IsSpriteTypeAsset) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiImageComponent::OnEditorSpritePathnameChange) - ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ_CRC("RefreshEntireTree", 0xefbc823c)); + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiImageComponent::OnEditorSpritePathnameChange); editInfo->DataElement(AZ::Edit::UIHandlers::ComboBox, &UiImageComponent::m_spriteSheetCellIndex, "Index", "Sprite-sheet index. Defines which cell in a sprite-sheet is displayed.") ->Attribute(AZ::Edit::Attributes::Visibility, &UiImageComponent::IsSpriteTypeSpriteSheet) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiImageComponent::OnIndexChange) @@ -2364,7 +2366,8 @@ void UiImageComponent::SnapOffsetsToFixedImage() } // if the image has no texture it will not use Fixed rendering so do nothing - if (!m_sprite || !m_sprite->GetTexture()) + AZ::Data::Instance image = GetSpriteImage(m_sprite); + if (!image) { return; } diff --git a/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp b/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp index e6cbef8386..df77a003ae 100644 --- a/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp +++ b/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp @@ -12,6 +12,9 @@ #include "LyShine_precompiled.h" #include "UiImageSequenceComponent.h" +#include "Sprite.h" +#include "RenderGraph.h" + #include #include #include @@ -100,7 +103,7 @@ void UiImageSequenceComponent::Render(LyShine::IRenderGraph* renderGraph) return; } - ISprite* sprite = m_spriteList[m_sequenceIndex]; + CSprite* sprite = dynamic_cast(m_spriteList[m_sequenceIndex]); // get fade value (tracked by UiRenderer) and compute the desired alpha for the image float fade = renderGraph->GetAlphaFade(); @@ -158,15 +161,23 @@ void UiImageSequenceComponent::Render(LyShine::IRenderGraph* renderGraph) } } - ITexture* texture = (sprite) ? sprite->GetTexture() : nullptr; + AZ::Data::Instance image; + if (sprite) + { + image = sprite->GetImage(); + } bool isClampTextureMode = false; bool isTextureSRGB = false; bool isTexturePremultipliedAlpha = false; LyShine::BlendMode blendMode = LyShine::BlendMode::Normal; // Add the quad to the render graph - renderGraph->AddPrimitive(&m_cachedPrimitive, texture, - isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode); + LyShine::RenderGraph* lyRenderGraph = dynamic_cast(renderGraph); + if (lyRenderGraph) + { + lyRenderGraph->AddPrimitiveAtom(&m_cachedPrimitive, image, + isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode); + } } } diff --git a/Gems/LyShine/Code/Source/UiInteractableComponent.cpp b/Gems/LyShine/Code/Source/UiInteractableComponent.cpp index b665bbe1dc..e4ba507340 100644 --- a/Gems/LyShine/Code/Source/UiInteractableComponent.cpp +++ b/Gems/LyShine/Code/Source/UiInteractableComponent.cpp @@ -546,6 +546,7 @@ void UiInteractableComponent::Reflect(AZ::ReflectContext* context) ->Handler(); } + UiInteractableStateAction::Reflect(context); UiInteractableStateColor::Reflect(context); UiInteractableStateAlpha::Reflect(context); UiInteractableStateSprite::Reflect(context); diff --git a/Gems/LyShine/Code/Source/UiInteractableState.cpp b/Gems/LyShine/Code/Source/UiInteractableState.cpp index f5d703d87a..965899a958 100644 --- a/Gems/LyShine/Code/Source/UiInteractableState.cpp +++ b/Gems/LyShine/Code/Source/UiInteractableState.cpp @@ -41,6 +41,16 @@ void UiInteractableStateAction::SetInteractableEntity(AZ::EntityId interactableE m_interactableEntity = interactableEntityId; } +//////////////////////////////////////////////////////////////////////////////////////////////////// +void UiInteractableStateAction::Reflect(AZ::ReflectContext* context) +{ + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class(); + } +} + + //////////////////////////////////////////////////////////////////////////////////////////////////// void UiInteractableStateAction::Init(AZ::EntityId interactableEntityId) { @@ -128,8 +138,8 @@ void UiInteractableStateColor::Reflect(AZ::ReflectContext* context) if (serializeContext) { - serializeContext->Class() - ->Version(2, &VersionConverter) + serializeContext->Class() + ->Version(3, &VersionConverter) ->Field("TargetEntity", &UiInteractableStateColor::m_targetEntity) ->Field("Color", &UiInteractableStateColor::m_color); @@ -223,8 +233,8 @@ void UiInteractableStateAlpha::Reflect(AZ::ReflectContext* context) if (serializeContext) { - serializeContext->Class() - ->Version(1) + serializeContext->Class() + ->Version(2) ->Field("TargetEntity", &UiInteractableStateAlpha::m_targetEntity) ->Field("Alpha", &UiInteractableStateAlpha::m_alpha); @@ -379,8 +389,8 @@ void UiInteractableStateSprite::Reflect(AZ::ReflectContext* context) if (serializeContext) { - serializeContext->Class() - ->Version(3) + serializeContext->Class() + ->Version(4) ->Field("TargetEntity", &UiInteractableStateSprite::m_targetEntity) ->Field("Sprite", &UiInteractableStateSprite::m_spritePathname) ->Field("Index", &UiInteractableStateSprite::m_spriteSheetCellIndex); @@ -633,8 +643,8 @@ void UiInteractableStateFont::Reflect(AZ::ReflectContext* context) if (serializeContext) { - serializeContext->Class() - ->Version(1) + serializeContext->Class() + ->Version(2) ->Field("TargetEntity", &UiInteractableStateFont::m_targetEntity) ->Field("FontFileName", &UiInteractableStateFont::m_fontFilename) ->Field("EffectIndex", &UiInteractableStateFont::m_fontEffectIndex); diff --git a/Gems/LyShine/Code/Source/UiInteractableState.h b/Gems/LyShine/Code/Source/UiInteractableState.h index 966c24f202..81e9ac48e1 100644 --- a/Gems/LyShine/Code/Source/UiInteractableState.h +++ b/Gems/LyShine/Code/Source/UiInteractableState.h @@ -42,6 +42,8 @@ public: // member functions virtual ~UiInteractableStateAction() {} + static void Reflect(AZ::ReflectContext* context); + //! Called from the Init of the UiInteractableComponent virtual void Init(AZ::EntityId); diff --git a/Gems/LyShine/Code/Source/UiParticleEmitterComponent.cpp b/Gems/LyShine/Code/Source/UiParticleEmitterComponent.cpp index e54f61fbfa..3c9a871847 100644 --- a/Gems/LyShine/Code/Source/UiParticleEmitterComponent.cpp +++ b/Gems/LyShine/Code/Source/UiParticleEmitterComponent.cpp @@ -13,6 +13,8 @@ #include "UiParticleEmitterComponent.h" #include "EditorPropertyTypes.h" +#include "Sprite.h" +#include "RenderGraph.h" #include #include @@ -21,7 +23,6 @@ #include #include -#include #include #include @@ -764,6 +765,12 @@ void UiParticleEmitterComponent::InGamePostActivate() //////////////////////////////////////////////////////////////////////////////////////////////////// void UiParticleEmitterComponent::Render(LyShine::IRenderGraph* renderGraph) { + AZ::u32 particlesToRender = AZ::GetMin(m_particleContainer.size(), m_particleBufferSize); + if (particlesToRender == 0) + { + return; + } + AZ::Matrix4x4 transform = AZ::Matrix4x4::CreateIdentity(); AZ::Vector2 emitterOffset = AZ::Vector2::CreateZero(); @@ -781,9 +788,15 @@ void UiParticleEmitterComponent::Render(LyShine::IRenderGraph* renderGraph) EBUS_EVENT_ID_RESULT(transform, canvasID, UiCanvasBus, GetCanvasToViewportMatrix); } - AZ::u32 particlesToRender = AZ::GetMin(m_particleContainer.size(), m_particleBufferSize); - - ITexture* texture = (m_sprite) ? m_sprite->GetTexture() : nullptr; + AZ::Data::Instance image; + if (m_sprite) + { + CSprite* sprite = dynamic_cast(m_sprite); + if (sprite) + { + image = sprite->GetImage(); + } + } bool isClampTextureMode = true; bool isTextureSRGB = false; @@ -836,7 +849,11 @@ void UiParticleEmitterComponent::Render(LyShine::IRenderGraph* renderGraph) m_cachedPrimitive.m_numVertices = totalVerticesInserted; m_cachedPrimitive.m_numIndices = totalParticlesInserted * indicesPerParticle; - renderGraph->AddPrimitive(&m_cachedPrimitive, texture, isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, m_blendMode); + LyShine::RenderGraph* lyRenderGraph = dynamic_cast(renderGraph); + if (lyRenderGraph) + { + lyRenderGraph->AddPrimitiveAtom(&m_cachedPrimitive, image, isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, m_blendMode); + } } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/LyShine/Code/Tests/SpriteTest.cpp b/Gems/LyShine/Code/Tests/SpriteTest.cpp index 1d45a6113c..29ef1eb7f2 100644 --- a/Gems/LyShine/Code/Tests/SpriteTest.cpp +++ b/Gems/LyShine/Code/Tests/SpriteTest.cpp @@ -68,6 +68,7 @@ namespace UnitTest AZStd::unique_ptr m_data; }; +#ifdef LYSHINE_ATOM_TODO // [LYN-3359] - render target support using Atom TEST_F(LyShineSpriteTest, Sprite_CanAcquireRenderTarget) { // initialize to create the static sprite cache @@ -130,6 +131,7 @@ namespace UnitTest CSprite::Shutdown(); delete mockTexture; } +#endif } //namespace UnitTest AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas index 2e3ab0121f..3bcd4f3db3 100644 --- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas +++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas @@ -56,7 +56,7 @@ - + diff --git a/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp b/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp index 1bd2bd10be..b2055f2a0c 100644 --- a/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp +++ b/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp @@ -78,8 +78,9 @@ namespace LyShineExamples } //////////////////////////////////////////////////////////////////////////////////////////////////// - void UiCustomImageComponent::Render(LyShine::IRenderGraph* renderGraph) + void UiCustomImageComponent::Render([[maybe_unused]] LyShine::IRenderGraph* renderGraph) { +#ifdef LYSHINE_ATOM_TODO // [LYN-3635] convert to use Atom // get fade value (tracked by UiRenderer) and compute the desired alpha for the image float fade = renderGraph->GetAlphaFade(); float desiredAlpha = m_overrideAlpha * fade; @@ -126,6 +127,7 @@ namespace LyShineExamples bool isTexturePremultipliedAlpha = false; // we are not rendering from a render target with alpha in it LyShine::BlendMode blendMode = LyShine::BlendMode::Normal; renderGraph->AddPrimitive(&m_cachedPrimitive, texture, m_clamp, isTextureSRGB, isTexturePremultipliedAlpha, blendMode); +#endif } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp b/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp index cd0dfb02b3..1ee2ddc1c8 100644 --- a/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp +++ b/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp @@ -105,34 +105,11 @@ namespace Maestro MaestroAllocatorScope::DeactivateAllocators(); } - ////////////////////////////////////////////////////////////////////////// - void CSystemEventListener_Movie::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam) - { - switch (event) - { - case ESYSTEM_EVENT_LEVEL_POST_UNLOAD: - { - STLALLOCATOR_CLEANUP; - CLightAnimWrapper::ReconstructCache(); - break; - } - } - } - /////////////////////////////////////////////////////////////////////////////////////////////// void MaestroSystemComponent::OnCrySystemInitialized(ISystem& system, const SSystemInitParams& startupParams) { if (!startupParams.bSkipMovie) { - // OnCrySystemInitialized should only ever be called once, and we should be the only one initializing gEnv->pMovieSystem - AZ_Assert(!m_movieSystemEventListener && gEnv && !gEnv->pMovieSystem, "MaestroSystemComponent::OnCrySystemInitialized - movie system was alread initialized."); - - if (!m_movieSystemEventListener) - { - m_movieSystemEventListener.reset(new CSystemEventListener_Movie); - } - system.GetISystemEventDispatcher()->RegisterListener(m_movieSystemEventListener.get()); - // Create the movie System m_movieSystem.reset(new CMovieSystem(&system)); gEnv->pMovieSystem = m_movieSystem.get(); @@ -142,17 +119,6 @@ namespace Maestro /////////////////////////////////////////////////////////////////////////////////////////////// void MaestroSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system) { - // Remove the system movie listener and clean up allocations - if (m_movieSystemEventListener) - { - if (gEnv && gEnv->pSystem && gEnv->pSystem->GetISystemEventDispatcher()) - { - gEnv->pSystem->GetISystemEventDispatcher()->RemoveListener(m_movieSystemEventListener.get()); - } - // delete m_movieSystemEventListener - m_movieSystemEventListener.reset(); - } - if (gEnv && gEnv->pMovieSystem) { gEnv->pMovieSystem = nullptr; diff --git a/Gems/Maestro/Code/Source/MaestroSystemComponent.h b/Gems/Maestro/Code/Source/MaestroSystemComponent.h index ca8ae35d06..39a087eaa7 100644 --- a/Gems/Maestro/Code/Source/MaestroSystemComponent.h +++ b/Gems/Maestro/Code/Source/MaestroSystemComponent.h @@ -42,13 +42,6 @@ namespace Maestro void Deactivate() override; }; - ////////////////////////////////////////////////////////////////////////// - struct CSystemEventListener_Movie - : public ISystemEventListener - { - void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) override; - }; - ////////////////////////////////////////////////////////////////////////// class MaestroSystemComponent : public AZ::Component @@ -91,6 +84,5 @@ namespace Maestro private: // singletons representing the movie system AZStd::unique_ptr m_movieSystem; - AZStd::unique_ptr m_movieSystemEventListener; }; } diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h similarity index 95% rename from Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h index 924fd78391..c69623a9e9 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include namespace Multiplayer { @@ -102,7 +102,8 @@ namespace Multiplayer AZ::TimeMs m_lastInputReceivedTimeMs = AZ::TimeMs{ 0 }; AZ::TimeMs m_lastCorrectionSentTimeMs = AZ::TimeMs{ 0 }; - ClientInputId m_clientInputId = ClientInputId{ 0 }; + ClientInputId m_clientInputId = ClientInputId{ 0 }; // Clients incrementing inputId + ClientInputId m_lastClientInputId = ClientInputId{ 0 }; // Last inputId processed by the server ClientInputId m_lastCorrectionInputId = ClientInputId{ 0 }; ClientInputId m_lastMigratedInputId = ClientInputId{ 0 }; // Used to resend inputs that were queued during a migration event HostFrameId m_serverMigrateFrameId = InvalidHostFrameId; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h similarity index 94% rename from Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerComponent.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h index 29348a698a..19689171c5 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponent.h @@ -15,7 +15,8 @@ #include #include #include -#include +#include +#include #include #include @@ -62,11 +63,15 @@ namespace Multiplayer //! @} NetEntityId GetNetEntityId() const; - NetEntityRole GetNetEntityRole() const; + bool IsAuthority() const; + bool IsAutonomous() const; + bool IsServer() const; + bool IsClient() const; ConstNetworkEntityHandle GetEntityHandle() const; NetworkEntityHandle GetEntityHandle(); void MarkDirty(); + virtual void SetOwningConnectionId(AzNetworking::ConnectionId connectionId) = 0; virtual NetComponentId GetNetComponentId() const = 0; virtual bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole netEntityRole, NetworkEntityRpcMessage& rpcMessage) = 0; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerComponentRegistry.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponentRegistry.h similarity index 83% rename from Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerComponentRegistry.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponentRegistry.h index d06362ed4b..d3064d87dd 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerComponentRegistry.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerComponentRegistry.h @@ -14,7 +14,8 @@ #include #include -#include +#include +#include namespace Multiplayer { @@ -22,13 +23,15 @@ namespace Multiplayer { public: using PropertyNameLookupFunction = AZStd::function; - using RpcNameLookupFunction = AZStd::function; + using RpcNameLookupFunction = AZStd::function; + using AllocComponentInputFunction = AZStd::function()>; struct ComponentData { AZ::Name m_gemName; AZ::Name m_componentName; PropertyNameLookupFunction m_componentPropertyNameLookupFunction; RpcNameLookupFunction m_componentRpcNameLookupFunction; + AllocComponentInputFunction m_allocComponentInputFunction; }; //! Registers a multiplayer component with the multiplayer system. @@ -36,6 +39,11 @@ namespace Multiplayer //! @return the NetComponentId assigned to this particular component NetComponentId RegisterMultiplayerComponent(const ComponentData& componentData); + //! Allocates a new component input for the provided netComponentId. + //! @param netComponentId the NetComponentId to allocate a component input for + //! @return pointer to the allocated component input, caller assumes ownership + AZStd::unique_ptr AllocateComponentInput(NetComponentId netComponentId); + //! Returns the gem name associated with the provided NetComponentId. //! @param netComponentId the NetComponentId to return the gem name of //! @return the name of the gem that contains the requested component diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerController.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerController.h similarity index 92% rename from Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerController.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerController.h index 89c47c40d4..a8017ef9d1 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerController.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/MultiplayerController.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include namespace Multiplayer @@ -47,9 +47,13 @@ namespace Multiplayer //! @return the networkId for the entity that owns this controller NetEntityId GetNetEntityId() const; - //! Returns the networkRole for the entity that owns this controller. - //! @return the networkRole for the entity that owns this controller - NetEntityRole GetNetEntityRole() const; + //! Returns true if this controller has authority. + //! @return boolean true if this controller has authority + bool IsAuthority() const; + + //! Returns true if this controller has autonomy (can locally predict). + //! @return boolean true if this controller has autonomy + bool IsAutonomous() const; //! Returns the raw AZ::Entity pointer for the entity that owns this controller. //! @return the raw AZ::Entity pointer for the entity that owns this controller diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetBindComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h similarity index 92% rename from Gems/Multiplayer/Code/Include/Multiplayer/NetBindComponent.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h index 464333e3b2..41503396fb 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetBindComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h @@ -20,10 +20,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -63,12 +63,17 @@ namespace Multiplayer NetEntityRole GetNetEntityRole() const; bool IsAuthority() const; + bool IsAutonomous() const; + bool IsServer() const; + bool IsClient() const; bool HasController() const; NetEntityId GetNetEntityId() const; const PrefabEntityId& GetPrefabEntityId() const; ConstNetworkEntityHandle GetEntityHandle() const; NetworkEntityHandle GetEntityHandle(); + void SetOwningConnectionId(AzNetworking::ConnectionId connectionId); + void SetAllowAutonomy(bool value); MultiplayerComponentInputVector AllocateComponentInputs(); bool IsProcessingInput() const; void CreateInput(NetworkInput& networkInput, float deltaTime); @@ -155,6 +160,7 @@ namespace Multiplayer bool m_isProcessingInput = false; bool m_isMigrationDataValid = false; bool m_needsToBeStopped = false; + bool m_allowAutonomy = false; // Set to true for the hosts controlled entity friend class NetworkEntityManager; friend class EntityReplicationManager; diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h similarity index 100% rename from Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IConnectionData.h b/Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h similarity index 97% rename from Gems/Multiplayer/Code/Include/Multiplayer/IConnectionData.h rename to Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h index 39fdb61435..1fb3003c7b 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IConnectionData.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IEntityDomain.h b/Gems/Multiplayer/Code/Include/Multiplayer/EntityDomains/IEntityDomain.h similarity index 96% rename from Gems/Multiplayer/Code/Include/Multiplayer/IEntityDomain.h rename to Gems/Multiplayer/Code/Include/Multiplayer/EntityDomains/IEntityDomain.h index 70215612b0..dd7a11bb4a 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IEntityDomain.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/EntityDomains/IEntityDomain.h @@ -12,7 +12,7 @@ #pragma once -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h index 4931fb167f..6a615465c2 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h @@ -15,8 +15,9 @@ #include #include #include -#include -#include +#include +#include +#include #include namespace AzNetworking @@ -101,28 +102,6 @@ namespace Multiplayer //! @return pointer to the network entity manager instance bound to this multiplayer instance virtual INetworkEntityManager* GetNetworkEntityManager() = 0; - //! Returns the gem name associated with the provided component index. - //! @param netComponentId the componentId to return the gem name of - //! @return the name of the gem that contains the requested component - virtual const char* GetComponentGemName(NetComponentId netComponentId) const = 0; - - //! Returns the component name associated with the provided component index. - //! @param netComponentId the componentId to return the component name of - //! @return the name of the component - virtual const char* GetComponentName(NetComponentId netComponentId) const = 0; - - //! Returns the property name associated with the provided component index and property index. - //! @param netComponentId the component index to return the property name of - //! @param propertyIndex the index of the network property to return the property name of - //! @return the name of the network property - virtual const char* GetComponentPropertyName(NetComponentId netComponentId, PropertyIndex propertyIndex) const = 0; - - //! Returns the Rpc name associated with the provided component index and rpc index. - //! @param netComponentId the componentId to return the property name of - //! @param rpcIndex the index of the rpc to return the rpc name of - //! @return the name of the requested rpc - virtual const char* GetComponentRpcName(NetComponentId netComponentId, RpcIndex rpcIndex) const = 0; - //! Retrieve the stats object bound to this multiplayer instance. //! @return the stats object bound to this multiplayer instance MultiplayerStats& GetStats() { return m_stats; } diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h index 1bee9867e3..e9f3865563 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h @@ -130,3 +130,14 @@ AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::PropertyIndex); AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::RpcIndex); AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::ClientInputId); AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::HostFrameId); + +namespace AZ +{ + AZ_TYPE_INFO_SPECIALIZE(Multiplayer::HostId, "{D04B3363-8E1B-4193-8B2B-D2140389C9D5}"); + AZ_TYPE_INFO_SPECIALIZE(Multiplayer::NetEntityId, "{05E4C08B-3A1B-4390-8144-3767D8E56A81}"); + AZ_TYPE_INFO_SPECIALIZE(Multiplayer::NetComponentId, "{8AF3B382-F187-4323-9014-B380638767E3}"); + AZ_TYPE_INFO_SPECIALIZE(Multiplayer::PropertyIndex, "{F4460210-024D-4B3B-A10A-04B669C34230}"); + AZ_TYPE_INFO_SPECIALIZE(Multiplayer::RpcIndex, "{EBB1C475-FA03-4111-8C84-985377434B9B}"); + AZ_TYPE_INFO_SPECIALIZE(Multiplayer::ClientInputId, "{35BF3504-CEC9-4406-A275-C633A17FBEFB}"); + AZ_TYPE_INFO_SPECIALIZE(Multiplayer::HostFrameId, "{DF17F6F3-48C6-4B4A-BBD9-37DA03162864}"); +} // namespace AZ diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/ReplicationRecord.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h similarity index 100% rename from Gems/Multiplayer/Code/Include/Multiplayer/ReplicationRecord.h rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/INetworkEntityManager.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h similarity index 99% rename from Gems/Multiplayer/Code/Include/Multiplayer/INetworkEntityManager.h rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h index 17224e64cb..72dbe201e5 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/INetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntityHandle.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/NetworkEntityHandle.h similarity index 99% rename from Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntityHandle.h rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/NetworkEntityHandle.h index 813589fac6..21d4ae9c62 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntityHandle.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/NetworkEntityHandle.h @@ -138,4 +138,4 @@ namespace Multiplayer }; } -#include +#include diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntityHandle.inl b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/NetworkEntityHandle.inl similarity index 100% rename from Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntityHandle.inl rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/NetworkEntityHandle.inl diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntityRpcMessage.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h similarity index 100% rename from Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntityRpcMessage.h rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntityUpdateMessage.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h similarity index 100% rename from Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntityUpdateMessage.h rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerComponentInput.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/IMultiplayerComponentInput.h similarity index 86% rename from Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerComponentInput.h rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/IMultiplayerComponentInput.h index b26feadc4f..7af1bf3f60 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayerComponentInput.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/IMultiplayerComponentInput.h @@ -28,8 +28,9 @@ namespace Multiplayer { public: virtual ~IMultiplayerComponentInput() = default; - virtual NetComponentId GetComponentId() const = 0; + virtual NetComponentId GetNetComponentId() const = 0; virtual bool Serialize(AzNetworking::ISerializer& serializer) = 0; + virtual IMultiplayerComponentInput& operator= (const IMultiplayerComponentInput&) { return *this; } }; using MultiplayerComponentInputVector = AZStd::vector>; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h similarity index 85% rename from Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput.h rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h index 9c6d2ce66a..b2e0134ea9 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h @@ -12,9 +12,9 @@ #pragma once -#include -#include -#include +#include +#include +#include #include namespace Multiplayer @@ -57,15 +57,15 @@ namespace Multiplayer IMultiplayerComponentInput* FindComponentInput(NetComponentId componentId); template - const InputType* FindInput() const + const InputType* FindComponentInput() const { - return static_cast(FindInput(InputType::s_Type)); + return static_cast(FindComponentInput(InputType::s_netComponentId)); } template - InputType* FindInput() + InputType* FindComponentInput() { - return static_cast(FindInput(InputType::s_Type)); + return static_cast(FindComponentInput(InputType::s_netComponentId)); } private: diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/INetworkTime.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h similarity index 100% rename from Gems/Multiplayer/Code/Include/Multiplayer/INetworkTime.h rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/RewindableObject.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h similarity index 97% rename from Gems/Multiplayer/Code/Include/Multiplayer/RewindableObject.h rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h index 9e1655aec7..d5b7d563ab 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/RewindableObject.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include #include #include @@ -115,4 +115,4 @@ namespace AZ AZ_TYPE_INFO_TEMPLATE(Multiplayer::RewindableObject, "{B2937B44-FEE1-4277-B1E0-863DE76D363F}", AZ_TYPE_INFO_TYPENAME, AZ_TYPE_INFO_AUTO); } -#include +#include diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/RewindableObject.inl b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl similarity index 100% rename from Gems/Multiplayer/Code/Include/Multiplayer/RewindableObject.inl rename to Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IReplicationWindow.h b/Gems/Multiplayer/Code/Include/Multiplayer/ReplicationWindows/IReplicationWindow.h similarity index 96% rename from Gems/Multiplayer/Code/Include/Multiplayer/IReplicationWindow.h rename to Gems/Multiplayer/Code/Include/Multiplayer/ReplicationWindows/IReplicationWindow.h index d0192e8aa4..5d90fc286b 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IReplicationWindow.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/ReplicationWindows/IReplicationWindow.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja index 453d74c907..7bb4bdcc2c 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponentTypes_Source.jinja @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include {% for Component in dataFiles %} {% set ComponentDerived = Component.attrib['OverrideComponent']|booleanTrue %} {% set ControllerDerived = Component.attrib['OverrideController']|booleanTrue %} @@ -38,7 +38,11 @@ namespace {{ Namespace }} componentData.m_componentName = AZ::Name("{{ Component.attrib['Name'] }}"); componentData.m_componentPropertyNameLookupFunction = {{ ComponentBaseName }}::GetNetworkPropertyName; componentData.m_componentRpcNameLookupFunction = {{ ComponentBaseName }}::GetRpcName; + componentData.m_allocComponentInputFunction = {{ ComponentBaseName }}::AllocateComponentInput; {{ ComponentBaseName }}::s_netComponentId = multiplayerComponentRegistry->RegisterMultiplayerComponent(componentData); +{% if NetworkInputCount > 0 %} + {{ ComponentName }}NetworkInput::s_netComponentId = {{ ComponentBaseName }}::s_netComponentId; +{% endif %} stats.ReserveComponentStats({{ ComponentBaseName }}::s_netComponentId, static_cast({{ NetworkPropertyCount }}), static_cast({{ RpcCount }})); } {% endfor %} diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja index d211b933c5..4279c26cf2 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Common.jinja @@ -207,11 +207,11 @@ namespace {{ Component.attrib['Namespace'] }} public: AZ_MULTIPLAYER_COMPONENT({{ Component.attrib['Namespace'] }}::{{ ComponentName }}, s_{{ LowerFirst(ComponentName) }}ConcreteUuid, {{ Component.attrib['Namespace'] }}::{{ ComponentNameBase }}); - static void Reflect([[maybe_unused]] AZ::ReflectContext* context); + static void Reflect(AZ::ReflectContext* context); - void OnInit() override {} - void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} - void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} + void OnInit() override; + void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override; + void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override; {{ DeclareRpcHandlers(Component, 'Authority', 'Client', true)|indent(8) }} }; @@ -222,15 +222,15 @@ namespace {{ Component.attrib['Namespace'] }} : public {{ ControllerNameBase }} { public: - {{ ControllerName }}({{ ComponentName }}& parent) : {{ ControllerNameBase }}(parent) {} + {{ ControllerName }}({{ ComponentName }}& parent); - void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} - void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {} + void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override; + void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override; {% if NetworkInputCount > 0 %} //! Common input processing logic for the NetworkInput. //! @param input input structure to process //! @param deltaTime amount of time to integrate the provided inputs over - void ProcessInput([[maybe_unused]] Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime) override {} + void ProcessInput(Multiplayer::NetworkInput& input, float deltaTime) override; {%endif %} {{ DeclareRpcHandlers(Component, 'Server', 'Authority', true)|indent(8) }} {{ DeclareRpcHandlers(Component, 'Client', 'Authority', true)|indent(8) }} @@ -239,10 +239,12 @@ namespace {{ Component.attrib['Namespace'] }} }; {% endif %} } -{% if ComponentDerived %} /// Place in your .cpp +#include <{{ Component.attrib['OverrideInclude'] }}> + namespace {{ Component.attrib['Namespace'] }} { +{% if ComponentDerived %} void {{ ComponentName }}::{{ ComponentName }}::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -251,9 +253,43 @@ namespace {{ Component.attrib['Namespace'] }} serializeContext->Class<{{ ComponentName }}, {{ ComponentNameBase }}>() ->Version(1); } + {{ ComponentNameBase }}::Reflect(context); } -} + + void {{ ComponentName }}::OnInit() + { + } + + void {{ ComponentName }}::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + } + + void {{ ComponentName }}::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + } + {% endif %} +{% if ControllerDerived %} + {{ ControllerName }}::{{ ControllerName }}({{ ComponentName }}& parent) + : {{ ControllerNameBase }}(parent) + { + } + + void {{ ControllerName }}::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + } + + void {{ ControllerName }}::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) + { + } +{% if NetworkInputCount > 0 %} + + void {{ ControllerName }}::ProcessInput([[maybe_unused]] Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime) + { + } +{% endif %} +{% endif %} +} */ {% else %} // NOTE: diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja index c22945c983..8ae8fee618 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja @@ -7,25 +7,25 @@ {% macro DeclareNetworkPropertyGetter(Property) %} {% set PropertyName = UpperFirst(Property.attrib['Name']) %} {% if Property.attrib['Container'] == 'Array' %} -{% if Property.attrib['GenerateEventBindings']|booleanTrue %} -void {{ PropertyName }}AddEvent(AZ::Event::Handler& handler); -{% endif %} const AZStd::array<{% if Property.attrib['IsRewindable']|booleanTrue %}Multiplayer::RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::k_RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Array() const; const {{ Property.attrib['Type'] }} &Get{{ PropertyName }}(int32_t index) const; -{% elif Property.attrib['Container'] == 'Vector' %} {% if Property.attrib['GenerateEventBindings']|booleanTrue %} void {{ PropertyName }}AddEvent(AZ::Event::Handler& handler); -void {{ PropertyName }}SizeChangedAddEvent(AZ::Event::Handler& handler); {% endif %} +{% elif Property.attrib['Container'] == 'Vector' %} const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Vector() const; const {{ Property.attrib['Type'] }} &Get{{ PropertyName }}(int32_t index) const; const {{ Property.attrib['Type'] }} &{{ PropertyName }}GetBack() const; uint32_t {{ PropertyName }}GetSize() const; +{% if Property.attrib['GenerateEventBindings']|booleanTrue %} +void {{ PropertyName }}AddEvent(AZ::Event::Handler& handler); +void {{ PropertyName }}SizeChangedAddEvent(AZ::Event::Handler& handler); +{% endif %} {% else %} +const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}() const; {% if Property.attrib['GenerateEventBindings']|booleanTrue %} void {{ PropertyName }}AddEvent(AZ::Event<{{ Property.attrib['Type'] }}>::Handler& handler); {% endif %} -const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}() const; {% endif %} {% endmacro %} {# @@ -221,14 +221,14 @@ AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] } #include #include #include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include {% call(Include) AutoComponentMacros.ParseIncludes(Component) %} #include <{{ Include.attrib['File'] }}> {% endcall %} @@ -323,17 +323,20 @@ namespace {{ Component.attrib['Namespace'] }} }; {% if NetworkInputCount > 0 %} - class NetworkInput + class {{ ComponentName }}NetworkInput : public Multiplayer::IMultiplayerComponentInput { public: - Multiplayer::NetComponentId GetComponentId() const override; - INetworkInput& operator=(const INetworkInput& rhs) override; - bool Serialize(AzNetworking::ISerializer& serializer); + Multiplayer::NetComponentId GetNetComponentId() const override; + bool Serialize(AzNetworking::ISerializer& serializer) override; + Multiplayer::IMultiplayerComponentInput& operator =(const Multiplayer::IMultiplayerComponentInput& rhs) override; {% call(Input) AutoComponentMacros.ParseNetworkInputs(Component) %} {{ Input.attrib['Type'] }} m_{{ LowerFirst(Input.attrib['Name']) }} = {{ Input.attrib['Type'] }}({{ Input.attrib['Init'] }}); {% endcall %} + + static Multiplayer::NetComponentId s_netComponentId; + friend void RegisterMultiplayerComponents(); }; {% endif %} @@ -410,11 +413,14 @@ namespace {{ Component.attrib['Namespace'] }} static void Reflect(AZ::ReflectContext* context); static void ReflectToEditContext(AZ::ReflectContext* context); + static void ReflectToBehaviorContext(AZ::ReflectContext* context); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static AZStd::unique_ptr AllocateComponentInput(); + {{ ComponentBaseName }}() = default; ~{{ ComponentBaseName }}() override = default; @@ -428,12 +434,14 @@ namespace {{ Component.attrib['Namespace'] }} {% endif %} {{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Server', false)|indent(8) -}} + {{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Autonomous', false)|indent(8) -}} {{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Client', false)|indent(8) }} {{ DeclareArchetypePropertyGetters(Component)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Server', 'Authority', false)|indent(8) }} //! MultiplayerComponent interface //! @{ + void SetOwningConnectionId(AzNetworking::ConnectionId connectionId) override; Multiplayer::NetComponentId GetNetComponentId() const override; bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, Multiplayer::NetEntityRole remoteRole, Multiplayer::NetworkEntityRpcMessage& rpcMessage) override; bool SerializeStateDeltaMessage(Multiplayer::ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer) override; @@ -514,7 +522,7 @@ namespace {{ Component.attrib['Namespace'] }} //! Archetype Properties {{ DeclareArchetypePropertyVars(Component)|indent(8) }} {% call(Type, Name) AutoComponentMacros.ParseComponentServiceTypeAndName(Component) %} - {{ Type }}* {{ Name }} = nullptr; + {{ Type }}* {{ Name }} = nullptr; {% endcall %} static Multiplayer::NetComponentId s_netComponentId; diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index 200d38910b..141c35e1fe 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -476,7 +476,7 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re {%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%} {% endcall %} {% if networkPropertyCount.value > 0 %} - MultiplayerStats& stats = GetMultiplayer()->GetStats(); + Multiplayer::MultiplayerStats& stats = Multiplayer::GetMultiplayer()->GetStats(); // We modify the record if we are writing an update so that we don't notify for a change that really didn't change the value (just a duplicated send from the server) [[maybe_unused]] bool modifyRecord = serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject; {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %} @@ -492,9 +492,9 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re if (deltaRecord.AnySet()) { {% if Property.attrib['Container'] == 'Vector' %} - NovaNet::SerializableFixedSizeVectorDeltaStruct<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> deltaStruct(m_{{ LowerFirst(Property.attrib['Name']) }}, deltaRecord); + Multiplayer::SerializableFixedSizeVectorDeltaStruct<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> deltaStruct(m_{{ LowerFirst(Property.attrib['Name']) }}, deltaRecord); {% else %} - NovaNet::SerializableFixedSizeArrayDeltaStruct<{% if Property.attrib['IsRewindable']|booleanTrue %}Multiplayer::RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> deltaStruct(m_{{ Property.attrib['Name'] }}, deltaRecord); + Multiplayer::SerializableFixedSizeArrayDeltaStruct<{% if Property.attrib['IsRewindable']|booleanTrue %}Multiplayer::RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> deltaStruct(m_{{ Property.attrib['Name'] }}, deltaRecord); {% endif %} serializer.Serialize(deltaStruct, "{{ UpperFirst(Property.attrib['Name']) }}"); } @@ -509,7 +509,7 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re m_{{ LowerFirst(Property.attrib['Name']) }}, "{{ Property.attrib['Name'] }}", GetNetComponentId(), - static_cast({{ UpperFirst(Component.attrib['Name']) }}Internal::NetworkProperties::{{ UpperFirst(Property.attrib['Name']) }}), + static_cast({{ UpperFirst(Component.attrib['Name']) }}Internal::NetworkProperties::{{ UpperFirst(Property.attrib['Name']) }}), stats ); {% endif %} @@ -661,20 +661,75 @@ enum class NetworkProperties {# #} -{% macro DefineNetworkPropertyBehaviorReflection(Component, ReplicateFrom, ReplicateTo, ClassType) %} +{% macro DefineNetworkPropertyBehaviorReflection(Component, ReplicateFrom, ReplicateTo, ClassName) %} {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %} -{% if (Property.attrib['IsPublic'] | booleanTrue == true) %} -{% if Property.attrib['Container'] == 'Array' %} -->Event("Get{{ Property.attrib['Name'] }}", &{{ ClassType }}Bus::Events::Get{{ Property.attrib['Name'] }}) -{% elif Property.attrib['Container'] == 'Vector' %} -->Event("Get{{ Property.attrib['Name'] }}", &{{ ClassType }}Bus::Events::Get{{ Property.attrib['Name'] }}) -->Event("{{ Property.attrib['Name'] }}GetBack", &{{ ClassType }}Bus::Events::{{ Property.attrib['Name'] }}GetBack) -->Event("{{ Property.attrib['Name'] }}GetSize", &{{ ClassType }}Bus::Events::{{ Property.attrib['Name'] }}GetSize) -{% else %} -->Event("Get{{ Property.attrib['Name'] }}", &{{ ClassType }}Bus::Events::Get{{ Property.attrib['Name'] }}) -{% endif %} +{% if (Property.attrib['IsPublic'] | booleanTrue == true) and (Property.attrib['GenerateEventBindings'] | booleanTrue == true) -%} + // {{ UpperFirst(Property.attrib['Name']) }}: Replicate from {{ ReplicateFrom }} to {{ ReplicateTo }} + ->Method("Get{{ UpperFirst(Property.attrib['Name']) }}", [](AZ::EntityId id) -> {{ Property.attrib['Type'] }} + { + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id); + if (!entity) + { + AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str()) + return {{ Property.attrib['Type'] }}(); + } + + {{ ClassName }}* networkComponent = entity->FindComponent<{{ ClassName }}>(); + if (!networkComponent) + { + AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str()) + return {{ Property.attrib['Type'] }}(); + } + + return networkComponent->Get{{ UpperFirst(Property.attrib['Name']) }}(); + }) + ->Method("Set{{ UpperFirst(Property.attrib['Name']) }}", [](AZ::EntityId id, const {{ Property.attrib['Type'] }}& {{ LowerFirst(Property.attrib['Name']) }}) -> void + { + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id); + if (!entity) + { + AZ_Warning("Network Property", false, "{{ ClassName }} Set{{ UpperFirst(Property.attrib['Name']) }} failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str()) + return; + } + + {{ ClassName }}* networkComponent = entity->FindComponent<{{ ClassName }}>(); + if (!networkComponent) + { + AZ_Warning("Network Property", false, "{{ ClassName }} Set{{ UpperFirst(Property.attrib['Name']) }} method failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str()) + return; + } + + {{ ClassName }}Controller* controller = static_cast<{{ ClassName }}Controller*>(networkComponent->GetController()); + if (!controller) + { + AZ_Warning("Network Property", false, "{{ ClassName }} Set{{ UpperFirst(Property.attrib['Name']) }} method failed. Entity '%s' (id: %s) {{ ClassName }} is missing the network controller. Network controllers only spawn when some form of write access is available; for example, when you're server authoritatively controlling this entity, or you're a client predictively writing to your player entity. Please check your network context before attempting to set {{ UpperFirst(Property.attrib['Name']) }}.", entity->GetName().c_str(), id.ToString().c_str()) + return; + } + + controller->Set{{ UpperFirst(Property.attrib['Name']) }}({{ LowerFirst(Property.attrib['Name']) }}); + }) + ->Method("GetOn{{ UpperFirst(Property.attrib['Name']) }}ChangedEvent", [](AZ::EntityId id) -> AZ::Event<{{ Property.attrib['Type'] }}>* + { + AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id); + if (!entity) + { + AZ_Warning("Network Property", false, "{{ ClassName }} GetOn{{ UpperFirst(Property.attrib['Name']) }}ChangedEvent failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str()) + return nullptr; + } + + {{ ClassName }}* networkComponent = entity->FindComponent<{{ ClassName }}>(); + if (!networkComponent) + { + AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str()) + return nullptr; + } + + return &networkComponent->m_{{ LowerFirst(Property.attrib['Name']) }}Event; + }) + ->Attribute(AZ::Script::Attributes::AzEventDescription, AZ::BehaviorAzEventDescription{ "On {{ UpperFirst(Property.attrib['Name']) }} Changed Event", {"New {{ Property.attrib['Type'] }}"} }) + {% endif %} -{% endcall -%} +{% endcall %} {% endmacro %} {# @@ -805,6 +860,7 @@ m_{{ LowerFirst(Service.attrib['Name']) }} = FindComponent<{{ UpperFirst(Service {% endmacro %} {# + #} {% macro DefineNetworkPropertyEditConstruction(Component, ReplicateFrom, ReplicateTo, ClassName) %} {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %} @@ -902,8 +958,8 @@ m_{{ LowerFirst(Property.attrib['Name']) }} = m_{{ LowerFirst(Property.attrib['N #include #include #include -#include -#include +#include +#include {% if ComponentDerived or ControllerDerived %} #include <{{ Component.attrib['OverrideInclude'] }}> {% endif %} @@ -916,6 +972,9 @@ m_{{ LowerFirst(Property.attrib['Name']) }} = m_{{ LowerFirst(Property.attrib['N namespace {{ Component.attrib['Namespace'] }} { Multiplayer::NetComponentId {{ UpperFirst(ComponentBaseName) }}::s_netComponentId = Multiplayer::InvalidNetComponentId; +{% if NetworkInputCount > 0 %} + Multiplayer::NetComponentId {{ ComponentName }}NetworkInput::s_netComponentId = Multiplayer::InvalidNetComponentId; +{% endif %} namespace {{ UpperFirst(Component.attrib['Name']) }}Internal { @@ -1051,6 +1110,28 @@ namespace {{ Component.attrib['Namespace'] }} {{ GenerateModelReplicationRecordPredictableBits(Component, ClassType, 'Autonomous', 'Authority')|indent(8) }} } +{% if NetworkInputCount > 0 %} + Multiplayer::NetComponentId {{ ComponentName }}NetworkInput::GetNetComponentId() const + { + return {{ ComponentName }}NetworkInput::s_netComponentId; + } + + bool {{ ComponentName }}NetworkInput::Serialize(AzNetworking::ISerializer& serializer) + { +{% call(Input) AutoComponentMacros.ParseNetworkInputs(Component) %} + serializer.Serialize(m_{{ LowerFirst(Input.attrib['Name']) }}, "{{ UpperFirst(Input.attrib['Name']) }}"); +{% endcall %} + return serializer.IsValid(); + } + + Multiplayer::IMultiplayerComponentInput& {{ ComponentName }}NetworkInput::operator =([[maybe_unused]] const Multiplayer::IMultiplayerComponentInput& rhs) + { + AZ_Assert(s_netComponentId == rhs.GetNetComponentId(), "AttachNetSystemComponent was not called on the owning NetworkInput"); + *this = *static_cast(&rhs); + return *this; + } + +{% endif %} {{ ControllerBaseName }}::{{ ControllerBaseName }}({{ ComponentName }}& parent) : MultiplayerController(parent) { @@ -1107,10 +1188,10 @@ namespace {{ Component.attrib['Namespace'] }} {{ DefineRpcInvocations(Component, ControllerBaseName, 'Authority', 'Client', true)|indent(4) }} {% for Service in Component.iter('ComponentRelation') %} {% if (Service.attrib['HasController']|booleanTrue) and (Service.attrib['Constraint'] != 'Incompatible') %} - {{ Service.attrib['Name'] }}Controller* {{ ControllerBaseName }}::Get{{ Service.attrib['Name'] }}Controller() + {{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}Controller* {{ ControllerBaseName }}::Get{{ Service.attrib['Name'] }}Controller() { - MultiplayerComponent* controllerComponent = GetParent().Get{{ Service.attrib['Name'] }}(); - return static_cast<{{ Service.attrib['Name'] }}Controller*>(controllerComponent->GetController()); + Multiplayer::MultiplayerComponent* controllerComponent = GetParent().Get{{ Service.attrib['Name'] }}(); + return static_cast<{{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}Controller*>(controllerComponent->GetController()); } {% endif %} @@ -1131,6 +1212,7 @@ namespace {{ Component.attrib['Namespace'] }} {{ DefineArchetypePropertyReflection(Component, ComponentBaseName)|indent(16) }}; } ReflectToEditContext(context); + ReflectToBehaviorContext(context); } void {{ ComponentBaseName }}::{{ ComponentBaseName }}::ReflectToEditContext(AZ::ReflectContext* context) @@ -1162,9 +1244,29 @@ namespace {{ Component.attrib['Namespace'] }} } } + void {{ ComponentBaseName }}::{{ ComponentBaseName }}::ReflectToBehaviorContext(AZ::ReflectContext* context) + { + AZ::BehaviorContext* behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + behaviorContext->Class<{{ ComponentName }}>("{{ ComponentName }}") + ->Attribute(AZ::Script::Attributes::Module, "{{ LowerFirst(Component.attrib['Namespace']) }}") + ->Attribute(AZ::Script::Attributes::Category, "{{ UpperFirst(Component.attrib['Namespace']) }}") + + // Reflect Network Properties Get, Set, and OnChanged methods + {{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Authority', ComponentName) | indent(16) -}} + {{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Server', ComponentName) | indent(16) -}} + {{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Client', ComponentName) | indent(16) -}} + {{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Autonomous', ComponentName) | indent(16) -}} + {{ DefineNetworkPropertyBehaviorReflection(Component, 'Autonomous', 'Authority', ComponentName) | indent(16) -}} + {{- DefineArchetypePropertyBehaviorReflection(Component, ComponentName) | indent(16) }} + ; + } + } + void {{ ComponentBaseName }}::{{ ComponentBaseName }}::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { - provided.push_back(AZ_CRC_CE("{{ ComponentName }}Service")); + provided.push_back(AZ_CRC_CE("{{ ComponentName }}")); } void {{ ComponentBaseName }}::{{ ComponentBaseName }}::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) @@ -1184,12 +1286,21 @@ namespace {{ Component.attrib['Namespace'] }} void {{ ComponentBaseName }}::{{ ComponentBaseName }}::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) { - incompatible.push_back(AZ_CRC_CE("{{ ComponentName }}Service")); + incompatible.push_back(AZ_CRC_CE("{{ ComponentName }}")); {% call(ComponentService) ParseComponentServiceNames(Component, ClassType, 'Incompatible') %} incompatible.push_back(AZ_CRC_CE("{{ ComponentService }}")); {% endcall %} } + AZStd::unique_ptr {{ ComponentBaseName }}::AllocateComponentInput() + { +{% if NetworkInputCount > 0 %} + return AZStd::make_unique<{{ ComponentName }}NetworkInput>(); +{% else %} + return nullptr; +{% endif %} + } + void {{ ComponentBaseName }}::Init() { if (m_netBindComponent == nullptr) @@ -1251,6 +1362,15 @@ namespace {{ Component.attrib['Namespace'] }} {{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', false)|indent(4) -}} {{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', true)|indent(4) }} + void {{ ComponentBaseName }}::SetOwningConnectionId([[maybe_unused]] AzNetworking::ConnectionId connectionId) + { +{% for Property in Component.iter('NetworkProperty') %} +{% if Property.attrib['IsRewindable']|booleanTrue %} + m_{{ LowerFirst(Property.attrib['Name']) }}.SetOwningConnectionId(connectionId); +{% endif %} +{% endfor %} + } + Multiplayer::NetComponentId {{ ComponentBaseName }}::GetNetComponentId() const { return s_netComponentId; @@ -1408,6 +1528,7 @@ namespace {{ Component.attrib['Namespace'] }} } {% endif %} +{% endfor %} const char* {{ ComponentBaseName }}::GetNetworkPropertyName([[maybe_unused]] Multiplayer::PropertyIndex propertyIndex) { {% if NetworkPropertyCount > 0 %} @@ -1437,6 +1558,5 @@ namespace {{ Component.attrib['Namespace'] }} {% endif %} return "Unknown Rpc"; } -{% endfor %} } {% endfor %} diff --git a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml index a5a7e8decd..94bdac2b5d 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml @@ -5,13 +5,13 @@ Namespace="Multiplayer" OverrideComponent="true" OverrideController="true" - OverrideInclude="Source/Components/LocalPredictionPlayerInputComponent.h" + OverrideInclude="Multiplayer/Components/LocalPredictionPlayerInputComponent.h" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - + - + diff --git a/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml b/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml index 1260075cba..2f934979b1 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml @@ -3,9 +3,9 @@ - - - + + + diff --git a/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml index e76ac75edc..96653a607c 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml @@ -5,7 +5,7 @@ Namespace="Multiplayer" OverrideComponent="true" OverrideController="true" - OverrideInclude="Source/Components/NetworkTransformComponent.h" + OverrideInclude="Multiplayer/Components/NetworkTransformComponent.h" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index b57c465df2..10a0d17e73 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -10,7 +10,7 @@ * */ -#include +#include #include #include #include @@ -81,12 +81,7 @@ namespace Multiplayer , m_migrateStartHandler([this](ClientInputId migratedInputId) { OnMigrateStart(migratedInputId); }) , m_migrateEndHandler([this]() { OnMigrateEnd(); }) { - if (GetNetEntityRole() == NetEntityRole::Autonomous) - { - m_autonomousUpdateEvent.Enqueue(AZ::TimeMs{ 1 }, true); - parent.GetNetBindComponent()->AddEntityMigrationStartEventHandler(m_migrateStartHandler); - parent.GetNetBindComponent()->AddEntityMigrationEndEventHandler(m_migrateEndHandler); - } + ; } void LocalPredictionPlayerInputComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) @@ -96,6 +91,13 @@ namespace Multiplayer m_allowMigrateClientInput = true; m_serverMigrateFrameId = GetNetworkTime()->GetHostFrameId(); } + + if (IsAutonomous()) + { + m_autonomousUpdateEvent.Enqueue(AZ::TimeMs{ 1 }, true); + GetParent().GetNetBindComponent()->AddEntityMigrationStartEventHandler(m_migrateStartHandler); + GetParent().GetNetBindComponent()->AddEntityMigrationEndEventHandler(m_migrateEndHandler); + } } void LocalPredictionPlayerInputComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) @@ -111,73 +113,57 @@ namespace Multiplayer [[maybe_unused]] const AzNetworking::PacketEncodingBuffer& clientState ) { - // After receiving the first input from the client, start the update event to check for slow hacking - if (!m_updateBankedTimeEvent.IsScheduled()) + if (invokingConnection == nullptr) { - m_updateBankedTimeEvent.Enqueue(sv_InputUpdateTimeMs, true); + // Discard any input messages that were locally dispatched or sent by disconnected clients + return; } - if (invokingConnection == nullptr) + const ClientInputId clientInputId = inputArray[0].GetClientInputId(); + if (clientInputId <= m_lastClientInputId) { - // Discard any input messages that were locally dispatched or sent by disconnected clients + AZLOG(NET_Prediction, "Discarding old or out of order move input (current: %u, received %u)", + aznumeric_cast(m_lastClientInputId), aznumeric_cast(clientInputId)); return; } + // After receiving the first input from the client, start the update event to check for slow hacking + if (!m_updateBankedTimeEvent.IsScheduled()) + { + m_updateBankedTimeEvent.Enqueue(sv_InputUpdateTimeMs, true); + } + const AZ::TimeMs currentTimeMs = AZ::GetElapsedTimeMs(); const double clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; m_lastInputReceivedTimeMs = currentTimeMs; // Keep track of last inputs received, also allows us to update frame ids m_lastInputReceived = inputArray; + SetLastInputId(m_lastInputReceived[0].GetClientInputId()); // Set this variable in case of migration - // Figure out which index from the input array we want - // we start at the oldest input that has not been processed - int32_t inputArrayIndex = -1; - for (int32_t i = NetworkInputArray::MaxElements - 1; i >= 0; --i) - { - // Find an input that is newer than the last one we processed - if (m_lastInputReceived[i].GetClientInputId() > GetLastInputId()) - { - inputArrayIndex = i; - break; - } - } - - if (inputArrayIndex < 0) + while (m_lastClientInputId < clientInputId) { - AZLOG - ( - NET_Prediction, - "Discarding old or out of order move input (current: %u, received %u)", - aznumeric_cast(GetLastInputId()), - aznumeric_cast(m_lastInputReceived[0].GetClientInputId()) - ); - return; - } + ++m_lastClientInputId; - bool lostInput = false; - if (GetLastInputId() < inputArray.GetPreviousInputId()) - { - // last move id processed is older than the previous input id, we missed some input packets - lostInput = true; - } + // Figure out which index from the input array we want + // If we have skipped an id, check if it was sent to us in the array. If we have lost too many, just use the oldest one in the array + const uint32_t deltaFrameId = aznumeric_cast(clientInputId - m_lastClientInputId); // always >= 0 because of while loop check + const uint32_t inputArrayIdx = AZStd::min(deltaFrameId, NetworkInputArray::MaxElements - 1); + const bool lostInput = deltaFrameId >= NetworkInputArray::MaxElements; // For logging only - SetLastInputId(m_lastInputReceived[0].GetClientInputId()); // Set this variable in case of migration - - while (inputArrayIndex >= 0) - { - NetworkInput& input = m_lastInputReceived[inputArrayIndex]; + NetworkInput &input = m_lastInputReceived[inputArrayIdx]; + input.SetClientInputId(m_lastClientInputId); // Anticheat, if we're receiving too many inputs, and fall outside our variable latency input window // Discard move input events, client may be speed hacking if (m_clientBankedTime < sv_MaxBankTimeWindowSec) { m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary - { ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); GetNetBindComponent()->ProcessInput(input, static_cast(clientInputRateSec)); } + if (lostInput) { AZLOG(NET_Prediction, "InputLost InputId=%u", aznumeric_cast(input.GetClientInputId())); @@ -191,7 +177,6 @@ namespace Multiplayer { AZLOG(NET_Prediction, "Dropped InputId=%u", aznumeric_cast(input.GetClientInputId())); } - --inputArrayIndex; } if (sv_EnableCorrections && (currentTimeMs - m_lastCorrectionSentTimeMs > sv_MinCorrectionTimeMs)) @@ -203,6 +188,14 @@ namespace Multiplayer const AZ::HashValue32 localAuthorityHash = hashSerializer.GetHash(); + AZLOG + ( + NET_Prediction, + "Hash values for ProcessInput: client=%u, server=%u", + aznumeric_cast(stateHash), + aznumeric_cast(localAuthorityHash) + ); + if (stateHash != localAuthorityHash) { // Produce correction for client @@ -540,21 +533,15 @@ namespace Multiplayer m_inputHistory.PopFront(); } - const size_t inputHistorySize = m_inputHistory.Size(); + const int64_t inputHistorySize = aznumeric_cast(m_inputHistory.Size()); // Form the rest of the input array using the n most recent elements in the history buffer // NOTE: inputArray[0] has already been initialized hence start at i = 1 - for (uint32_t i = 1; i < NetworkInputArray::MaxElements; ++i) + for (int64_t i = 1; i < aznumeric_cast(NetworkInputArray::MaxElements); ++i) { - if (i < inputHistorySize) - { - inputArray[i] = m_inputHistory[inputHistorySize - 1 - i]; - } - else // History is too small? - { - // Plug in the most recent input - inputArray[i] = input; - } + // Clamp to oldest element if history is too small + const int64_t historyIndex = AZStd::max(inputHistorySize - 1 - i, 0); + inputArray[i] = m_inputHistory[historyIndex]; } // Send the input to server (only when we are not migrating) diff --git a/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.cpp b/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.cpp index ae6fc50f5a..8542288b23 100644 --- a/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/MultiplayerComponent.cpp @@ -10,8 +10,8 @@ * */ -#include -#include +#include +#include #include namespace Multiplayer @@ -46,9 +46,24 @@ namespace Multiplayer return m_netBindComponent ? m_netBindComponent->GetNetEntityId() : InvalidNetEntityId; } - NetEntityRole MultiplayerComponent::GetNetEntityRole() const + bool MultiplayerComponent::IsAuthority() const { - return m_netBindComponent ? m_netBindComponent->GetNetEntityRole() : NetEntityRole::InvalidRole; + return m_netBindComponent ? m_netBindComponent->IsAuthority() : false; + } + + bool MultiplayerComponent::IsAutonomous() const + { + return m_netBindComponent ? m_netBindComponent->IsAutonomous() : false; + } + + bool MultiplayerComponent::IsServer() const + { + return m_netBindComponent ? m_netBindComponent->IsServer() : false; + } + + bool MultiplayerComponent::IsClient() const + { + return m_netBindComponent ? m_netBindComponent->IsClient() : false; } ConstNetworkEntityHandle MultiplayerComponent::GetEntityHandle() const diff --git a/Gems/Multiplayer/Code/Source/Components/MultiplayerComponentRegistry.cpp b/Gems/Multiplayer/Code/Source/Components/MultiplayerComponentRegistry.cpp index 648b28633e..7e7cbfc480 100644 --- a/Gems/Multiplayer/Code/Source/Components/MultiplayerComponentRegistry.cpp +++ b/Gems/Multiplayer/Code/Source/Components/MultiplayerComponentRegistry.cpp @@ -10,7 +10,7 @@ * */ -#include +#include namespace Multiplayer { @@ -21,6 +21,12 @@ namespace Multiplayer return netComponentId; } + AZStd::unique_ptr MultiplayerComponentRegistry::AllocateComponentInput(NetComponentId netComponentId) + { + const ComponentData& componentData = GetMultiplayerComponentData(netComponentId); + return AZStd::move(componentData.m_allocComponentInputFunction()); + } + const char* MultiplayerComponentRegistry::GetComponentGemName(NetComponentId netComponentId) const { const ComponentData& componentData = GetMultiplayerComponentData(netComponentId); diff --git a/Gems/Multiplayer/Code/Source/Components/MultiplayerController.cpp b/Gems/Multiplayer/Code/Source/Components/MultiplayerController.cpp index 9b8f41d5bc..b0bafccf79 100644 --- a/Gems/Multiplayer/Code/Source/Components/MultiplayerController.cpp +++ b/Gems/Multiplayer/Code/Source/Components/MultiplayerController.cpp @@ -10,9 +10,9 @@ * */ -#include -#include -#include +#include +#include +#include namespace Multiplayer { @@ -27,9 +27,14 @@ namespace Multiplayer return m_owner.GetNetEntityId(); } - NetEntityRole MultiplayerController::GetNetEntityRole() const + bool MultiplayerController::IsAuthority() const { - return GetNetBindComponent()->GetNetEntityRole(); + return GetNetBindComponent() ? GetNetBindComponent()->IsAuthority() : false; + } + + bool MultiplayerController::IsAutonomous() const + { + return GetNetBindComponent() ? GetNetBindComponent()->IsAutonomous() : false; } AZ::Entity* MultiplayerController::GetEntity() const diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index 6dc661415e..e48d0b0d09 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -10,13 +10,13 @@ * */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -110,6 +110,22 @@ namespace Multiplayer return (m_netEntityRole == NetEntityRole::Authority); } + bool NetBindComponent::IsAutonomous() const + { + return (m_netEntityRole == NetEntityRole::Autonomous) + || (m_netEntityRole == NetEntityRole::Authority) && m_allowAutonomy; + } + + bool NetBindComponent::IsServer() const + { + return (m_netEntityRole == NetEntityRole::Server); + } + + bool NetBindComponent::IsClient() const + { + return (m_netEntityRole == NetEntityRole::Client); + } + bool NetBindComponent::HasController() const { return (m_netEntityRole == NetEntityRole::Authority) @@ -136,14 +152,29 @@ namespace Multiplayer return m_netEntityHandle; } + void NetBindComponent::SetOwningConnectionId(AzNetworking::ConnectionId connectionId) + { + for (MultiplayerComponent* multiplayerComponent : m_multiplayerInputComponentVector) + { + multiplayerComponent->SetOwningConnectionId(connectionId); + } + } + + void NetBindComponent::SetAllowAutonomy(bool value) + { + // This flag allows a player host to autonomously control their player entity, even though the entity is in an authority role + m_allowAutonomy = value; + } + MultiplayerComponentInputVector NetBindComponent::AllocateComponentInputs() { MultiplayerComponentInputVector componentInputs; const size_t multiplayerComponentSize = m_multiplayerInputComponentVector.size(); for (size_t i = 0; i < multiplayerComponentSize; ++i) { - // TODO: ComponentInput factory, needs multiplayer component architecture and autogen - AZStd::unique_ptr componentInput = nullptr; // ComponentInputFactory(multiplayerComponent->GetComponentId()); + const NetComponentId netComponentId = m_multiplayerInputComponentVector[i]->GetNetComponentId(); + AZStd::unique_ptr componentInput = AZStd::move(GetMultiplayerComponentRegistry()->AllocateComponentInput(netComponentId)); + if (componentInput != nullptr) { componentInputs.emplace_back(AZStd::move(componentInput)); diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp index 607e2813ec..0cc4cb131e 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp @@ -10,7 +10,7 @@ * */ -#include +#include #include #include #include @@ -96,7 +96,7 @@ namespace Multiplayer void NetworkTransformComponentController::OnTransformChangedEvent(const AZ::Transform& worldTm) { - if (GetNetEntityRole() == NetEntityRole::Authority) + if (IsAuthority()) { SetRotation(worldTm.GetRotation()); SetTranslation(worldTm.GetTranslation()); diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h index 449ffafe45..2e7be47842 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h index 6274a6ba31..faa11bc225 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp index 1ae4bffd07..4ae7c3fdfe 100644 --- a/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Debug/MultiplayerDebugSystemComponent.cpp @@ -138,7 +138,7 @@ namespace Multiplayer void DrawComponentDetails(const MultiplayerStats& stats, NetComponentId netComponentId) { - IMultiplayer* multiplayer = AZ::Interface::Get(); + MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry(); { const MultiplayerStats::Metric metric = stats.CalculateComponentPropertyUpdateSentMetrics(netComponentId); float callsPerSecond = 0.0f; @@ -150,7 +150,7 @@ namespace Multiplayer for (AZStd::size_t index = 0; index < componentStats.m_propertyUpdatesSent.size(); ++index) { const PropertyIndex propertyIndex = aznumeric_cast(index); - const char* propertyName = multiplayer->GetComponentPropertyName(netComponentId, propertyIndex); + const char* propertyName = componentRegistry->GetComponentPropertyName(netComponentId, propertyIndex); const MultiplayerStats::Metric& subMetric = componentStats.m_propertyUpdatesSent[index]; callsPerSecond = 0.0f; bytesPerSecond = 0.0f; @@ -172,7 +172,7 @@ namespace Multiplayer for (AZStd::size_t index = 0; index < componentStats.m_propertyUpdatesRecv.size(); ++index) { const PropertyIndex propertyIndex = aznumeric_cast(index); - const char* propertyName = multiplayer->GetComponentPropertyName(netComponentId, propertyIndex); + const char* propertyName = componentRegistry->GetComponentPropertyName(netComponentId, propertyIndex); const MultiplayerStats::Metric& subMetric = componentStats.m_propertyUpdatesRecv[index]; callsPerSecond = 0.0f; bytesPerSecond = 0.0f; @@ -194,7 +194,7 @@ namespace Multiplayer for (AZStd::size_t index = 0; index < componentStats.m_rpcsSent.size(); ++index) { const RpcIndex rpcIndex = aznumeric_cast(index); - const char* rpcName = multiplayer->GetComponentRpcName(netComponentId, rpcIndex); + const char* rpcName = componentRegistry->GetComponentRpcName(netComponentId, rpcIndex); const MultiplayerStats::Metric& subMetric = componentStats.m_rpcsSent[index]; callsPerSecond = 0.0f; bytesPerSecond = 0.0f; @@ -216,7 +216,7 @@ namespace Multiplayer for (AZStd::size_t index = 0; index < componentStats.m_rpcsRecv.size(); ++index) { const RpcIndex rpcIndex = aznumeric_cast(index); - const char* rpcName = multiplayer->GetComponentRpcName(netComponentId, rpcIndex); + const char* rpcName = componentRegistry->GetComponentRpcName(netComponentId, rpcIndex); const MultiplayerStats::Metric& subMetric = componentStats.m_rpcsRecv[index]; callsPerSecond = 0.0f; bytesPerSecond = 0.0f; @@ -238,6 +238,7 @@ namespace Multiplayer if (ImGui::Begin("Multiplayer Stats", &m_displayMultiplayerStats, ImGuiWindowFlags_None)) { IMultiplayer* multiplayer = AZ::Interface::Get(); + MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry(); const Multiplayer::MultiplayerStats& stats = multiplayer->GetStats(); ImGui::Text("Multiplayer operating in %s mode", GetEnumString(multiplayer->GetAgentType())); ImGui::Text("Total networked entities: %llu", aznumeric_cast(stats.m_entityCount)); @@ -267,8 +268,8 @@ namespace Multiplayer { const NetComponentId netComponentId = aznumeric_cast(index); using StringLabel = AZStd::fixed_string<128>; - const StringLabel gemName = multiplayer->GetComponentGemName(netComponentId); - const StringLabel componentName = multiplayer->GetComponentName(netComponentId); + const StringLabel gemName = componentRegistry->GetComponentGemName(netComponentId); + const StringLabel componentName = componentRegistry->GetComponentName(netComponentId); const StringLabel label = gemName + "::" + componentName; if (DrawComponentRow(label.c_str(), stats, netComponentId)) { diff --git a/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h b/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h index 3bf6eb554f..d8d264dc34 100644 --- a/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h +++ b/Gems/Multiplayer/Code/Source/EntityDomains/FullOwnershipEntityDomain.h @@ -12,7 +12,7 @@ #pragma once -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/MultiplayerGem.cpp b/Gems/Multiplayer/Code/Source/MultiplayerGem.cpp index aef3e546ad..14bb71bcd5 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerGem.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerGem.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.cpp b/Gems/Multiplayer/Code/Source/MultiplayerStats.cpp similarity index 100% rename from Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerStats.cpp rename to Gems/Multiplayer/Code/Source/MultiplayerStats.cpp diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 80a09d7d48..8eb5bf7b0c 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -80,6 +80,31 @@ namespace Multiplayer { serializeContext->Class() ->Version(1); + + serializeContext->Class() + ->Version(1); + serializeContext->Class() + ->Version(1); + serializeContext->Class() + ->Version(1); + serializeContext->Class() + ->Version(1); + serializeContext->Class() + ->Version(1); + serializeContext->Class() + ->Version(1); + serializeContext->Class() + ->Version(1); + } + else if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class(); + behaviorContext->Class(); + behaviorContext->Class(); + behaviorContext->Class(); + behaviorContext->Class(); + behaviorContext->Class(); + behaviorContext->Class(); } MultiplayerComponent::Reflect(context); @@ -448,6 +473,7 @@ namespace Multiplayer if (entityList.size() > 0) { controlledEntity = entityList[0]; + controlledEntity.GetNetBindComponent()->SetOwningConnectionId(connection->GetConnectionId()); } if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so @@ -576,26 +602,6 @@ namespace Multiplayer return &m_networkEntityManager; } - const char* MultiplayerSystemComponent::GetComponentGemName(NetComponentId netComponentId) const - { - return GetMultiplayerComponentRegistry()->GetComponentGemName(netComponentId); - } - - const char* MultiplayerSystemComponent::GetComponentName(NetComponentId netComponentId) const - { - return GetMultiplayerComponentRegistry()->GetComponentName(netComponentId); - } - - const char* MultiplayerSystemComponent::GetComponentPropertyName(NetComponentId netComponentId, PropertyIndex propertyIndex) const - { - return GetMultiplayerComponentRegistry()->GetComponentPropertyName(netComponentId, propertyIndex); - } - - const char* MultiplayerSystemComponent::GetComponentRpcName(NetComponentId netComponentId, RpcIndex rpcIndex) const - { - return GetMultiplayerComponentRegistry()->GetComponentRpcName(netComponentId, rpcIndex); - } - void MultiplayerSystemComponent::DumpStats([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { const MultiplayerStats& stats = GetStats(); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index ba59a82eae..6bedd0599b 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -94,10 +94,6 @@ namespace Multiplayer AZ::TimeMs GetCurrentHostTimeMs() const override; INetworkTime* GetNetworkTime() override; INetworkEntityManager* GetNetworkEntityManager() override; - const char* GetComponentGemName(NetComponentId netComponentId) const override; - const char* GetComponentName(NetComponentId netComponentId) const override; - const char* GetComponentPropertyName(NetComponentId netComponentId, PropertyIndex propertyIndex) const override; - const char* GetComponentRpcName(NetComponentId netComponentId, RpcIndex rpcIndex) const override; //! @} //! Console commands. diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp index 286090ca74..e47d142be8 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp @@ -15,13 +15,13 @@ #include #include #include -#include -#include -#include -#include #include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -828,12 +828,11 @@ namespace Multiplayer { if (entityReplicator == nullptr) { - IMultiplayer* multiplayer = GetMultiplayer(); AZLOG_INFO ( "EntityReplicationManager: Dropping remote RPC message for component %s of rpc index %s, entityId %u has already been deleted", - multiplayer->GetComponentName(message.GetComponentId()), - multiplayer->GetComponentRpcName(message.GetComponentId(), message.GetRpcIndex()), + GetMultiplayerComponentRegistry()->GetComponentName(message.GetComponentId()), + GetMultiplayerComponentRegistry()->GetComponentRpcName(message.GetComponentId(), message.GetRpcIndex()), message.GetEntityId() ); return false; diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h index 50a4ad43d4..083413e19e 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h @@ -13,11 +13,11 @@ #pragma once #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp index 15293d518d..f84487080b 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp @@ -16,11 +16,11 @@ #include #include #include -#include #include #include -#include -#include +#include +#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h index 3587c28975..ced665abf3 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.h @@ -18,8 +18,8 @@ #include #include #include -#include -#include +#include +#include namespace AzNetworking { diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.h b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.h index be8ac1b65b..fb23adfbd5 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include namespace AzNetworking diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertySubscriber.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertySubscriber.cpp index 4994884364..b74c8af081 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertySubscriber.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertySubscriber.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/ReplicationRecord.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/ReplicationRecord.cpp index 6aa6c10b11..41cc86aaee 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/ReplicationRecord.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/ReplicationRecord.cpp @@ -10,7 +10,7 @@ * */ -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp index ecfd416380..f30b7ee9e0 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityAuthorityTracker.cpp @@ -11,8 +11,8 @@ */ #include -#include -#include +#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp index 0dd7292d25..3ca56f01b3 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityHandle.cpp @@ -10,10 +10,10 @@ * */ -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index 28b72abf25..6f3fdf2b23 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h index e763e7ebca..3291f2c38d 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h @@ -18,10 +18,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityRpcMessage.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityRpcMessage.cpp index d58c192162..f636fb6447 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityRpcMessage.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityRpcMessage.cpp @@ -10,7 +10,7 @@ * */ -#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp index 42104e79fd..2dac90deee 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h index 34f5d03f2f..1b4b7f15f1 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityUpdateMessage.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityUpdateMessage.cpp index 5ece0c7157..3fe5a497cb 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityUpdateMessage.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityUpdateMessage.cpp @@ -10,7 +10,7 @@ * */ -#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp index eafd4375e7..2589f52d87 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp @@ -10,8 +10,10 @@ * */ -#include -#include +#include +#include +#include +#include #include #include @@ -111,13 +113,12 @@ namespace Multiplayer // This happens when deserializing a non-delta'd input command // However in the delta serializer case, we use the previous input as our initial value // which will have the NetworkInputs setup and therefore won't write out the componentId - NetComponentId componentId = m_componentInputs[i] ? m_componentInputs[i]->GetComponentId() : InvalidNetComponentId; + NetComponentId componentId = m_componentInputs[i] ? m_componentInputs[i]->GetNetComponentId() : InvalidNetComponentId; serializer.Serialize(componentId, "ComponentType"); // Create a new input if we don't have one or the types do not match - if ((m_componentInputs[i] == nullptr) || (componentId != m_componentInputs[i]->GetComponentId())) + if ((m_componentInputs[i] == nullptr) || (componentId != m_componentInputs[i]->GetNetComponentId())) { - // TODO: ComponentInput factory, needs multiplayer component architecture and autogen - m_componentInputs[i] = nullptr; // ComponentInputFactory(componentId); + m_componentInputs[i] = AZStd::move(GetMultiplayerComponentRegistry()->AllocateComponentInput(componentId)); } if (!m_componentInputs[i]) { @@ -135,7 +136,7 @@ namespace Multiplayer // We assume that the order of the network inputs is fixed between the server and client for (auto& componentInput : m_componentInputs) { - NetComponentId componentId = componentInput->GetComponentId(); + NetComponentId componentId = componentInput->GetNetComponentId(); serializer.Serialize(componentId, "ComponentId"); serializer.Serialize(*componentInput, "ComponentInput"); } @@ -148,7 +149,7 @@ namespace Multiplayer // linear search since we expect to have very few components for (auto& componentInput : m_componentInputs) { - if (componentInput->GetComponentId() == componentId) + if (componentInput->GetNetComponentId() == componentId) { return componentInput.get(); } @@ -165,16 +166,17 @@ namespace Multiplayer void NetworkInput::CopyInternal(const NetworkInput& rhs) { m_inputId = rhs.m_inputId; + m_hostFrameId = rhs.m_hostFrameId; m_hostTimeMs = rhs.m_hostTimeMs; m_componentInputs.resize(rhs.m_componentInputs.size()); for (int32_t i = 0; i < rhs.m_componentInputs.size(); ++i) { - if (m_componentInputs[i] == nullptr || m_componentInputs[i]->GetComponentId() != rhs.m_componentInputs[i]->GetComponentId()) + const NetComponentId rhsComponentId = rhs.m_componentInputs[i]->GetNetComponentId(); + if (m_componentInputs[i] == nullptr || m_componentInputs[i]->GetNetComponentId() != rhsComponentId) { - // TODO: ComponentInput factory, needs multiplayer component architecture and autogen - m_componentInputs[i] = nullptr; // ComponentInputFactory(rhs.m_componentInputs[i]->GetComponentId()); + m_componentInputs[i] = AZStd::move(GetMultiplayerComponentRegistry()->AllocateComponentInput(rhsComponentId)); } - *m_componentInputs[i] = *rhs.m_componentInputs[i]; + *(m_componentInputs[i]) = *(rhs.m_componentInputs[i]); } m_wasAttached = rhs.m_wasAttached; } diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.cpp index 82e5cea0c4..e736cd4da2 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.cpp @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include @@ -48,16 +48,6 @@ namespace Multiplayer return m_inputs[index].m_networkInput; } - void NetworkInputArray::SetPreviousInputId(ClientInputId previousInputId) - { - m_previousInputId = previousInputId; - } - - ClientInputId NetworkInputArray::GetPreviousInputId() const - { - return m_previousInputId; - } - bool NetworkInputArray::Serialize(AzNetworking::ISerializer& serializer) { // Always serialize the full first element @@ -102,7 +92,6 @@ namespace Multiplayer } } } - serializer.Serialize(m_previousInputId, "PreviousInputId"); return true; } } diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h index d5cbcbbed3..293fb18928 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputArray.h @@ -12,8 +12,8 @@ #pragma once -#include -#include +#include +#include #include #include @@ -33,9 +33,6 @@ namespace Multiplayer NetworkInput& operator[](uint32_t index); const NetworkInput& operator[](uint32_t index) const; - void SetPreviousInputId(ClientInputId previousInputId); - ClientInputId GetPreviousInputId() const; - bool Serialize(AzNetworking::ISerializer& serializer); private: @@ -49,6 +46,5 @@ namespace Multiplayer ConstNetworkEntityHandle m_owner; AZStd::array m_inputs; - ClientInputId m_previousInputId; }; } diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.h index fa4ab1e4e9..e81bce0210 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.h @@ -12,7 +12,7 @@ #pragma once -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputHistory.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputHistory.h index c5f0a70fd3..76eeebf73a 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputHistory.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputHistory.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.h index 454cef4e0a..e5f8fdf648 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputMigrationVector.h @@ -12,8 +12,8 @@ #pragma once -#include -#include +#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp index d991e59d05..98ece0a8cc 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp @@ -11,8 +11,8 @@ */ #include -#include #include +#include #include namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h index ff2da0f759..f714e046b3 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h +++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp index 805a982506..4661df7564 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h index 5cb9c0de70..f633a35a14 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h @@ -12,7 +12,7 @@ #pragma once -#include +#include namespace Multiplayer { diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp index bf370c1952..d048476cc0 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h index 25fbfd481d..fc143a7cc4 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h @@ -13,8 +13,8 @@ #pragma once #include -#include -#include +#include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp b/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp index f614dc2690..4596e3b35c 100644 --- a/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp +++ b/Gems/Multiplayer/Code/Tests/RewindableObjectTests.cpp @@ -10,8 +10,8 @@ * */ -#include #include +#include #include #include #include diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index 26909cbfd3..8dd7c07689 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -10,33 +10,34 @@ # set(FILES - Include/Multiplayer/IConnectionData.h - Include/Multiplayer/IEntityDomain.h Include/Multiplayer/IMultiplayer.h - Include/Multiplayer/IMultiplayerComponentInput.h - Include/Multiplayer/INetworkEntityManager.h - Include/Multiplayer/INetworkPlayerSpawner.h - Include/Multiplayer/INetworkTime.h - Include/Multiplayer/IReplicationWindow.h - Include/Multiplayer/MultiplayerComponent.h - Include/Multiplayer/MultiplayerController.h - Include/Multiplayer/MultiplayerComponentRegistry.h - Include/Multiplayer/MultiplayerStats.cpp Include/Multiplayer/MultiplayerStats.h Include/Multiplayer/MultiplayerTypes.h - Include/Multiplayer/NetBindComponent.h - Include/Multiplayer/NetworkEntityRpcMessage.h - Include/Multiplayer/NetworkEntityUpdateMessage.h - Include/Multiplayer/NetworkEntityHandle.h - Include/Multiplayer/NetworkEntityHandle.inl - Include/Multiplayer/NetworkInput.h - Include/Multiplayer/ReplicationRecord.h - Include/Multiplayer/RewindableObject.h - Include/Multiplayer/RewindableObject.inl + Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h + Include/Multiplayer/Components/MultiplayerComponent.h + Include/Multiplayer/Components/MultiplayerController.h + Include/Multiplayer/Components/MultiplayerComponentRegistry.h + Include/Multiplayer/Components/NetBindComponent.h + Include/Multiplayer/Components/NetworkTransformComponent.h + Include/Multiplayer/ConnectionData/IConnectionData.h + Include/Multiplayer/EntityDomains/IEntityDomain.h + Include/Multiplayer/NetworkEntity/INetworkEntityManager.h + Include/Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h + Include/Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h + Include/Multiplayer/NetworkEntity/NetworkEntityHandle.h + Include/Multiplayer/NetworkEntity/NetworkEntityHandle.inl + Include/Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h + Include/Multiplayer/NetworkInput/IMultiplayerComponentInput.h + Include/Multiplayer/NetworkInput/NetworkInput.h + Include/Multiplayer/NetworkTime/INetworkTime.h + Include/Multiplayer/NetworkTime/RewindableObject.h + Include/Multiplayer/NetworkTime/RewindableObject.inl + Include/Multiplayer/ReplicationWindows/IReplicationWindow.h Source/Multiplayer_precompiled.cpp Source/Multiplayer_precompiled.h Source/MultiplayerSystemComponent.cpp Source/MultiplayerSystemComponent.h + Source/MultiplayerStats.cpp Source/AutoGen/AutoComponent_Header.jinja Source/AutoGen/AutoComponent_Source.jinja Source/AutoGen/AutoComponent_Common.jinja @@ -46,13 +47,11 @@ set(FILES Source/AutoGen/Multiplayer.AutoPackets.xml Source/AutoGen/NetworkTransformComponent.AutoComponent.xml Source/Components/LocalPredictionPlayerInputComponent.cpp - Source/Components/LocalPredictionPlayerInputComponent.h Source/Components/MultiplayerComponent.cpp Source/Components/MultiplayerController.cpp Source/Components/MultiplayerComponentRegistry.cpp Source/Components/NetBindComponent.cpp Source/Components/NetworkTransformComponent.cpp - Source/Components/NetworkTransformComponent.h Source/ConnectionData/ClientToServerConnectionData.cpp Source/ConnectionData/ClientToServerConnectionData.h Source/ConnectionData/ClientToServerConnectionData.inl diff --git a/Gems/NvCloth/Assets/slices/Cloth/cloth_blinds.slice b/Gems/NvCloth/Assets/slices/Cloth/cloth_blinds.slice index c8709b3a6a..8d7605318e 100644 --- a/Gems/NvCloth/Assets/slices/Cloth/cloth_blinds.slice +++ b/Gems/NvCloth/Assets/slices/Cloth/cloth_blinds.slice @@ -39,13 +39,13 @@ + - @@ -188,6 +188,7 @@ + diff --git a/Gems/NvCloth/Assets/slices/Cloth/cloth_blinds_broken.slice b/Gems/NvCloth/Assets/slices/Cloth/cloth_blinds_broken.slice index e3ef330b3e..ff955f260e 100644 --- a/Gems/NvCloth/Assets/slices/Cloth/cloth_blinds_broken.slice +++ b/Gems/NvCloth/Assets/slices/Cloth/cloth_blinds_broken.slice @@ -39,13 +39,13 @@ + - @@ -188,6 +188,7 @@ + diff --git a/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_corners_four.slice b/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_corners_four.slice index 0a32a4191a..d0bcd1296a 100644 --- a/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_corners_four.slice +++ b/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_corners_four.slice @@ -39,13 +39,13 @@ + - @@ -188,6 +188,7 @@ + diff --git a/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_corners_two.slice b/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_corners_two.slice index 369cb76841..8e07a65147 100644 --- a/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_corners_two.slice +++ b/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_corners_two.slice @@ -39,13 +39,13 @@ + - @@ -188,6 +188,7 @@ + diff --git a/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_edge.slice b/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_edge.slice index b44a440d4d..a80058d820 100644 --- a/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_edge.slice +++ b/Gems/NvCloth/Assets/slices/Cloth/cloth_locked_edge.slice @@ -39,13 +39,13 @@ + - @@ -188,6 +188,7 @@ + diff --git a/Gems/NvCloth/Code/CMakeLists.txt b/Gems/NvCloth/Code/CMakeLists.txt index d83190a05c..0f019a985f 100644 --- a/Gems/NvCloth/Code/CMakeLists.txt +++ b/Gems/NvCloth/Code/CMakeLists.txt @@ -30,11 +30,7 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC 3rdParty::NvCloth - # CryCommon required for 'gEnv->IsDedicated()'. - # Because of this the module will need CrySystemEventBus to initialize gEnv - # and tests targets will need to fake gEnv. To be removed when there is - # an AZ replacement for asking if the game is running on a server or not. - Legacy::CryCommon + AZ::AzFramework Gem::AtomLyIntegration_CommonFeatures.Public PRIVATE Gem::EMotionFXStaticLib diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponent.cpp b/Gems/NvCloth/Code/Source/Components/ClothComponent.cpp index 912255c798..0170fd65bd 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponent.cpp +++ b/Gems/NvCloth/Code/Source/Components/ClothComponent.cpp @@ -10,9 +10,8 @@ * */ -#include - #include +#include #include @@ -55,10 +54,14 @@ namespace NvCloth void ClothComponent::Activate() { // Cloth components do not run on dedicated servers. - AZ_Assert(gEnv, "Environment not ready"); - if (gEnv->IsDedicated()) + if (auto* console = AZ::Interface::Get()) { - return; + bool isDedicated = false; + if (const auto result = console->GetCvarValue("sv_isDedicated", isDedicated); + result == AZ::GetValueResult::Success && isDedicated) + { + return; + } } AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId()); diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothSkinning.cpp b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothSkinning.cpp index 411c727d33..88aae06bf2 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothSkinning.cpp +++ b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothSkinning.cpp @@ -430,10 +430,12 @@ namespace NvCloth AZStd::unique_ptr ActorClothSkinning::Create( AZ::EntityId entityId, const MeshNodeInfo& meshNodeInfo, - const size_t numVertices, + const AZStd::vector& originalMeshParticles, const size_t numSimulatedVertices, const AZStd::vector& meshRemappedVertices) { + const size_t numVertices = originalMeshParticles.size(); + AZStd::vector skinningInfluences; if (!Internal::ObtainSkinningInfluences(entityId, meshNodeInfo, numVertices, skinningInfluences)) { @@ -480,11 +482,14 @@ namespace NvCloth for (size_t vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex) { const int remappedIndex = meshRemappedVertices[vertexIndex]; + if (remappedIndex >= 0) { actorClothSkinning->m_simulatedVertices[remappedIndex] = vertexIndex; } - else + + if (remappedIndex < 0 || + originalMeshParticles[vertexIndex].GetW() == 0.0f) { actorClothSkinning->m_nonSimulatedVertices.emplace_back(vertexIndex); } diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothSkinning.h b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothSkinning.h index 01df1f87ef..1fd667b9c0 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothSkinning.h +++ b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothSkinning.h @@ -21,8 +21,6 @@ namespace NvCloth { - struct MeshNodeInfo; - //! One skinning influence of a vertex. struct SkinningInfluence { @@ -45,7 +43,7 @@ namespace NvCloth static AZStd::unique_ptr Create( AZ::EntityId entityId, const MeshNodeInfo& meshNodeInfo, - const size_t numVertices, + const AZStd::vector& originalMeshParticles, const size_t numSimulatedVertices, const AZStd::vector& meshRemappedVertices); diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp index 52c93ea672..0914e26cb7 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp +++ b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.cpp @@ -36,6 +36,9 @@ namespace NvCloth AZ_CVAR(float, cloth_DistanceToTeleport, 0.5f, nullptr, AZ::ConsoleFunctorFlags::Null, "The amount of meters the entity has to move in a frame to consider it a teleport for cloth."); + AZ_CVAR(float, cloth_SecondsToDelaySimulationOnActorSpawned, 0.25f, nullptr, AZ::ConsoleFunctorFlags::Null, + "The amount of time in seconds the cloth simulation will be delayed to avoid sudden impulses when actors are spawned."); + // Helper class to map an RPI buffer from a buffer asset view. template class MappedBuffer @@ -187,10 +190,10 @@ namespace NvCloth m_actorClothSkinning = ActorClothSkinning::Create( m_entityId, m_meshNodeInfo, - m_meshClothInfo.m_particles.size(), + m_meshClothInfo.m_particles, m_cloth->GetParticles().size(), m_meshRemappedVertices); - m_numberOfClothSkinningUpdates = 0; + m_timeClothSkinningUpdates = 0.0f; m_clothConstraints = ClothConstraints::Create( m_meshClothInfo.m_motionConstraints, @@ -248,7 +251,7 @@ namespace NvCloth void ClothComponentMesh::OnPreSimulation( [[maybe_unused]] ClothId clothId, - [[maybe_unused]] float deltaTime) + float deltaTime) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Cloth); @@ -256,7 +259,7 @@ namespace NvCloth if (m_actorClothSkinning) { - UpdateSimulationSkinning(); + UpdateSimulationSkinning(deltaTime); UpdateSimulationConstraints(); } @@ -338,7 +341,7 @@ namespace NvCloth } } - void ClothComponentMesh::UpdateSimulationSkinning() + void ClothComponentMesh::UpdateSimulationSkinning(float deltaTime) { if (m_actorClothSkinning) { @@ -349,22 +352,21 @@ namespace NvCloth // Since component activation order is not trivial, the actor's pose might not be updated // immediately. Because of this cloth will receive a sudden impulse when changing from // T pose to animated pose. To avoid this undesired effect we will override cloth simulation during - // a short amount of frames. - const AZ::u32 numberOfTicksToDoFullSkinning = 10; - m_numberOfClothSkinningUpdates++; + // a short amount of time. + m_timeClothSkinningUpdates += deltaTime; // While the actor is not visible the skinned joints are not updated. Then when // it becomes visible the jump to the new skinned positions causes a sudden // impulse to cloth simulation. To avoid this undesired effect we will override cloth simulation during - // a short amount of frames. + // a short amount of time. m_actorClothSkinning->UpdateActorVisibility(); if (!m_actorClothSkinning->WasActorVisible() && m_actorClothSkinning->IsActorVisible()) { - m_numberOfClothSkinningUpdates = 0; + m_timeClothSkinningUpdates = 0.0f; } - if (m_numberOfClothSkinningUpdates <= numberOfTicksToDoFullSkinning) + if (m_timeClothSkinningUpdates <= cloth_SecondsToDelaySimulationOnActorSpawned) { // Update skinning for all particles and apply it to cloth AZStd::vector particles = m_cloth->GetParticles(); @@ -406,7 +408,7 @@ namespace NvCloth auto& renderData = GetRenderData(); - if (m_config.m_removeStaticTriangles && m_actorClothSkinning) + if (m_actorClothSkinning) { // Apply skinning to the non-simulated part of the mesh. m_actorClothSkinning->ApplySkinningOnNonSimulatedVertices(m_meshClothInfo, renderData); @@ -427,7 +429,15 @@ namespace NvCloth if (remappedIndex >= 0) { renderData.m_particles[index] = particles[remappedIndex]; - renderData.m_normals[index] = normals[remappedIndex]; + + // For static particles only use the updated normal when indicated in the configuration. + const bool useSimulatedClothParticleNormal = + m_meshClothInfo.m_particles[index].GetW() != 0.0f || + m_config.m_updateNormalsOfStaticParticles; + if (useSimulatedClothParticleNormal) + { + renderData.m_normals[index] = normals[remappedIndex]; + } } } diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.h b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.h index a1fb6d5572..f8772d2e93 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.h +++ b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ClothComponentMesh.h @@ -85,7 +85,7 @@ namespace NvCloth private: void UpdateSimulationCollisions(); - void UpdateSimulationSkinning(); + void UpdateSimulationSkinning(float deltaTime); void UpdateSimulationConstraints(); void UpdateRenderData(const AZStd::vector& particles); @@ -133,7 +133,7 @@ namespace NvCloth // Cloth Skinning from the character AZStd::unique_ptr m_actorClothSkinning; - AZ::u32 m_numberOfClothSkinningUpdates = 0; + float m_timeClothSkinningUpdates = 0.0f; // Cloth Constraints AZStd::unique_ptr m_clothConstraints; diff --git a/Gems/NvCloth/Code/Source/Components/ClothConfiguration.cpp b/Gems/NvCloth/Code/Source/Components/ClothConfiguration.cpp index 7173f78e92..164e0c62d8 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothConfiguration.cpp +++ b/Gems/NvCloth/Code/Source/Components/ClothConfiguration.cpp @@ -74,6 +74,7 @@ namespace NvCloth ->Field("Solver Frequency", &ClothConfiguration::m_solverFrequency) ->Field("Acceleration Filter Iterations", &ClothConfiguration::m_accelerationFilterIterations) ->Field("Remove Static Triangles", &ClothConfiguration::m_removeStaticTriangles) + ->Field("Update Normals of Static Particles", &ClothConfiguration::m_updateNormalsOfStaticParticles) ; } } diff --git a/Gems/NvCloth/Code/Source/Components/ClothConfiguration.h b/Gems/NvCloth/Code/Source/Components/ClothConfiguration.h index e5a5bdb8e8..7c08b2bfb0 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothConfiguration.h +++ b/Gems/NvCloth/Code/Source/Components/ClothConfiguration.h @@ -96,6 +96,7 @@ namespace NvCloth float m_solverFrequency = 300.0f; uint32_t m_accelerationFilterIterations = 30; bool m_removeStaticTriangles = true; + bool m_updateNormalsOfStaticParticles = false; // Fabric phases parameters float m_horizontalStiffness = 1.0f; diff --git a/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp b/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp index 1254a13cb2..7da677a7eb 100644 --- a/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp +++ b/Gems/NvCloth/Code/Source/Components/EditorClothComponent.cpp @@ -374,12 +374,15 @@ namespace NvCloth ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_solverFrequency, "Solver frequency", "Target solver iterations per second. At least 1 iteration per frame will be solved regardless of the value set.") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) - ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_accelerationFilterIterations, "Acceleration filter Iterations", + ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_accelerationFilterIterations, "Acceleration filter iterations", "Number of iterations to average delta time factor used for gravity and external acceleration.") ->Attribute(AZ::Edit::Attributes::Min, 1) ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_removeStaticTriangles, "Remove static triangles", "Removing static triangles improves performance by not taking into account triangles whose particles are all static.\n" "The removed static particles will not be present for collision or self collision during simulation.") + ->DataElement(AZ::Edit::UIHandlers::Default, &ClothConfiguration::m_updateNormalsOfStaticParticles, "Update normals of static particles", + "When enabled the normals of static particles will be updated according with the movement of the simulated mesh.\n" + "When disabled the static particles will keep the same normals as the original mesh.") ; } } diff --git a/Gems/NvCloth/Code/Source/Module.cpp b/Gems/NvCloth/Code/Source/Module.cpp index 08d673fd07..66390dda86 100644 --- a/Gems/NvCloth/Code/Source/Module.cpp +++ b/Gems/NvCloth/Code/Source/Module.cpp @@ -10,9 +10,6 @@ * */ -#include -#include - #include #include @@ -31,7 +28,6 @@ namespace NvCloth { class Module : public AZ::Module - , protected CrySystemEventBus::Handler { public: AZ_RTTI(Module, "{34C529D4-688F-4B51-BF60-75425754A7E6}", AZ::Module); @@ -47,8 +43,6 @@ namespace NvCloth m_fabricCooker = AZStd::make_unique(); m_tangentSpaceHelper = AZStd::make_unique(); - CrySystemEventBus::Handler::BusConnect(); - // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. m_descriptors.insert(m_descriptors.end(), { SystemComponent::CreateDescriptor(), @@ -64,8 +58,6 @@ namespace NvCloth ~Module() { - CrySystemEventBus::Handler::BusDisconnect(); - m_tangentSpaceHelper.reset(); m_fabricCooker.reset(); @@ -85,33 +77,10 @@ namespace NvCloth }; } - protected: - // CrySystemEventBus ... - void OnCrySystemPreInitialize(ISystem& system, const SSystemInitParams& systemInitParams) override; - void OnCrySystemPostShutdown() override; - private: AZStd::unique_ptr m_fabricCooker; AZStd::unique_ptr m_tangentSpaceHelper; }; - - void Module::OnCrySystemPreInitialize( - [[maybe_unused]] ISystem& system, - [[maybe_unused]] const SSystemInitParams& systemInitParams) - { -#if !defined(AZ_MONOLITHIC_BUILD) - // When module is linked dynamically, we must set our gEnv pointer. - // When module is linked statically, we'll share the application's gEnv pointer. - gEnv = system.GetGlobalEnvironment(); -#endif - } - - void Module::OnCrySystemPostShutdown() - { -#if !defined(AZ_MONOLITHIC_BUILD) - gEnv = nullptr; -#endif - } } // namespace NvCloth // DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM diff --git a/Gems/NvCloth/Code/Source/Utils/MeshAssetHelper.cpp b/Gems/NvCloth/Code/Source/Utils/MeshAssetHelper.cpp index 00ce77c176..32e745f9cb 100644 --- a/Gems/NvCloth/Code/Source/Utils/MeshAssetHelper.cpp +++ b/Gems/NvCloth/Code/Source/Utils/MeshAssetHelper.cpp @@ -172,6 +172,7 @@ namespace NvCloth meshClothInfo.m_uvs.reserve(numTotalVertices); meshClothInfo.m_motionConstraints.reserve(numTotalVertices); meshClothInfo.m_backstopData.reserve(numTotalVertices); + meshClothInfo.m_normals.reserve(numTotalVertices); meshClothInfo.m_indices.reserve(numTotalIndices); struct Vec2 @@ -192,10 +193,15 @@ namespace NvCloth { const auto sourceIndices = mesh->GetIndexBufferTyped(); const auto sourcePositions = mesh->GetSemanticBufferTyped(AZ::Name("POSITION")); + const auto sourceNormals = mesh->GetSemanticBufferTyped(AZ::Name("NORMAL")); const auto sourceClothData = mesh->GetSemanticBufferTyped(AZ::Name("CLOTH_DATA")); const auto sourceUVs = mesh->GetSemanticBufferTyped(AZ::Name("UV")); - if (sourceIndices.empty() || sourcePositions.empty() || sourceClothData.empty()) + if (sourceIndices.empty() || + sourcePositions.empty() || + sourceNormals.empty() || + sourceClothData.empty() || + sourceUVs.empty()) { return false; } @@ -214,6 +220,11 @@ namespace NvCloth sourcePositions[index].z, inverseMass); + meshClothInfo.m_normals.emplace_back( + sourceNormals[index].x, + sourceNormals[index].y, + sourceNormals[index].z); + meshClothInfo.m_motionConstraints.emplace_back(motionConstraint); meshClothInfo.m_backstopData.emplace_back(backstopOffset, backstopRadius); @@ -226,12 +237,12 @@ namespace NvCloth meshClothInfo.m_indices.insert(meshClothInfo.m_indices.end(), sourceIndices.begin(), sourceIndices.end()); } - // Calculate tangent space for the mesh. - [[maybe_unused]] bool tangentSpaceCalculated = - AZ::Interface::Get()->CalculateTangentSpace( - meshClothInfo.m_particles, meshClothInfo.m_indices, meshClothInfo.m_uvs, - meshClothInfo.m_tangents, meshClothInfo.m_bitangents, meshClothInfo.m_normals); - AZ_Assert(tangentSpaceCalculated, "Failed to calculate tangent space."); + // Calculate tangents and bitangents for the whole mesh + [[maybe_unused]] bool tangentsAndBitangentsCalculated = + AZ::Interface::Get()->CalculateTangentsAndBitagents( + meshClothInfo.m_particles, meshClothInfo.m_indices, meshClothInfo.m_uvs, meshClothInfo.m_normals, + meshClothInfo.m_tangents, meshClothInfo.m_bitangents); + AZ_Assert(tangentsAndBitangentsCalculated, "Failed to calculate tangents and bitangents."); return true; } diff --git a/Gems/NvCloth/Code/Tests/Components/ClothComponentMesh/ActorClothSkinningTest.cpp b/Gems/NvCloth/Code/Tests/Components/ClothComponentMesh/ActorClothSkinningTest.cpp index 3fba04f695..818c36e7d2 100644 --- a/Gems/NvCloth/Code/Tests/Components/ClothComponentMesh/ActorClothSkinningTest.cpp +++ b/Gems/NvCloth/Code/Tests/Components/ClothComponentMesh/ActorClothSkinningTest.cpp @@ -36,6 +36,12 @@ namespace UnitTest AZ::Vector3(1.0f, 0.0f, 0.0f), AZ::Vector3(0.0f, 1.0f, 0.0f) }}; + + const AZStd::vector MeshParticles = {{ + NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[0], 1.0f), + NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[1], 1.0f), + NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[2], 1.0f), + }}; const AZStd::vector MeshIndices = {{ 0, 1, 2 @@ -98,7 +104,7 @@ namespace UnitTest { AZ::EntityId entityId; AZStd::unique_ptr actorClothSkinning = - NvCloth::ActorClothSkinning::Create(entityId, {}, 0, 0, {}); + NvCloth::ActorClothSkinning::Create(entityId, {}, {}, 0, {}); EXPECT_TRUE(actorClothSkinning.get() == nullptr); } @@ -107,7 +113,7 @@ namespace UnitTest { AZ::EntityId entityId; AZStd::unique_ptr actorClothSkinning = - NvCloth::ActorClothSkinning::Create(entityId, MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices); + NvCloth::ActorClothSkinning::Create(entityId, MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices); EXPECT_TRUE(actorClothSkinning.get() == nullptr); } @@ -122,7 +128,7 @@ namespace UnitTest } AZStd::unique_ptr actorClothSkinning = - NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), {}, 0, 0, {}); + NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), {}, {}, 0, {}); EXPECT_TRUE(actorClothSkinning.get() == nullptr); } @@ -139,7 +145,7 @@ namespace UnitTest } AZStd::unique_ptr actorClothSkinning = - NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices); + NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices); EXPECT_TRUE(actorClothSkinning.get() == nullptr); } @@ -156,7 +162,7 @@ namespace UnitTest } AZStd::unique_ptr actorClothSkinning = - NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices); + NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices); EXPECT_TRUE(actorClothSkinning.get() != nullptr); } @@ -184,20 +190,15 @@ namespace UnitTest } AZStd::unique_ptr actorClothSkinning = - NvCloth::ActorClothSkinning::Create(actorComponent->GetEntityId(), MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices); + NvCloth::ActorClothSkinning::Create(actorComponent->GetEntityId(), MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices); ASSERT_TRUE(actorClothSkinning.get() != nullptr); - const AZStd::vector clothParticles = {{ - NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[0], 1.0f), - NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[1], 1.0f), - NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[2], 1.0f), - }}; - AZStd::vector skinnedClothParticles(clothParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f)); + AZStd::vector skinnedClothParticles(MeshParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f)); actorClothSkinning->UpdateSkinning(); - actorClothSkinning->ApplySkinning(clothParticles, skinnedClothParticles); + actorClothSkinning->ApplySkinning(MeshParticles, skinnedClothParticles); - EXPECT_THAT(skinnedClothParticles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), clothParticles)); + EXPECT_THAT(skinnedClothParticles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), MeshParticles)); // Update actor instance's joints transforms const AZ::Transform newMeshNodeTransform = AZ::Transform::CreateRotationY(AZ::DegToRad(180.0f)); @@ -205,10 +206,10 @@ namespace UnitTest currentPose->SetLocalSpaceTransform(0, newMeshNodeTransform); actorComponent->GetActorInstance()->UpdateSkinningMatrices(); - AZStd::vector newSkinnedClothParticles(clothParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f)); + AZStd::vector newSkinnedClothParticles(MeshParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f)); actorClothSkinning->UpdateSkinning(); - actorClothSkinning->ApplySkinning(clothParticles, newSkinnedClothParticles); + actorClothSkinning->ApplySkinning(MeshParticles, newSkinnedClothParticles); const AZ::Transform diffTransform = AZ::Transform::CreateRotationY(AZ::DegToRad(90.0f)); const AZStd::vector clothParticlesResult = {{ @@ -245,20 +246,15 @@ namespace UnitTest } AZStd::unique_ptr actorClothSkinning = - NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices); + NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices); ASSERT_TRUE(actorClothSkinning.get() != nullptr); - const AZStd::vector clothParticles = {{ - NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[0], 1.0f), - NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[1], 1.0f), - NvCloth::SimParticleFormat::CreateFromVector3AndFloat(MeshVertices[2], 1.0f), - }}; - AZStd::vector skinnedClothParticles(clothParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f)); + AZStd::vector skinnedClothParticles(MeshParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f)); actorClothSkinning->UpdateSkinning(); - actorClothSkinning->ApplySkinning(clothParticles, skinnedClothParticles); + actorClothSkinning->ApplySkinning(MeshParticles, skinnedClothParticles); - EXPECT_THAT(skinnedClothParticles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), clothParticles)); + EXPECT_THAT(skinnedClothParticles, ::testing::Pointwise(ContainerIsCloseTolerance(Tolerance), MeshParticles)); // Update actor instance's joints transforms const AZ::Transform newJointRootTransform = AZ::Transform::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateRotationZ(AZ::DegToRad(-32.0f)), AZ::Vector3(2.5f, -6.0f, 0.2f)); @@ -268,10 +264,10 @@ namespace UnitTest currentPose->SetLocalSpaceTransform(1, newJointChildTransform); m_actorComponent->GetActorInstance()->UpdateSkinningMatrices(); - AZStd::vector newSkinnedClothParticles(clothParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f)); + AZStd::vector newSkinnedClothParticles(MeshParticles.size(), NvCloth::SimParticleFormat(0.0f, 0.0f, 0.0f, 1.0f)); actorClothSkinning->UpdateSkinning(); - actorClothSkinning->ApplySkinning(clothParticles, newSkinnedClothParticles); + actorClothSkinning->ApplySkinning(MeshParticles, newSkinnedClothParticles); const AZStd::vector clothParticlesResult = {{ NvCloth::SimParticleFormat(-48.4177f, -31.9446f, 45.2279f, 1.0f), @@ -294,7 +290,7 @@ namespace UnitTest } AZStd::unique_ptr actorClothSkinning = - NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshVertices.size(), MeshVertices.size(), MeshRemappedVertices); + NvCloth::ActorClothSkinning::Create(m_actorComponent->GetEntityId(), MeshNodeInfo, MeshParticles, MeshParticles.size(), MeshRemappedVertices); ASSERT_TRUE(actorClothSkinning.get() != nullptr); EXPECT_FALSE(actorClothSkinning->IsActorVisible()); diff --git a/Gems/NvCloth/Code/Tests/Components/ClothComponentTest.cpp b/Gems/NvCloth/Code/Tests/Components/ClothComponentTest.cpp index 379cf6988d..ad37c8f079 100644 --- a/Gems/NvCloth/Code/Tests/Components/ClothComponentTest.cpp +++ b/Gems/NvCloth/Code/Tests/Components/ClothComponentTest.cpp @@ -12,8 +12,6 @@ #include -#include - #include #include #include @@ -25,48 +23,14 @@ namespace UnitTest { - //! Sets up a mock global environment to - //! change between server and client. class NvClothComponent : public ::testing::Test { - public: - static void SetUpTestCase(); - static void TearDownTestCase(); - protected: AZStd::unique_ptr CreateClothActorEntity(const NvCloth::ClothConfiguration& clothConfiguration); bool IsConnectedToMeshComponentNotificationBus(NvCloth::ClothComponent* clothComponent) const; - - private: - static AZStd::unique_ptr s_mockGEnv; - static SSystemGlobalEnvironment* s_previousGEnv; }; - AZStd::unique_ptr NvClothComponent::s_mockGEnv; - SSystemGlobalEnvironment* NvClothComponent::s_previousGEnv = nullptr; - - void NvClothComponent::SetUpTestCase() - { - // override global environment - s_previousGEnv = gEnv; - s_mockGEnv = AZStd::make_unique(); - gEnv = s_mockGEnv.get(); - -#if !defined(CONSOLE) - // Set environment to not be a server by default. - gEnv->SetIsDedicated(false); -#endif - } - - void NvClothComponent::TearDownTestCase() - { - // restore global environment - gEnv = s_previousGEnv; - s_mockGEnv.reset(); - s_previousGEnv = nullptr; - } - AZStd::unique_ptr NvClothComponent::CreateClothActorEntity(const NvCloth::ClothConfiguration& clothConfiguration) { AZStd::unique_ptr entity = AZStd::make_unique(); @@ -101,21 +65,43 @@ namespace UnitTest EXPECT_TRUE(sortOutcome.IsSuccess()); } -#if !defined(CONSOLE) - TEST_F(NvClothComponent, ClothComponent_OnServer_DoesNotConnectToMeshComponentNotificationBusOnActivation) + TEST_F(NvClothComponent, ClothComponent_WithoutMultiplayerGem_ConnectsToMeshComponentNotificationBusOnActivation) + { + AZStd::unique_ptr entity = CreateClothActorEntity({}); + entity->Activate(); + + auto* clothComponent = entity->FindComponent(); + + EXPECT_TRUE(IsConnectedToMeshComponentNotificationBus(clothComponent)); + } + + TEST_F(NvClothComponent, ClothComponent_WithMultiplayerGem_Game_ConnectsToMeshComponentNotificationBusOnActivation) { - gEnv->SetIsDedicated(true); + // Fake that multiplayer gem is enabled by creating a local sv_isDedicated AZ_CVAR + AZ::ConsoleDataWrapper> sv_isDedicated(false, + nullptr, "sv_isDedicated", "", AZ::ConsoleFunctorFlags::DontReplicate); AZStd::unique_ptr entity = CreateClothActorEntity({}); entity->Activate(); auto* clothComponent = entity->FindComponent(); - EXPECT_FALSE(IsConnectedToMeshComponentNotificationBus(clothComponent)); + EXPECT_TRUE(IsConnectedToMeshComponentNotificationBus(clothComponent)); + } - gEnv->SetIsDedicated(false); + TEST_F(NvClothComponent, ClothComponent_WithMultiplayerGem_Server_DoesNotConnectToMeshComponentNotificationBusOnActivation) + { + // Fake that multiplayer gem is enabled by creating a local sv_isDedicated AZ_CVAR + AZ::ConsoleDataWrapper> sv_isDedicated(true, + nullptr, "sv_isDedicated", "", AZ::ConsoleFunctorFlags::DontReplicate); + + AZStd::unique_ptr entity = CreateClothActorEntity({}); + entity->Activate(); + + auto* clothComponent = entity->FindComponent(); + + EXPECT_FALSE(IsConnectedToMeshComponentNotificationBus(clothComponent)); } -#endif TEST_F(NvClothComponent, ClothComponent_OneEntityWithTwoClothComponents_BothConnectToMeshComponentNotificationBusOnActivation) { diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index ec98b0970f..b4c7b580a6 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -107,7 +107,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::SceneCore AZ::SceneData Legacy::CryCommon - Legacy::CryCommonTools Gem::LmbrCentral Gem::PhysX.NumericalMethods Gem::PhysX.Static diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp index 58b8995281..82a38a04c2 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp @@ -326,6 +326,7 @@ namespace PhysX else { m_shapeType = !shapeCrc ? ShapeType::None : ShapeType::Unsupported; + m_shapeConfigs.clear(); AZ_Warning("PhysX Shape Collider Component", m_shapeTypeWarningIssued, "Unsupported shape type for " "entity \"%s\". The following shapes are currently supported - box, capsule, sphere, polygon prism.", GetEntity()->GetName().c_str()); diff --git a/Registry/application_options.setreg b/Registry/application_options.setreg index 06ccdc9b41..8dbb6fe418 100644 --- a/Registry/application_options.setreg +++ b/Registry/application_options.setreg @@ -6,6 +6,7 @@ "project-path", "engine-path", "project-cache-path", + "project-build-path", "regset", "regremove", "regdump", diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py index 36746b510f..1b0afb3efe 100755 --- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py +++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/base.py @@ -108,15 +108,7 @@ class Launcher(object): # Wait for the AssetProcessor to be open. if launch_ap: - timeout = 10 - self.workspace.asset_processor.start() - ly_test_tools.environment.waiter.wait_for( - lambda: ly_test_tools.environment.process_utils.process_exists( - name="AssetProcessor", ignore_extensions=True), - exc=ly_test_tools.launchers.exceptions.SetupError( - f'AssetProcessor never opened after {timeout} seconds'), - timeout=timeout - ) + self.workspace.asset_processor.start(connect_to_ap=True, connection_timeout=10) # verify connection self.workspace.asset_processor.wait_for_idle() log.debug('AssetProcessor started from calling Launcher.setup()') diff --git a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py index 11cd1fc4ce..0983d2c45f 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py @@ -20,7 +20,7 @@ import time import tempfile import shutil import stat -from typing import List +from typing import List, Tuple import psutil import ly_test_tools @@ -45,6 +45,7 @@ ASSET_PROCESSOR_PLATFORM_MAP = { ASSET_PROCESSOR_SETTINGS_ROOT_KEY = '/Amazon/AssetProcessor/Settings' + class AssetProcessorError(Exception): """ Indicates that the AssetProcessor raised an error """ @@ -88,11 +89,16 @@ class AssetProcessor(object): def wait_for_idle(self, timeout=DEFAULT_TIMEOUT_SECONDS): """ Communicate with asset processor to request a response if either AP is currently idle, - or whenever it becomes idle + or that it becomes idle within the timeout """ + if not self.process_exists(): + logger.warning("Not currently managing a running Asset Processor, cannot request idle") + return False + self.send_message("waitforidle") result = self.read_message(read_timeout=timeout) - assert result == "idle" or not self.process_exists(), f"Couldn't get idle state from AP, message {result}" + assert self.process_exists(), "Asset Processor appears unexpectedly shut down, or has crashed" + assert result == "idle", f"Did not get idle state from AP, message was instead: {result}" return True def next_idle(self): @@ -103,9 +109,14 @@ class AssetProcessor(object): which will be picked up by the scanner but may take a couple seconds to begin, and you only want to hear back after it's done. """ + if not self.process_exists(): + logger.warning("Not currently managing a running Asset Processor, cannot request idle") + return + self.send_message("signalidle") result = self.read_message() - assert result == "idle" or not self.process_exists(), f"Couldn't get idle state from AP, message {result}" + assert self.process_exists(), "Asset Processor appears unexpectedly shut down, or has crashed" + assert result == "idle", f"Did not get idle state from AP, message was instead: {result}" def send_quit(self): """ @@ -160,8 +171,6 @@ class AssetProcessor(object): logger.warning(f"Failed to read message from with error {e}") return f"error_{e}" - - def read_control_port(self): return self.read_port_from_log("Control Port") @@ -185,7 +194,7 @@ class AssetProcessor(object): if port: logger.info(f"Read port type {port_type} : {port}") return port - except: + except Exception: # intentionally broad pass time.sleep(1) logger.warning(f"Failed to read port type {port_type}") @@ -203,7 +212,7 @@ class AssetProcessor(object): control_timeout = 60 try: return self.connect_socket("Control Connection", self.read_control_port, - set_port_method=self.set_control_connection, timeout=control_timeout) + set_port_method=self.set_control_connection, timeout=control_timeout) except AssetProcessorError as e: # We dont want a failure of our test socket connection to fail the entire test automatically. logger.error(f"Failed to connect control socket with error {e}") @@ -237,7 +246,7 @@ class AssetProcessor(object): if set_port_method is not None: set_port_method(connection_socket) return True, None - except Exception as e: # Purposefully broad + except Exception: # Purposefully broad # Short delay to prevent immediate failure due to slower starting applications such as debug builds time.sleep(0.01) if not connect_port or not self.using_temp_workspace(): @@ -261,7 +270,7 @@ class AssetProcessor(object): :return: None """ if not self._ap_proc: - logger.info("Attempting to quit AP but none running") + logger.warning("Attempting to quit AP but none running") return if not self._control_connection: @@ -319,7 +328,7 @@ class AssetProcessor(object): pass _, remaining = psutil.wait_procs(process_list, timeout=10, callback=term_success) for process in remaining: - logger.info(f"Killing: {this_process.name()} pid: {this_process.pid}") + logger.info(f"Killing: {process.name()} pid: {process.pid}") process.kill() logger.info("Finished terminating asset processor") self._ap_proc = None @@ -500,22 +509,17 @@ class AssetProcessor(object): def build_ap_command(self, ap_path, fastscan=True, platforms=None, extra_params=None, add_gem_scan_folders=None, add_config_scan_folders=None, scan_folder_pattern=None): - # type: (float, bool) -> bool """ Launch asset processor batch and wait for it to complete or until the timeout expires. Returns true on success and False if an error is reported. :param fastscan: Enable "zero analysis mode" - :param capture_output = Capture output which will be returned in the second of the return pair :param platforms: Different set of platforms to run against :param add_gem_scan_folders: Should gem scan folders be added to the processing - by default this is off if scan folder overrides are set, on if not :param add_config_scan_folders: Should config scan folders be added to the processing - by default this is off if scan folder overrides are set, on if not - :param decode: decode byte strings from captured output to utf-8 - :return: Pair: Success, output: True if all assets were processed successfully, False if the process times out - or returns errors. output is raw output from process - + :return: Command list ready to pass to subprocess """ logger.info(f"Starting {ap_path}") command = [ap_path] @@ -784,7 +788,7 @@ class AssetProcessor(object): def prepare_test_environment(self, assets_path: str, function_name: str, use_current_root=False, relative_asset_root=None, add_scan_folder=True, cache_platform=None, - existing_function_name=None) -> str: + existing_function_name=None) -> Tuple[str, str]: """ Creates a temporary test workspace, copies the specified test assets and sets the folder as a scan folder for processing. @@ -844,7 +848,7 @@ class AssetProcessor(object): """ return self._test_assets_source_folder - def compare_assets_with_cache(self) -> str: + def compare_assets_with_cache(self) -> Tuple[List[str], List[str]]: """ Helper to compare output assets from a test run using prepare_test_environment @@ -982,14 +986,10 @@ def _build_ap_batch_call_params(ap_path, project, platforms, extra_params=None): project_str.rstrip(' ') param_list = [ap_path, project_str] - if self._disable_all_platforms: - command.append(f'--regremove="f{ASSET_PROCESSOR_SETTINGS_ROOT_KEY}/Platforms"') if platforms: if isinstance(platforms, list): platforms = ','.join(platforms) param_list.append(f'--platforms={platforms}') - for key, value in self._enabled_platform_overrides: - param_list.append(f'--regset="f{ASSET_PROCESSOR_SETTINGS_ROOT_KEY}/Platforms/{key}={value}"') if extra_params: if isinstance(extra_params, list): @@ -1053,4 +1053,3 @@ def get_num_failed_processed_assets(output): def has_invalid_server_address(output): return parse_output_value(output, 'Invalid server address') is not None - diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 139c2a24d1..781fee3711 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -105,9 +105,54 @@ function(ly_add_project_dependencies) ) endfunction() +#template for generating the project build_path setreg +set(project_build_path_template [[ +{ + "Amazon": { + "Project": { + "Settings": { + "Build": { + "project_build_path": "@project_bin_path@" + } + } + } + } +}]] +) + + +#! ly_generate_project_build_path_setreg: Generates a .setreg file that contains an absolute path to the ${CMAKE_BINARY_DIR} +# This allows locate the directory where the project it's binaries are built to be located within the engine. +# Which are the shared libraries and launcher executables +# When an a pre-built engine application runs from a directory other than the project build directory, it needs +# to be able to locate the project build directory to determine the list of gems that the project depends on to load +# as well the location of those gems. +# For example if the project uses an external gem not associated with the engine, that gem's dlls/so/dylib files +# would be located within the project build directory and the engine SDK binary directory would need that info + +# NOTE: This only needed for non-monolithic host platforms. +# This is because there are no dynamic gems to load on monolithic builds +# Furthermore the pre-built SDK engine applications such as the Editor and AssetProcessor +# can only run on the host platform +# \arg:project_real_path Full path to the o3de project directory +function(ly_generate_project_build_path_setreg project_real_path) + # The build path isn't needed on non-monolithic platforms + # Nor on any non-host platforms + if (LY_MONOLITHIC_GAME OR NOT PAL_TRAIT_BUILD_HOST_TOOLS) + return() + endif() + + # Set the project_bin_path to the ${CMAKE_BINARY_DIR} to provide the configure template + # with the project build directory + set(project_bin_path ${CMAKE_BINARY_DIR}) + string(CONFIGURE ${project_build_path_template} project_build_path_setreg_content @ONLY) + set(project_user_build_path_setreg_file ${project_real_path}/user/Registry/Platform/${PAL_PLATFORM_NAME}/build_path.setreg) + file(GENERATE OUTPUT ${project_user_build_path_setreg_file} CONTENT ${project_build_path_setreg_content}) +endfunction() + # Add the projects here so the above function is found foreach(project ${LY_PROJECTS}) - get_filename_component(full_directory_path ${project} REALPATH ${CMAKE_SOURCE_DIR}) + file(REAL_PATH ${project} full_directory_path BASE_DIRECTORY ${CMAKE_SOURCE_DIR}) string(SHA256 full_directory_hash ${full_directory_path}) # Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit @@ -117,5 +162,6 @@ foreach(project ${LY_PROJECTS}) get_filename_component(project_folder_name ${project} NAME) list(APPEND LY_PROJECTS_FOLDER_NAME ${project_folder_name}) add_subdirectory(${project} "${project_folder_name}-${full_directory_hash}") + ly_generate_project_build_path_setreg(${full_directory_path}) endforeach() ly_set(LY_PROJECTS_FOLDER_NAME ${LY_PROJECTS_FOLDER_NAME}) diff --git a/cmake/Tools/registration.py b/cmake/Tools/registration.py index 292ec33d1f..184d2cdb31 100755 --- a/cmake/Tools/registration.py +++ b/cmake/Tools/registration.py @@ -258,15 +258,6 @@ def register_shipped_engine_o3de_objects() -> int: if error_code: ret_val = error_code - starting_external_subdirectories = [ - f'{engine_path}/Gems/Atom', - f'{engine_path}/Gems/AtomLyIntegration' - ] - for external_subdir in sorted(starting_external_subdirectories, reverse=True): - error_code = add_external_subdirectory(engine_path=engine_path, external_subdir=external_subdir) - if error_code: - ret_val = error_code - json_data = load_o3de_manifest() engine_object = find_engine_data(json_data) gems = json_data['gems'].copy() diff --git a/scripts/build/package/Platform/Windows/package_filelists/atom.json b/scripts/build/package/Platform/Windows/package_filelists/atom.json index 5f3d3b78cb..e18e191882 100644 --- a/scripts/build/package/Platform/Windows/package_filelists/atom.json +++ b/scripts/build/package/Platform/Windows/package_filelists/atom.json @@ -37,7 +37,6 @@ "AssetBundler/**": "#include", "AzTestRunner/**": "#include", "CrashHandler/**": "#include", - "CryCommonTools/**": "#include", "DeltaCataloger/**": "#include", "GridHub/**": "#include", "News/**": "#include", @@ -139,7 +138,6 @@ "3dsmax/**": "#include", "7za.exe": "#include", "7za_legal_notice.txt": "#include", - "CrySCompileServer/**": "#include", "PakShaders/**": "#include", "Python/**": "#include", "Redistributables": {