summaryrefslogtreecommitdiff
path: root/Runtime/Serialize/Blobification/BlobWrite.cpp
blob: dcb7705e05f86bdc5e9ed413082a0fa081d5642b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include "UnityPrefix.h"
#include "BlobWrite.h"
#include "Configuration/UnityConfigure.h"
#include "BlobWriteTargetSupport.h"

BlobWrite::BlobWrite (container_type& blob, TransferInstructionFlags flags, BuildTargetPlatform targetPlatform)
:	m_Blob(blob),
	m_CopyData(true),
	m_ReduceCopy(false),
	m_TargetPlatform(targetPlatform)
{
	m_Flags = false;
	m_SwapEndianess = m_Flags & kSwapEndianess;
	m_Use64BitOffsetPtr = IsBuildTarget64BitBlob (targetPlatform);
}

void BlobWrite::Push (size_t size, void* srcDataPtr, size_t align)
{
	Assert (m_CopyData);
	
	size_t offset = AlignAddress(m_Blob.size(), align);
	m_Context.push( TypeContext(offset, 0, reinterpret_cast<UInt8*> (srcDataPtr), size) );
	m_Blob.resize_initialized(offset + size, 0);
	m_CopyData = false;
}

void BlobWrite::WritePtrValueAtLocation (size_t locationInBlob, SInt64 value)
{
	if (m_Use64BitOffsetPtr)
	{
		SInt64 offset64 = value;
		
		if (m_SwapEndianess)
			SwapEndianBytes(offset64);
		memcpy (&m_Blob[locationInBlob], &offset64, sizeof(offset64));
	}
	else
	{
		SInt32 offset32 = value;
		
		if (m_SwapEndianess)
			SwapEndianBytes(offset32);
		memcpy (&m_Blob[locationInBlob], &offset32, sizeof(offset32));
	}
}


void BlobWrite::TransferPtrImpl (bool isValidPtr, ReduceCopyData* reduceCopyData, size_t alignOfT)
{
	Assert(!m_CopyData);
	// When the data is null we will not call Transfer.
	m_CopyData = isValidPtr;
	
	// Need to update OffsetPtr's member 'mOffset'
	// compute member offset in memory buffer
	size_t dataPosition = AlignAddress(m_Blob.size(), alignOfT);
	size_t offset = GetActiveOffset();
	offset = dataPosition - offset;
	if (!isValidPtr)
		offset = 0;
	
	// Write the ptr
	WritePtrValueAtLocation(GetActiveOffset (), offset);
	
	// Setup reduce copy data for later use by ReduceCopyImpl
	if (reduceCopyData != NULL)
	{
		if (isValidPtr)
		{
			reduceCopyData->ptrPosition = GetActiveOffset();
			reduceCopyData->dataStart = dataPosition;
			reduceCopyData->blobSize = m_Blob.size();
		}
		else
		{
			reduceCopyData->ptrPosition = 0xFFFFF;
			reduceCopyData->dataStart = 0xFFFFF;
			reduceCopyData->blobSize = 0xFFFFF;
		}
	}
	
	
	// Offset write location in the blob
	m_Context.top().m_Offset += m_Use64BitOffsetPtr ? sizeof(SInt64) : sizeof(SInt32);
	if (HasOffsetPtrWithDebugPtr())
		m_Context.top().m_Offset += sizeof(void*);
}

bool BlobWrite::HasOffsetPtrWithDebugPtr () const
{
	return m_TargetPlatform == kBuildNoTargetPlatform;
}

bool BlobWrite::AllowDataLayoutValidation () const
{
	size_t targetOffsetPtrSize = Use64BitOffsetPtr () ? sizeof(SInt64) : sizeof(SInt32);
	if (HasOffsetPtrWithDebugPtr ())
		targetOffsetPtrSize += sizeof(void*);
	
	size_t srcOffsetPtrSize = sizeof(OffsetPtr<UInt8>);

	return targetOffsetPtrSize == srcOffsetPtrSize;
}

// Ensure that the user has matching Transfer calls & Data layout in the struct
void BlobWrite::ValidateSerializedLayout (void* srcData, const char* name)
{
	UInt8* srcDataPtr = reinterpret_cast<UInt8*> (srcData);
	
	// (float4 and some others transfer functions, transfer temporary data, we ignore layout checks on those and hope for the best)
	int srcDataOffset = srcDataPtr - m_Context.top().m_SourceDataPtr;
	if (srcDataOffset < 0 || srcDataOffset >= m_Context.top().m_SourceDataSize)
		return;
	
	// When targeting a platform with a different layout than our own, obviously these checks dont make sense...
	if (!AllowDataLayoutValidation ())
		return;
	
	int blobOffset = m_Context.top().m_Offset;
	if (srcDataOffset != blobOffset)
	{
		AssertString(Format("BlobWrite: Transfer '%s' is not called in the same order as the struct is laid out. Expected: %d got: %d ", name, srcDataOffset, blobOffset));
	}
}

void BlobWrite::ReduceCopyImpl (const ReduceCopyData& reduce, size_t alignOfT)
{
	if (!m_ReduceCopy || reduce.dataStart == 0xFFFFF)
		return;
	
	// Find any data in the blob that matches the last written data.
	// if we find it, delete it again and reference the previous memory block instead
	size_t dataSize = m_Blob.size() - reduce.dataStart;
	for (int i=0;i < reduce.dataStart;i+=alignOfT)
	{
		if (memcmp(&m_Blob[i], &m_Blob[reduce.dataStart], dataSize) == 0)
		{
			// Update offset pointer
			SInt64 offset = i - reduce.ptrPosition;
			WritePtrValueAtLocation (reduce.ptrPosition, offset);
			
			// resize blob based on the reduce copy
			m_Blob.resize_initialized(reduce.blobSize, 0);
			
			return;
		}
	}
}