void object::test<5>()
 {
     set_test_name("bad type");
     LLSD request;
     request["uri"] = uri;
     request["method"] = "getdict";
     request["reply"] = "reply";
     (void)request["params"];
     // Set up a timeout filter so we don't spin forever waiting.
     LLEventTimeout watchdog;
     // Connect the timeout filter to the reply pump.
     LLTempBoundListener temp(
         pumps.obtain("reply").
         listen("watchdog", boost::bind(&LLEventTimeout::post, boost::ref(watchdog), _1)));
     // Now connect our target listener to the timeout filter.
     watchdog.listen("captureReply", boost::bind(&data::captureReply, this, _1));
     // Kick off the request...
     reply.clear();
     pumps.obtain("LLXMLRPCTransaction").post(request);
     // Set the timer
     F32 timeout(10);
     watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
     // and pump "mainloop" until we get something, whether from
     // LLXMLRPCListener or from the watchdog filter.
     LLTimer timer;
     F32 start = timer.getElapsedTimeF32();
     LLEventPump& mainloop(pumps.obtain("mainloop"));
     while (reply.isUndefined())
     {
         mainloop.post(LLSD());
     }
     ensure("timeout works", (timer.getElapsedTimeF32() - start) < (timeout + 1));
     ensure_equals(reply["status"].asString(), "BadType");
     ensure_contains("bad type", reply["responses"]["nested_dict"].asString(), "bad XMLRPC type");
 }
		/*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content)
		{
			slmGetTimer.stop();

			if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
			{
				llinfos << " SLM GET status: " << status << llendl;
				llinfos << " SLM GET reason: " << reason << llendl;
				llinfos << " SLM GET content: " << content.asString() << llendl;

				llinfos << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << llendl;
			}

			if ((status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) ||
				(status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT))
			{
				if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
				{
					llinfos << " SLM GET clearing marketplace cookie due to authentication failure or timeout (" << status << " / " << reason << ")." << llendl;
				}

				sMarketplaceCookie.clear();
			}

			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING);
			sImportGetPending = false;
			sImportResultStatus = status;
			sImportResults = content;
		}
		/*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content)
		{
			slmGetTimer.stop();

			if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
			{
				llinfos << " SLM GET status: " << status << llendl;
				llinfos << " SLM GET reason: " << reason << llendl;
				llinfos << " SLM GET content: " << content.asString() << llendl;
				llinfos << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << llendl;
			}

			// MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions
			// ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initially empty
			if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) &&
				(status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) &&
				(status != MarketplaceErrorCodes::IMPORT_NOT_FOUND))
			{
				if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
				{
					llinfos << " SLM GET clearing marketplace cookie due to client or server error (" << status << " / " << reason << ")." << llendl;
				}
				sMarketplaceCookie.clear();
			}
			else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST))
			{
				llinfos << " SLM GET : Got error status = " << status << ", but marketplace cookie not cleared." << llendl;
			}

			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING);
			sImportGetPending = false;
			sImportResultStatus = status;
			sImportResults = content;
		}
		/*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content)
		{
			slmGetTimer.stop();

			if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
			{
				llinfos << " SLM GET status: " << status << llendl;
				llinfos << " SLM GET reason: " << reason << llendl;
				llinfos << " SLM GET content: " << content.asString() << llendl;
				llinfos << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << llendl;
			}

			// MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS
			if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) &&
				(status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS))
			{
				if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
				{
					llinfos << " SLM GET clearing marketplace cookie due to client or server error (" << status << " / " << reason << ")." << llendl;
				}
				sMarketplaceCookie.clear();
			}
			else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (status == MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS))
			{
				llinfos << " SLM GET : Got IMPORT_DONE_WITH_ERRORS, marketplace cookie not cleared." << llendl;
			}

			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING);
			sImportGetPending = false;
			sImportResultStatus = status;
			sImportResults = content;
		}
F32 pump_loop(LLPumpIO* pump, F32 seconds)
{
	LLTimer timer;
	timer.setTimerExpirySec(seconds);
	while(!timer.hasExpired())
	{
		LLFrameTimer::updateFrameTime();			
		pump->pump();
		pump->callback();
	}
	return timer.getElapsedTimeF32();
}
Exemple #6
0
void LLProgressBar::draw()
{
	static LLTimer timer;
	F32 alpha = getDrawContext().mAlpha;
	
	LLColor4 image_bar_color = mColorBackground.get();
	image_bar_color.setAlpha(alpha);
	mImageBar->draw(getLocalRect(), image_bar_color);

	alpha *= 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
	LLColor4 bar_color = mColorBar.get();
	bar_color.mV[VALPHA] *= alpha; // modulate alpha
	LLRect progress_rect = getLocalRect();
	progress_rect.mRight = llround(getRect().getWidth() * (mPercentDone / 100.f));
	mImageFill->draw(progress_rect, bar_color);
}
Exemple #7
0
void LLTextureCache::purgeTextureFilesTimeSliced(BOOL force_all)
{
	LLMutexLock lock(&mHeaderMutex);

	F32 delay_between_passes = 1.0f; // seconds
	F32 max_time_per_pass = 0.1f; // seconds

	if (!force_all && mTimeLastFileDelete.getElapsedTimeF32() <= delay_between_passes) 
	{
		return;
	}

	LLTimer timer;
	S32 howmany = 0;

	if (mFilesToDelete.size() > 0)
	{
		llinfos << "TEXTURE CACHE: " << mFilesToDelete.size() << " files scheduled for deletion" << llendl;
	}

	for (LLTextureCache::filename_list_t::iterator iter = mFilesToDelete.begin(); iter!=mFilesToDelete.end(); ) 
	{	
		LLTextureCache::filename_list_t::iterator iter2 = iter++;
		ll_apr_file_remove(*iter2, NULL);
		mFilesToDelete.erase(iter2);
		howmany++;

		if (!force_all && timer.getElapsedTimeF32() > max_time_per_pass) 
		{
			break;
		}
	}

	if (!mFilesToDelete.empty())
	{
		llinfos << "TEXTURE CACHE: "<< howmany << " files deleted (" 
				<< mFilesToDelete.size() << " files left for next pass)" 
				<< llendl;
	}

	mTimeLastFileDelete.reset();
}
void LLProgressBar::draw()
{
	static LLTimer timer;

	LLUIImagePtr shadow_imagep = LLUI::getUIImage("rounded_square_soft.tga");
	LLUIImagePtr bar_fg_imagep = LLUI::getUIImage("progressbar_fill.tga");
	LLUIImagePtr bar_bg_imagep = LLUI::getUIImage("progressbar_track.tga");
	LLUIImagePtr bar_imagep = LLUI::getUIImage("rounded_square.tga");
	LLColor4 background_color = LLUI::sColorsGroup->getColor("LoginProgressBarBgColor");
	
	bar_bg_imagep->draw(getLocalRect(),
		background_color);

	F32 alpha = 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
	LLColor4 bar_color = LLUI::sColorsGroup->getColor("LoginProgressBarFgColor");
	bar_color.mV[3] = alpha;
	LLRect progress_rect = getLocalRect();
	progress_rect.mRight = llround(getRect().getWidth() * (mPercentDone / 100.f));
	bar_fg_imagep->draw(progress_rect);
}
		/*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content)
		{
			slmPostTimer.stop();

			if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
			{
				llinfos << " SLM POST status: " << status << llendl;
				llinfos << " SLM POST reason: " << reason << llendl;
				llinfos << " SLM POST content: " << content.asString() << llendl;
				llinfos << " SLM POST timer: " << slmPostTimer.getElapsedTimeF32() << llendl;
			}

			// MAINT-2301 : we determined we can safely ignore that error in that context
			if (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)
			{
				if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
				{
					llinfos << " SLM POST : Ignoring time out status and treating it as success" << llendl;
				}
				status = MarketplaceErrorCodes::IMPORT_DONE;
			}

			if (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)
			{
				if (gSavedSettings.getBOOL("InventoryOutboxLogging"))
				{
					llinfos << " SLM POST clearing marketplace cookie due to client or server error" << llendl;
				}
				sMarketplaceCookie.clear();
			}

			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE);
			sImportPostPending = false;
			sImportResultStatus = status;
			sImportId = content;
		}
Exemple #10
0
BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host)
{
	//<edit>
	LLMessageLog::log(LLHost(16777343, gMessageSystem->getListenPort()), host, (U8*)send_buffer, buf_size);
	//</edit>
	BOOL status = TRUE;
	if (!mUseOutThrottle)
	{
		return doSendPacket(h_socket, send_buffer, buf_size, host );
	}
	else
	{
		mActualBitsOut += buf_size * 8;
		LLPacketBuffer *packetp = NULL;
		// See if we've got enough throttle to send a packet.
		while (!mOutThrottle.checkOverflow(0.f))
		{
			// While we have enough bandwidth, send a packet from the queue or the current packet

			S32 packet_size = 0;
			if (!mSendQueue.empty())
			{
				// Send a packet off of the queue
				LLPacketBuffer *packetp = mSendQueue.front();
				mSendQueue.pop();

				mOutBufferLength -= packetp->getSize();
				packet_size = packetp->getSize();

				status = doSendPacket(h_socket, packetp->getData(), packet_size, packetp->getHost());
				
				delete packetp;
				// Update the throttle
				mOutThrottle.throttleOverflow(packet_size * 8.f);
			}
			else
			{
				// If the queue's empty, we can just send this packet right away.
				status =  doSendPacket(h_socket, send_buffer, buf_size, host );
				packet_size = buf_size;

				// Update the throttle
				mOutThrottle.throttleOverflow(packet_size * 8.f);

				// This was the packet we're sending now, there are no other packets
				// that we need to send
				return status;
			}

		}

		// We haven't sent the incoming packet, add it to the queue
		if (mOutBufferLength + buf_size > mMaxBufferLength)
		{
			// Nuke this packet, we overflowed the buffer.
			// Toss it.
			llwarns << "Throwing away outbound packet, overflowing buffer" << llendl;
		}
		else
		{
			static LLTimer queue_timer;
			if ((mOutBufferLength > 4192) && queue_timer.getElapsedTimeF32() > 1.f)
			{
				// Add it to the queue
				llinfos << "Outbound packet queue " << mOutBufferLength << " bytes" << llendl;
				queue_timer.reset();
			}
			packetp = new LLPacketBuffer(host, send_buffer, buf_size);

			mOutBufferLength += packetp->getSize();
			mSendQueue.push(packetp);
		}
	}

	return status;
}
Exemple #11
0
BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
{
	LLFastTimer ftm(FTM_GEO_SKY);
	LLStrider<LLVector3>	vertices;
	LLStrider<LLVector2>	texCoords;
	LLStrider<U16>			indices;

#if DOME_SLICES
	{
		mFanVerts = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
		mFanVerts->allocateBuffer(getFanNumVerts(), getFanNumIndices(), TRUE);

		BOOL success = mFanVerts->getVertexStrider(vertices)
			&& mFanVerts->getTexCoord0Strider(texCoords)
			&& mFanVerts->getIndexStrider(indices);

		if(!success) 
		{
			llerrs << "Failed updating WindLight sky geometry." << llendl;
		}

		buildFanBuffer(vertices, texCoords, indices);

		mFanVerts->flush();
	}

	{
		const U32 max_buffer_bytes = gSavedSettings.getS32("RenderMaxVBOSize")*1024;
		const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK;
		const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcVertexSize(data_mask);

		const U32 total_stacks = getNumStacks();

		const U32 verts_per_stack = getNumSlices();

		// each seg has to have one more row of verts than it has stacks
		// then round down
		const U32 stacks_per_seg = (max_verts - verts_per_stack) / verts_per_stack;

		// round up to a whole number of segments
		const U32 strips_segments = (total_stacks+stacks_per_seg-1) / stacks_per_seg;

		llinfos << "WL Skydome strips in " << strips_segments << " batches." << llendl;

		mStripsVerts.resize(strips_segments, NULL);

		LLTimer timer;
		timer.start();

		for (U32 i = 0; i < strips_segments ;++i)
		{
			LLVertexBuffer * segment = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
			mStripsVerts[i] = segment;

			U32 num_stacks_this_seg = stacks_per_seg;
			if ((i == strips_segments - 1) && (total_stacks % stacks_per_seg) != 0)
			{
				// for the last buffer only allocate what we'll use
				num_stacks_this_seg = total_stacks % stacks_per_seg;
			}

			// figure out what range of the sky we're filling
			const U32 begin_stack = i * stacks_per_seg;
			const U32 end_stack = begin_stack + num_stacks_this_seg;
			llassert(end_stack <= total_stacks);

			const U32 num_verts_this_seg = verts_per_stack * (num_stacks_this_seg+1);
			llassert(num_verts_this_seg <= max_verts);

			const U32 num_indices_this_seg = 1+num_stacks_this_seg*(2+2*verts_per_stack);
			llassert(num_indices_this_seg * sizeof(U16) <= max_buffer_bytes);

			segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg, TRUE);

			// lock the buffer
			BOOL success = segment->getVertexStrider(vertices)
				&& segment->getTexCoord0Strider(texCoords)
				&& segment->getIndexStrider(indices);

			if(!success) 
			{
				llerrs << "Failed updating WindLight sky geometry." << llendl;
			}

			// fill it
			buildStripsBuffer(begin_stack, end_stack,  vertices, texCoords, indices);

			// and unlock the buffer
			segment->flush();
		}
	
		llinfos << "completed in " << llformat("%.2f", timer.getElapsedTimeF32()) << "seconds" << llendl;
	}
#else
	mStripsVerts = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
	
	const F32 RADIUS = LLWLParamManager::sParamMgr->getDomeRadius();

	LLPointer<LLVertexBuffer> temp = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0);
	temp->allocateBuffer(12, 60, TRUE);

	BOOL success = temp->getVertexStrider(vertices)
		&& temp->getIndexStrider(indices);

	if (success)
	{
		for (U32 i = 0; i < 12; i++)
		{
			*vertices++ = icosahedron_vert[i];
		}

		for (U32 i = 0; i < 60; i++)
		{
			*indices++ = icosahedron_ind[i];
		}
	}


	LLPointer<LLVertexBuffer> temp2;
	
	for (U32 i = 0; i < 8; i++)
	{
		temp2 = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0);
		subdivide(*temp, temp2);
		temp = temp2;
	}
	
	temp->getVertexStrider(vertices);
	for (S32 i = 0; i < temp->getNumVerts(); i++)
	{
		LLVector3 v = vertices[i];
		v.normVec();
		vertices[i] = v*RADIUS;
	}

	temp2 = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0);
	chop(*temp, temp2);

	mStripsVerts->allocateBuffer(temp2->getNumVerts(), temp2->getNumIndices(), TRUE);
	
	success = mStripsVerts->getVertexStrider(vertices)
		&& mStripsVerts->getTexCoordStrider(texCoords)
		&& mStripsVerts->getIndexStrider(indices);

	LLStrider<LLVector3> v;
	temp2->getVertexStrider(v);
	LLStrider<U16> ind;
	temp2->getIndexStrider(ind);

	if (success)
	{
		for (S32 i = 0; i < temp2->getNumVerts(); ++i)
		{
			LLVector3 vert = *v++;
			vert.normVec();
			F32 z0 = vert.mV[2];
			F32 x0 = vert.mV[0];
			
			vert *= RADIUS;
			
			*vertices++ = vert;
			*texCoords++ = LLVector2((-z0 + 1.f) / 2.f, (-x0 + 1.f) / 2.f);
		}

		for (S32 i = 0; i < temp2->getNumIndices(); ++i)
		{
			*indices++ = *ind++;
		}
	}

	mStripsVerts->flush();
#endif

	updateStarColors();
	updateStarGeometry(drawable);

	LLPipeline::sCompiles++;

	return TRUE;
}
// decode a given message
BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender )
{
	llassert( mReceiveSize >= 0 );
	llassert( mCurrentRMessageTemplate);
	llassert( !mCurrentRMessageData );
	delete mCurrentRMessageData; // just to make sure

	// The offset tells us how may bytes to skip after the end of the
	// message name.
	U8 offset = buffer[PHL_OFFSET];
	S32 decode_pos = LL_PACKET_ID_SIZE + (S32)(mCurrentRMessageTemplate->mFrequency) + offset;

	// create base working data set
	mCurrentRMessageData = new LLMsgData(mCurrentRMessageTemplate->mName);
	
	// loop through the template building the data structure as we go
	LLMessageTemplate::message_block_map_t::const_iterator iter;
	for(iter = mCurrentRMessageTemplate->mMemberBlocks.begin();
		iter != mCurrentRMessageTemplate->mMemberBlocks.end();
		++iter)
	{
		LLMessageBlock* mbci = *iter;
		U8	repeat_number;
		S32	i;

		// how many of this block?

		if (mbci->mType == MBT_SINGLE)
		{
			// just one
			repeat_number = 1;
		}
		else if (mbci->mType == MBT_MULTIPLE)
		{
			// a known number
			repeat_number = mbci->mNumber;
		}
		else if (mbci->mType == MBT_VARIABLE)
		{
			// need to read the number from the message
			// repeat number is a single byte
			if (decode_pos >= mReceiveSize)
			{
				// commented out - hetgrid says that missing variable blocks
				// at end of message are legal
				// logRanOffEndOfPacket(sender, decode_pos, 1);

				// default to 0 repeats
				repeat_number = 0;
			}
			else
			{
				repeat_number = buffer[decode_pos];
				decode_pos++;
			}
		}
		else
		{
			llerrs << "Unknown block type" << llendl;
			return FALSE;
		}

		LLMsgBlkData* cur_data_block = NULL;

		// now loop through the block
		for (i = 0; i < repeat_number; i++)
		{
			if (i)
			{
				// build new name to prevent collisions
				// TODO: This should really change to a vector
				cur_data_block = new LLMsgBlkData(mbci->mName, repeat_number);
				cur_data_block->mName = mbci->mName + i;
			}
			else
			{
				cur_data_block = new LLMsgBlkData(mbci->mName, repeat_number);
			}

			// add the block to the message
			mCurrentRMessageData->addBlock(cur_data_block);

			// now read the variables
			for (LLMessageBlock::message_variable_map_t::const_iterator iter = 
					 mbci->mMemberVariables.begin();
				 iter != mbci->mMemberVariables.end(); iter++)
			{
				const LLMessageVariable& mvci = **iter;

				// ok, build out the variables
				// add variable block
				cur_data_block->addVariable(mvci.getName(), mvci.getType());

				// what type of variable?
				if (mvci.getType() == MVT_VARIABLE)
				{
					// variable, get the number of bytes to read from the template
					S32 data_size = mvci.getSize();
					U8 tsizeb = 0;
					U16 tsizeh = 0;
					U32 tsize = 0;

					if ((decode_pos + data_size) > mReceiveSize)
					{
						logRanOffEndOfPacket(sender, decode_pos, data_size);

						// default to 0 length variable blocks
						tsize = 0;
					}
					else
					{
						switch(data_size)
						{
						case 1:
							htonmemcpy(&tsizeb, &buffer[decode_pos], MVT_U8, 1);
							tsize = tsizeb;
							break;
						case 2:
							htonmemcpy(&tsizeh, &buffer[decode_pos], MVT_U16, 2);
							tsize = tsizeh;
							break;
						case 4:
							htonmemcpy(&tsize, &buffer[decode_pos], MVT_U32, 4);
							break;
						default:
							llerrs << "Attempting to read variable field with unknown size of " << data_size << llendl;
							break;
						}
					}
					decode_pos += data_size;

					cur_data_block->addData(mvci.getName(), &buffer[decode_pos], tsize, mvci.getType());
					decode_pos += tsize;
				}
				else
				{
					// fixed!
					// so, copy data pointer and set data size to fixed size
					if ((decode_pos + mvci.getSize()) > mReceiveSize)
					{
						logRanOffEndOfPacket(sender, decode_pos, mvci.getSize());

						// default to 0s.
						U32 size = mvci.getSize();
						std::vector<U8> data(size);
						if (size) memset(&(data[0]), 0, size);
						cur_data_block->addData(mvci.getName(), &(data[0]), 
												size, mvci.getType());
					}
					else
					{
						cur_data_block->addData(mvci.getName(), 
												&buffer[decode_pos], 
												mvci.getSize(), 
												mvci.getType());
					}
					decode_pos += mvci.getSize();
				}
			}
		}
	}

	if (mCurrentRMessageData->mMemberBlocks.empty()
		&& !mCurrentRMessageTemplate->mMemberBlocks.empty())
	{
		lldebugs << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << llendl;
		return FALSE;
	}

	{
		static LLTimer decode_timer;

		if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback())
		{
			decode_timer.reset();
		}

		{
			LLFastTimer t(LLFastTimer::FTM_PROCESS_MESSAGES);
			if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) )
			{
				llwarns << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << llendl;
			}
		}

		if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback())
		{
			F32 decode_time = decode_timer.getElapsedTimeF32();

			if (gMessageSystem->getTimingCallback())
			{
				(gMessageSystem->getTimingCallback())(mCurrentRMessageTemplate->mName,
								decode_time,
								gMessageSystem->getTimingCallbackData());
			}

			if (LLMessageReader::getTimeDecodes())
			{
				mCurrentRMessageTemplate->mDecodeTimeThisFrame += decode_time;

				mCurrentRMessageTemplate->mTotalDecoded++;
				mCurrentRMessageTemplate->mTotalDecodeTime += decode_time;

				if( mCurrentRMessageTemplate->mMaxDecodeTimePerMsg < decode_time )
				{
					mCurrentRMessageTemplate->mMaxDecodeTimePerMsg = decode_time;
				}


				if(decode_time > LLMessageReader::getTimeDecodesSpamThreshold())
				{
					lldebugs << "--------- Message " << mCurrentRMessageTemplate->mName << " decode took " << decode_time << " seconds. (" <<
						mCurrentRMessageTemplate->mMaxDecodeTimePerMsg << " max, " <<
						(mCurrentRMessageTemplate->mTotalDecodeTime / mCurrentRMessageTemplate->mTotalDecoded) << " avg)" << llendl;
				}
			}
		}
	}
	return TRUE;
}
Exemple #13
0
void LLPanelGroupGeneral::updateMembers()
{
	mPendingMemberUpdate = FALSE;

	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID);

	if (!mListVisibleMembers || !gdatap 
		|| !gdatap->isMemberDataComplete())
	{
		return;
	}

	static LLTimer all_timer;
	static LLTimer sd_timer;
	static LLTimer element_timer;

	all_timer.reset();
	S32 i = 0;

	for( ; mMemberProgress != gdatap->mMembers.end() && i<UPDATE_MEMBERS_PER_FRAME; 
			++mMemberProgress, ++i)
	{
		//llinfos << "Adding " << iter->first << ", " << iter->second->getTitle() << llendl;
		LLGroupMemberData* member = mMemberProgress->second;
		if (!member)
		{
			continue;
		}
		// Owners show up in bold.
		std::string style = "NORMAL";
		if ( member->isOwner() )
		{
			style = "BOLD";
		}
		
		sd_timer.reset();
		LLSD row;
		row["id"] = member->getID();

		row["columns"][0]["column"] = "name";
		row["columns"][0]["font-style"] = style;
		// value is filled in by name list control

		row["columns"][1]["column"] = "title";
		row["columns"][1]["value"] = member->getTitle();
		row["columns"][1]["font-style"] = style;
		
		row["columns"][2]["column"] = "online";
		row["columns"][2]["value"] = member->getOnlineStatus();
		row["columns"][2]["font-style"] = style;

		sSDTime += sd_timer.getElapsedTimeF32();

		element_timer.reset();
		mListVisibleMembers->addElement(row);//, ADD_SORTED);
		sElementTime += element_timer.getElapsedTimeF32();
	}
	sAllTime += all_timer.getElapsedTimeF32();

	llinfos << "Updated " << i << " of " << UPDATE_MEMBERS_PER_FRAME << "members in the list." << llendl;
	if (mMemberProgress == gdatap->mMembers.end())
	{
		llinfos << "   member list completed." << llendl;
		mListVisibleMembers->setEnabled(TRUE);

		llinfos << "All Time: " << sAllTime << llendl;
		llinfos << "SD Time: " << sSDTime << llendl;
		llinfos << "Element Time: " << sElementTime << llendl;
	}
	else
	{
		mPendingMemberUpdate = TRUE;
		mListVisibleMembers->setEnabled(FALSE);
	}
}
Exemple #14
0
F32 gpu_benchmark()
{
    if (!gGLManager.mHasShaderObjects || !gGLManager.mHasTimerQuery)
    {   // don't bother benchmarking the fixed function
        // or venerable drivers which don't support accurate timing anyway
        // and are likely to be correctly identified by the GPU table already.
        return -1.f;
    }

    if (gBenchmarkProgram.mProgramObject == 0)
    {
        LLViewerShaderMgr::instance()->initAttribsAndUniforms();

        gBenchmarkProgram.mName = "Benchmark Shader";
        gBenchmarkProgram.mFeatures.attachNothing = true;
        gBenchmarkProgram.mShaderFiles.clear();
        gBenchmarkProgram.mShaderFiles.push_back(std::make_pair("interface/benchmarkV.glsl", GL_VERTEX_SHADER_ARB));
        gBenchmarkProgram.mShaderFiles.push_back(std::make_pair("interface/benchmarkF.glsl", GL_FRAGMENT_SHADER_ARB));
        gBenchmarkProgram.mShaderLevel = 1;
        if (!gBenchmarkProgram.createShader(NULL, NULL))
        {
            return -1.f;
        }
    }

    LLGLDisable blend(GL_BLEND);

    //measure memory bandwidth by:
    // - allocating a batch of textures and render targets
    // - rendering those textures to those render targets
    // - recording time taken
    // - taking the median time for a given number of samples

    //resolution of textures/render targets
    const U32 res = 1024;

    //number of textures
    const U32 count = 32;

    //number of samples to take
    const S32 samples = 64;

    if (gGLManager.mHasTimerQuery)
    {
        LLGLSLShader::initProfile();
    }

    LLRenderTarget dest[count];
    U32 source[count];
    LLImageGL::generateTextures(count, source);
    std::vector<F32> results;

    //build a random texture
    U8* pixels = new U8[res*res*4];

    for (U32 i = 0; i < res*res*4; ++i)
    {
        pixels[i] = (U8) ll_rand(255);
    }


    gGL.setColorMask(true, true);
    LLGLDepthTest depth(GL_FALSE);

    for (U32 i = 0; i < count; ++i)
    {   //allocate render targets and textures
        dest[i].allocate(res,res,GL_RGBA,false, false, LLTexUnit::TT_TEXTURE, true);
        dest[i].bindTarget();
        dest[i].clear();
        dest[i].flush();

        gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, source[i]);
        LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_RGBA, res,res,GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    }

    delete [] pixels;

    //make a dummy triangle to draw with
    LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, GL_STATIC_DRAW_ARB);
    buff->allocateBuffer(3, 0, true);

    LLStrider<LLVector3> v;
    LLStrider<LLVector2> tc;

    buff->getVertexStrider(v);

    v[0].set(-1,1,0);
    v[1].set(-1,-3,0);
    v[2].set(3,1,0);

    buff->flush();

    gBenchmarkProgram.bind();

    bool busted_finish = false;

    buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
    glFinish();

    for (S32 c = -1; c < samples; ++c)
    {
        LLTimer timer;
        timer.start();

        for (U32 i = 0; i < count; ++i)
        {
            dest[i].bindTarget();
            gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, source[i]);
            buff->drawArrays(LLRender::TRIANGLES, 0, 3);
            dest[i].flush();
        }

        //wait for current batch of copies to finish
        if (busted_finish)
        {
            //read a pixel off the last target since some drivers seem to ignore glFinish
            dest[count-1].bindTarget();
            U32 pixel = 0;
            glReadPixels(0,0,1,1,GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
            dest[count-1].flush();
        }
        else
        {
            glFinish();
        }

        F32 time = timer.getElapsedTimeF32();

        if (c >= 0) // <-- ignore the first sample as it tends to be artificially slow
        {
            //store result in gigabytes per second
            F32 gb = (F32) ((F64) (res*res*8*count))/(1000000000);

            F32 gbps = gb/time;

            if (!gGLManager.mHasTimerQuery && !busted_finish && gbps > 128.f)
            {   //unrealistically high bandwidth for a card without timer queries, glFinish is probably ignored
                busted_finish = true;
                LL_WARNS() << "GPU Benchmark detected GL driver with broken glFinish implementation." << LL_ENDL;
            }
            else
            {
                results.push_back(gbps);
            }
        }
    }

    gBenchmarkProgram.unbind();

    if (gGLManager.mHasTimerQuery)
    {
        LLGLSLShader::finishProfile(false);
    }

    LLImageGL::deleteTextures(count, source);

    std::sort(results.begin(), results.end());

    F32 gbps = results[results.size()/2];

    LL_INFOS() << "Memory bandwidth is " << llformat("%.3f", gbps) << "GB/sec according to CPU timers" << LL_ENDL;

#if LL_DARWIN
    if (gbps > 512.f)
    {
        LL_WARNS() << "Memory bandwidth is improbably high and likely incorrect; discarding result." << LL_ENDL;
        //OSX is probably lying, discard result
        gbps = -1.f;
    }
#endif

    F32 ms = gBenchmarkProgram.mTimeElapsed/1000000.f;
    F32 seconds = ms/1000.f;

    F64 samples_drawn = res*res*count*samples;
    F32 samples_sec = (samples_drawn/1000000000.0)/seconds;
    gbps = samples_sec*8;

    LL_INFOS() << "Memory bandwidth is " << llformat("%.3f", gbps) << "GB/sec according to ARB_timer_query" << LL_ENDL;

    return gbps;
}
Exemple #15
0
bool LLXMLRPCTransaction::Impl::process()
{
	switch(mStatus)
	{
		case LLXMLRPCTransaction::StatusComplete:
		case LLXMLRPCTransaction::StatusCURLError:
		case LLXMLRPCTransaction::StatusXMLRPCError:
		case LLXMLRPCTransaction::StatusOtherError:
		{
			return true;
		}
		
		case LLXMLRPCTransaction::StatusNotStarted:
		{
			setStatus(LLXMLRPCTransaction::StatusStarted);
			break;
		}
		
		default:
		{
			// continue onward
		}
	}
	
	const F32 MAX_PROCESSING_TIME = 0.05f;
	LLTimer timer;

	while (mCurlRequest->perform() > 0)
	{
		if (timer.getElapsedTimeF32() >= MAX_PROCESSING_TIME)
		{
			return false;
		}
	}

	while(1)
	{
		CURLcode result;
		bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo);
		if (newmsg)
		{
			if (result != CURLE_OK)
			{
				if ((result != CURLE_SSL_PEER_CERTIFICATE) &&
					(result != CURLE_SSL_CACERT))
				{
					// if we have a curl error that's not already been handled
					// (a non cert error), then generate the error message as
					// appropriate
					setCurlStatus(result);
				
					llwarns << "LLXMLRPCTransaction CURL error "
					<< mCurlCode << ": " << mCurlRequest->getErrorString() << llendl;
					llwarns << "LLXMLRPCTransaction request URI: "
					<< mURI << llendl;
				}
					
				return true;
			}
			
			setStatus(LLXMLRPCTransaction::StatusComplete);

			mResponse = XMLRPC_REQUEST_FromXML(
					mResponseText.data(), mResponseText.size(), NULL);

			bool		hasError = false;
			bool		hasFault = false;
			int			faultCode = 0;
			std::string	faultString;

			LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
			if (error.isValid())
			{
				hasError = true;
				faultCode = error["faultCode"].asInt();
				faultString = error["faultString"].asString();
			}
			else if (XMLRPC_ResponseIsFault(mResponse))
			{
				hasFault = true;
				faultCode = XMLRPC_GetResponseFaultCode(mResponse);
				faultString = XMLRPC_GetResponseFaultString(mResponse);
			}

			if (hasError || hasFault)
			{
				setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
				
				llwarns << "LLXMLRPCTransaction XMLRPC "
						<< (hasError ? "error " : "fault ")
						<< faultCode << ": "
						<< faultString << llendl;
				llwarns << "LLXMLRPCTransaction request URI: "
						<< mURI << llendl;
			}
			
			return true;
		}
		else
		{
			break; // done
		}
	}
	
	return false;
}
void LLViewerImageList::decodeAllImages(F32 max_time)
{
	LLTimer timer;
	if(gNoRender) return;
	
	// Update texture stats and priorities
	std::vector<LLPointer<LLViewerImage> > image_list;
	for (image_priority_list_t::iterator iter = mImageList.begin();
		 iter != mImageList.end(); )
	{
		LLViewerImage* imagep = *iter++;
		image_list.push_back(imagep);
		imagep->mInImageList = FALSE;
	}
	mImageList.clear();
	for (std::vector<LLPointer<LLViewerImage> >::iterator iter = image_list.begin();
		 iter != image_list.end(); ++iter)
	{
		LLViewerImage* imagep = *iter;
		imagep->processTextureStats();
		F32 decode_priority = imagep->calcDecodePriority();
		imagep->setDecodePriority(decode_priority);
		mImageList.insert(imagep);
		imagep->mInImageList = TRUE;
	}
	image_list.clear();
	
	// Update fetch (decode)
	for (image_priority_list_t::iterator iter = mImageList.begin();
		 iter != mImageList.end(); )
	{
		LLViewerImage* imagep = *iter++;
		imagep->updateFetch();
	}
	// Run threads
	S32 fetch_pending = 0;
	while (1)
	{
		LLAppViewer::instance()->getTextureCache()->update(1); // unpauses the texture cache thread
		LLAppViewer::instance()->getImageDecodeThread()->update(1); // unpauses the image thread
		fetch_pending = LLAppViewer::instance()->getTextureFetch()->update(1); // unpauses the texture fetch thread
		if (fetch_pending == 0 || timer.getElapsedTimeF32() > max_time)
		{
			break;
		}
	}
	// Update fetch again
	for (image_priority_list_t::iterator iter = mImageList.begin();
		 iter != mImageList.end(); )
	{
		LLViewerImage* imagep = *iter++;
		imagep->updateFetch();
	}
	max_time -= timer.getElapsedTimeF32();
	max_time = llmax(max_time, .001f);
	F32 create_time = updateImagesCreateTextures(max_time);
	
	LL_DEBUGS("ViewerImages") << "decodeAllImages() took " << timer.getElapsedTimeF32() << " seconds. " 
	<< " fetch_pending " << fetch_pending
	<< " create_time " << create_time
	<< LL_ENDL;
}
bool LLXMLRPCTransaction::Impl::process()
{
	switch(mStatus)
	{
		case LLXMLRPCTransaction::StatusComplete:
		case LLXMLRPCTransaction::StatusCURLError:
		case LLXMLRPCTransaction::StatusXMLRPCError:
		case LLXMLRPCTransaction::StatusOtherError:
		{
			return true;
		}
		
		case LLXMLRPCTransaction::StatusNotStarted:
		{
			setStatus(LLXMLRPCTransaction::StatusStarted);
			break;
		}
		
		default:
		{
			// continue onward
		}
	}
	
	const F32 MAX_PROCESSING_TIME = 0.05f;
	LLTimer timer;
	int count;
	
	while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(mCurlMulti, &count))
	{
		if (timer.getElapsedTimeF32() >= MAX_PROCESSING_TIME)
		{
			return false;
		}
	}
			 
	while(CURLMsg* curl_msg = curl_multi_info_read(mCurlMulti, &count))
	{
		if (CURLMSG_DONE == curl_msg->msg)
		{
			if (curl_msg->data.result != CURLE_OK)
			{
				setCurlStatus(curl_msg->data.result);
				llwarns << "LLXMLRPCTransaction CURL error "
					<< mCurlCode << ": " << mCurlErrorBuffer << llendl;
				llwarns << "LLXMLRPCTransaction request URI: "
					<< mURI << llendl;
					
				return true;
			}
			
			setStatus(LLXMLRPCTransaction::StatusComplete);

			mResponse = XMLRPC_REQUEST_FromXML(
				mResponseText.data(), mResponseText.size(), NULL);

			bool		hasError = false;
			bool		hasFault = false;
			int			faultCode = 0;
			std::string	faultString;

			LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
			if (error.isValid())
			{
				hasError = true;
				faultCode = error["faultCode"].asInt();
				faultString = error["faultString"].asString();
			}
			else if (XMLRPC_ResponseIsFault(mResponse))
			{
				hasFault = true;
				faultCode = XMLRPC_GetResponseFaultCode(mResponse);
				faultString = XMLRPC_GetResponseFaultString(mResponse);
			}

			if (hasError || hasFault)
			{
				setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
				
				llwarns << "LLXMLRPCTransaction XMLRPC "
					<< (hasError ? "error " : "fault ")
					<< faultCode << ": "
					<< faultString << llendl;
				llwarns << "LLXMLRPCTransaction request URI: "
					<< mURI << llendl;
			}
			
			return true;
		}
	}
	
	return false;
}
void LLProgressView::draw()
{
	static LLTimer timer;

	if (gNoRender)
	{
		return;
	}

	// Make sure the progress view always fills the entire window.
	S32 width = gViewerWindow->getWindowWidth();
	S32 height = gViewerWindow->getWindowHeight();
	if( (width != getRect().getWidth()) || (height != getRect().getHeight()) )
	{
		reshape( width, height );
	}

	// Paint bitmap if we've got one
	glPushMatrix();
	if (gStartImageGL)
	{
		LLGLSUIDefault gls_ui;
		LLViewerImage::bindTexture(gStartImageGL);
		gGL.color4f(1.f, 1.f, 1.f, mFadeTimer.getStarted() ? clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, FADE_IN_TIME, 1.f, 0.f) : 1.f);
		F32 image_aspect = (F32)gStartImageWidth / (F32)gStartImageHeight;
		F32 view_aspect = (F32)width / (F32)height;
		// stretch image to maintain aspect ratio
		if (image_aspect > view_aspect)
		{
			glTranslatef(-0.5f * (image_aspect / view_aspect - 1.f) * width, 0.f, 0.f);
			glScalef(image_aspect / view_aspect, 1.f, 1.f);
		}
		else
		{
			glTranslatef(0.f, -0.5f * (view_aspect / image_aspect - 1.f) * height, 0.f);
			glScalef(1.f, view_aspect / image_aspect, 1.f);
		}
		gl_rect_2d_simple_tex( getRect().getWidth(), getRect().getHeight() );
		gStartImageGL->unbindTexture(0, GL_TEXTURE_2D);
	}
	else
	{
		LLGLSNoTexture gls_no_texture;
		gGL.color4f(0.f, 0.f, 0.f, 1.f);
		gl_rect_2d(getRect());
	}
	glPopMatrix();

	// Handle fade-in animation
	if (mFadeTimer.getStarted())
	{
		LLView::draw();
		if (mFadeTimer.getElapsedTimeF32() > FADE_IN_TIME)
		{
			gFocusMgr.removeTopCtrlWithoutCallback(this);
			LLView::setVisible(FALSE);
			gStartImageGL = NULL;
		}
		return;
	}

	S32 line_x = getRect().getWidth() / 2;
	S32 line_one_y = getRect().getHeight() / 2 + 64;
	const S32 LINE_SPACING = 25;
	S32 line_two_y = line_one_y - LINE_SPACING;
	const LLFontGL* font = LLFontGL::sSansSerif;

	LLUIImagePtr shadow_imagep = LLUI::getUIImage("rounded_square_soft.tga");
	LLUIImagePtr bar_fg_imagep = LLUI::getUIImage("progressbar_fill.tga");
	LLUIImagePtr bar_bg_imagep = LLUI::getUIImage("progressbar_track.tga");
	LLUIImagePtr bar_imagep = LLUI::getUIImage("rounded_square.tga");
	
	LLColor4 background_color = gColors.getColor("LoginProgressBarBgColor");

	F32 alpha = 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
	// background_color.mV[3] = background_color.mV[3]*alpha;

	std::string top_line = LLAppViewer::instance()->getSecondLifeTitle();

	S32 bar_bottom = line_two_y - 30;
	S32 bar_height = 18;
	S32 bar_width = getRect().getWidth() * 2 / 3;
	S32 bar_left = (getRect().getWidth() / 2) - (bar_width / 2);

	// translucent outline box
	S32 background_box_left = ( ( ( getRect().getWidth() / 2 ) - ( bar_width / 2 ) ) / 4 ) * 3;
	S32 background_box_top = ( getRect().getHeight() / 2 ) + LINE_SPACING * 5;
	S32 background_box_right = getRect().getWidth() - background_box_left;
	S32 background_box_bottom = ( getRect().getHeight() / 2 ) - LINE_SPACING * 5;
	S32 background_box_width = background_box_right - background_box_left + 1;
	S32 background_box_height = background_box_top - background_box_bottom + 1;

//	shadow_imagep->draw( background_box_left + 2, 
//									background_box_bottom - 2, 
//									background_box_width, 
//									background_box_height,
//									gColors.getColor( "LoginProgressBoxShadowColor" ) );
//	bar_outline_imagep->draw( background_box_left, 
//									background_box_bottom, 
//									background_box_width, 
//									background_box_height,
//									gColors.getColor("LoginProgressBoxBorderColor") );

	bar_imagep->draw( background_box_left + 1,
									background_box_bottom + 1, 
									background_box_width - 2,
									background_box_height - 2,
									gColors.getColor("LoginProgressBoxCenterColor") );

	// we'll need this later for catching a click if it looks like it contains a link
	if ( mMessage.find( "http://" ) != std::string::npos )
		mOutlineRect.set( background_box_left, background_box_top, background_box_right, background_box_bottom );
	else
		mOutlineRect.set( 0, 0, 0, 0 );

	// draw loading bar
	font->renderUTF8(top_line, 0,
		line_x, line_one_y,
		//LLColor4::white,
		gColors.getColor("LoginProgressBoxTextColor"),
		LLFontGL::HCENTER, LLFontGL::BASELINE,
		LLFontGL::DROP_SHADOW);
	font->renderUTF8(mText, 0,
		line_x, line_two_y,
		//LLColor4::white,
		gColors.getColor("LoginProgressBoxTextColor"),
		LLFontGL::HCENTER, LLFontGL::BASELINE,
		LLFontGL::DROP_SHADOW);
		
//	shadow_imagep->draw(
//		bar_left + 2, 
//		bar_bottom - 2, 
//		bar_width, 
//		bar_height,
//		gColors.getColor("LoginProgressBoxShadowColor"));

//	bar_imagep->draw(
//		bar_left, 
//		bar_bottom, 
//		bar_width, 
//		bar_height,
//		LLColor4(0.7f, 0.7f, 0.8f, 1.0f));

	bar_bg_imagep->draw(
		bar_left + 2, 
		bar_bottom + 2,
		bar_width - 4, 
		bar_height - 4,
		background_color);

	LLColor4 bar_color = gColors.getColor("LoginProgressBarFgColor");
	bar_color.mV[3] = alpha;
	bar_fg_imagep->draw(
		bar_left + 2, 
		bar_bottom + 2,
		llround((bar_width - 4) * (mPercentDone / 100.f)), 
		bar_height - 4,
		bar_color);

	S32 line_three_y = line_two_y - LINE_SPACING * 3;
	
	// draw the message if there is one
	if(!mMessage.empty())
	{
		LLColor4 text_message_color = gColors.getColor("LoginProgressBoxTextColor");
		LLWString wmessage = utf8str_to_wstring(mMessage);
		const F32 MAX_PIXELS = 640.0f;
		S32 chars_left = wmessage.length();
		S32 chars_this_time = 0;
		S32 msgidx = 0;
		while(chars_left > 0)
		{
			chars_this_time = font->maxDrawableChars(wmessage.substr(msgidx).c_str(),
													 MAX_PIXELS,
													 MAX_STRING - 1,
													 TRUE);
			LLWString wbuffer = wmessage.substr(msgidx, chars_this_time);
			font->render(wbuffer, 0,
						 (F32)line_x, (F32)line_three_y,
						 //LLColor4::white,
						 gColors.getColor("LoginProgressBoxTextColor"),
						 LLFontGL::HCENTER, LLFontGL::BASELINE,
						 LLFontGL::DROP_SHADOW);
			msgidx += chars_this_time;
			chars_left -= chars_this_time;
			line_three_y -= LINE_SPACING;
		}
	}

	// draw children
	LLView::draw();
}